| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
| 8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
| 9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
| 10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
| (...skipping 2562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2573 SourceLocation location = | 2573 SourceLocation location = |
| 2574 new TokenSourceLocation(sourceFile, token, sourceElement.name); | 2574 new TokenSourceLocation(sourceFile, token, sourceElement.name); |
| 2575 checkValidSourceFileLocation(location, sourceFile, token.charOffset); | 2575 checkValidSourceFileLocation(location, sourceFile, token.charOffset); |
| 2576 return location; | 2576 return location; |
| 2577 } | 2577 } |
| 2578 | 2578 |
| 2579 void visit(ast.Node node) { | 2579 void visit(ast.Node node) { |
| 2580 if (node != null) node.accept(this); | 2580 if (node != null) node.accept(this); |
| 2581 } | 2581 } |
| 2582 | 2582 |
| 2583 /// Visit [node] and pop the resulting [HInstruction]. |
| 2584 HInstruction visitAndPop(ast.Node node) { |
| 2585 node.accept(this); |
| 2586 return pop(); |
| 2587 } |
| 2588 |
| 2583 visitBlock(ast.Block node) { | 2589 visitBlock(ast.Block node) { |
| 2584 assert(!isAborted()); | 2590 assert(!isAborted()); |
| 2585 if (!isReachable) return; // This can only happen when inlining. | 2591 if (!isReachable) return; // This can only happen when inlining. |
| 2586 for (Link<ast.Node> link = node.statements.nodes; | 2592 for (Link<ast.Node> link = node.statements.nodes; |
| 2587 !link.isEmpty; | 2593 !link.isEmpty; |
| 2588 link = link.tail) { | 2594 link = link.tail) { |
| 2589 visit(link.head); | 2595 visit(link.head); |
| 2590 if (!isReachable) { | 2596 if (!isReachable) { |
| 2591 // The block has been aborted by a return or a throw. | 2597 // The block has been aborted by a return or a throw. |
| 2592 if (!stack.isEmpty) { | 2598 if (!stack.isEmpty) { |
| (...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3152 () => visit(node.thenPart), | 3158 () => visit(node.thenPart), |
| 3153 node.elsePart != null ? () => visit(node.elsePart) : null); | 3159 node.elsePart != null ? () => visit(node.elsePart) : null); |
| 3154 } | 3160 } |
| 3155 | 3161 |
| 3156 void handleIf(ast.Node diagnosticNode, | 3162 void handleIf(ast.Node diagnosticNode, |
| 3157 void visitCondition(), void visitThen(), void visitElse()) { | 3163 void visitCondition(), void visitThen(), void visitElse()) { |
| 3158 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 3164 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
| 3159 branchBuilder.handleIf(visitCondition, visitThen, visitElse); | 3165 branchBuilder.handleIf(visitCondition, visitThen, visitElse); |
| 3160 } | 3166 } |
| 3161 | 3167 |
| 3162 void visitLogicalAndOr(ast.Send node, ast.Operator op) { | 3168 @override |
| 3169 void visitLogicalAnd(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3163 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); | 3170 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| 3164 branchBuilder.handleLogicalAndOrWithLeftNode( | 3171 branchBuilder.handleLogicalAndOrWithLeftNode( |
| 3165 node.receiver, | 3172 left, |
| 3166 () { visit(node.argumentsNode); }, | 3173 () { visit(right); }, |
| 3167 isAnd: ("&&" == op.source)); | 3174 isAnd: true); |
| 3168 } | 3175 } |
| 3169 | 3176 |
| 3170 void visitLogicalNot(ast.Send node) { | 3177 @override |
| 3178 void visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3179 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, node); |
| 3180 branchBuilder.handleLogicalAndOrWithLeftNode( |
| 3181 left, |
| 3182 () { visit(right); }, |
| 3183 isAnd: false); |
| 3184 } |
| 3185 |
| 3186 @override |
| 3187 void visitNot(ast.Send node, ast.Node expression, _) { |
| 3171 assert(node.argumentsNode is ast.Prefix); | 3188 assert(node.argumentsNode is ast.Prefix); |
| 3172 visit(node.receiver); | 3189 visit(expression); |
| 3173 HNot not = new HNot(popBoolified(), backend.boolType); | 3190 HNot not = new HNot(popBoolified(), backend.boolType); |
| 3174 pushWithPosition(not, node); | 3191 pushWithPosition(not, node); |
| 3175 } | 3192 } |
| 3176 | 3193 |
| 3177 void visitUnarySend(ast.Send node, ast.Operator op) { | 3194 @override |
| 3195 void visitUnary(ast.Send node, |
| 3196 UnaryOperator operator, |
| 3197 ast.Node expression,_) { |
| 3178 assert(node.argumentsNode is ast.Prefix); | 3198 assert(node.argumentsNode is ast.Prefix); |
| 3179 visit(node.receiver); | 3199 HInstruction operand = visitAndPop(expression); |
| 3180 assert(!identical(op.token.kind, PLUS_TOKEN)); | |
| 3181 HInstruction operand = pop(); | |
| 3182 | 3200 |
| 3183 // See if we can constant-fold right away. This avoids rewrites later on. | 3201 // See if we can constant-fold right away. This avoids rewrites later on. |
| 3184 if (operand is HConstant) { | 3202 if (operand is HConstant) { |
| 3185 UnaryOperation operation = constantSystem.lookupUnary( | 3203 UnaryOperation operation = constantSystem.lookupUnary(operator); |
| 3186 UnaryOperator.parse(op.source)); | |
| 3187 HConstant constant = operand; | 3204 HConstant constant = operand; |
| 3188 ConstantValue folded = operation.fold(constant.constant); | 3205 ConstantValue folded = operation.fold(constant.constant); |
| 3189 if (folded != null) { | 3206 if (folded != null) { |
| 3190 stack.add(graph.addConstant(folded, compiler)); | 3207 stack.add(graph.addConstant(folded, compiler)); |
| 3191 return; | 3208 return; |
| 3192 } | 3209 } |
| 3193 } | 3210 } |
| 3194 | 3211 |
| 3195 pushInvokeDynamic(node, elements.getSelector(node), [operand]); | 3212 pushInvokeDynamic(node, elements.getSelector(node), [operand]); |
| 3196 } | 3213 } |
| 3197 | 3214 |
| 3215 @override |
| 3216 void visitBinary(ast.Send node, |
| 3217 ast.Node left, |
| 3218 BinaryOperator operator, |
| 3219 ast.Node right, _) { |
| 3220 handleBinary(node, left, right); |
| 3221 } |
| 3222 |
| 3223 @override |
| 3224 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { |
| 3225 // TODO(johnniwinther): Add a new helper to join the paths used by |
| 3226 // [visitIndex], [visitDynamicSend] and [handleSendSet]. |
| 3227 visitDynamicSend(node); |
| 3228 } |
| 3229 |
| 3230 @override |
| 3231 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3232 handleBinary(node, left, right); |
| 3233 } |
| 3234 |
| 3235 @override |
| 3236 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3237 handleBinary(node, left, right); |
| 3238 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
| 3239 } |
| 3240 |
| 3241 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { |
| 3242 visitBinarySend( |
| 3243 visitAndPop(left), |
| 3244 visitAndPop(right), |
| 3245 elements.getSelector(node), |
| 3246 node, |
| 3247 location: node.selector); |
| 3248 } |
| 3249 |
| 3250 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and |
| 3251 /// remove use of [location] for source information. |
| 3198 void visitBinarySend(HInstruction left, | 3252 void visitBinarySend(HInstruction left, |
| 3199 ast.Operator op, | |
| 3200 HInstruction right, | 3253 HInstruction right, |
| 3201 Selector selector, | 3254 Selector selector, |
| 3202 ast.Send send) { | 3255 ast.Send send, |
| 3203 switch (op.source) { | 3256 {ast.Node location}) { |
| 3204 case "===": | 3257 pushInvokeDynamic(send, selector, [left, right], location: location); |
| 3205 pushWithPosition( | |
| 3206 new HIdentity(left, right, null, backend.boolType), op); | |
| 3207 return; | |
| 3208 case "!==": | |
| 3209 HIdentity eq = new HIdentity(left, right, null, backend.boolType); | |
| 3210 add(eq); | |
| 3211 pushWithPosition(new HNot(eq, backend.boolType), op); | |
| 3212 return; | |
| 3213 } | |
| 3214 | |
| 3215 pushInvokeDynamic(send, selector, [left, right], location: op); | |
| 3216 if (op.source == '!=') { | |
| 3217 pushWithPosition(new HNot(popBoolified(), backend.boolType), op); | |
| 3218 } | |
| 3219 } | 3258 } |
| 3220 | 3259 |
| 3221 HInstruction generateInstanceSendReceiver(ast.Send send) { | 3260 HInstruction generateInstanceSendReceiver(ast.Send send) { |
| 3222 assert(Elements.isInstanceSend(send, elements)); | 3261 assert(Elements.isInstanceSend(send, elements)); |
| 3223 if (send.receiver == null) { | 3262 if (send.receiver == null) { |
| 3224 return localsHandler.readThis(); | 3263 return localsHandler.readThis(); |
| 3225 } | 3264 } |
| 3226 visit(send.receiver); | 3265 visit(send.receiver); |
| 3227 return pop(); | 3266 return pop(); |
| 3228 } | 3267 } |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3470 // template manager build them. | 3509 // template manager build them. |
| 3471 js.Template code = js.js.uncachedExpressionTemplate(template); | 3510 js.Template code = js.js.uncachedExpressionTemplate(template); |
| 3472 HInstruction representation = | 3511 HInstruction representation = |
| 3473 new HForeignCode(code, backend.readableArrayType, inputs, | 3512 new HForeignCode(code, backend.readableArrayType, inputs, |
| 3474 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); | 3513 nativeBehavior: native.NativeBehavior.PURE_ALLOCATION); |
| 3475 return representation; | 3514 return representation; |
| 3476 } | 3515 } |
| 3477 } | 3516 } |
| 3478 | 3517 |
| 3479 visitOperatorSend(ast.Send node) { | 3518 visitOperatorSend(ast.Send node) { |
| 3480 ast.Operator op = node.selector; | 3519 internalError(node, 'Unexpected operator send: ${node}'); |
| 3481 if ("[]" == op.source) { | 3520 } |
| 3482 visitDynamicSend(node); | 3521 |
| 3483 } else if ("&&" == op.source || | 3522 @override |
| 3484 "||" == op.source) { | 3523 void visitAs(ast.Send node, ast.Node expression, DartType type, _) { |
| 3485 visitLogicalAndOr(node, op); | 3524 HInstruction expressionInstruction = visitAndPop(expression); |
| 3486 } else if ("!" == op.source) { | 3525 if (type.isMalformed) { |
| 3487 visitLogicalNot(node); | 3526 ErroneousElement element = type.element; |
| 3488 } else if (node.argumentsNode is ast.Prefix) { | 3527 generateTypeError(node, element.message); |
| 3489 visitUnarySend(node, op); | |
| 3490 } else if ("is" == op.source) { | |
| 3491 visitIsSend(node); | |
| 3492 } else if ("as" == op.source) { | |
| 3493 visit(node.receiver); | |
| 3494 HInstruction expression = pop(); | |
| 3495 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | |
| 3496 if (type.isMalformed) { | |
| 3497 ErroneousElement element = type.element; | |
| 3498 generateTypeError(node, element.message); | |
| 3499 } else { | |
| 3500 HInstruction converted = buildTypeConversion( | |
| 3501 expression, | |
| 3502 localsHandler.substInContext(type), | |
| 3503 HTypeConversion.CAST_TYPE_CHECK); | |
| 3504 if (converted != expression) add(converted); | |
| 3505 stack.add(converted); | |
| 3506 } | |
| 3507 } else { | 3528 } else { |
| 3508 visit(node.receiver); | 3529 HInstruction converted = buildTypeConversion( |
| 3509 visit(node.argumentsNode); | 3530 expressionInstruction, |
| 3510 var right = pop(); | 3531 localsHandler.substInContext(type), |
| 3511 var left = pop(); | 3532 HTypeConversion.CAST_TYPE_CHECK); |
| 3512 visitBinarySend(left, op, right, elements.getSelector(node), node); | 3533 if (converted != expressionInstruction) add(converted); |
| 3534 stack.add(converted); |
| 3513 } | 3535 } |
| 3514 } | 3536 } |
| 3515 | 3537 |
| 3516 void visitIsSend(ast.Send node) { | 3538 @override |
| 3517 visit(node.receiver); | 3539 void visitIs(ast.Send node, ast.Node expression, DartType type, _) { |
| 3518 HInstruction expression = pop(); | 3540 HInstruction expressionInstruction = visitAndPop(expression); |
| 3519 bool isNot = node.isIsNotCheck; | 3541 push(buildIsNode(node, type, expressionInstruction)); |
| 3520 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 3542 } |
| 3521 HInstruction instruction = buildIsNode(node, type, expression); | 3543 |
| 3522 if (isNot) { | 3544 @override |
| 3523 add(instruction); | 3545 void visitIsNot(ast.Send node, ast.Node expression, DartType type, _) { |
| 3524 instruction = new HNot(instruction, backend.boolType); | 3546 HInstruction expressionInstruction = visitAndPop(expression); |
| 3525 } | 3547 HInstruction instruction = buildIsNode(node, type, expressionInstruction); |
| 3526 push(instruction); | 3548 add(instruction); |
| 3549 push(new HNot(instruction, backend.boolType)); |
| 3527 } | 3550 } |
| 3528 | 3551 |
| 3529 HInstruction buildIsNode(ast.Node node, | 3552 HInstruction buildIsNode(ast.Node node, |
| 3530 DartType type, | 3553 DartType type, |
| 3531 HInstruction expression) { | 3554 HInstruction expression) { |
| 3532 type = localsHandler.substInContext(type).unalias(compiler); | 3555 type = localsHandler.substInContext(type).unalias(compiler); |
| 3533 if (type.isFunctionType) { | 3556 if (type.isFunctionType) { |
| 3534 List arguments = [buildFunctionType(type), expression]; | 3557 List arguments = [buildFunctionType(type), expression]; |
| 3535 pushInvokeDynamic( | 3558 pushInvokeDynamic( |
| 3536 node, new Selector.call('_isTest', backend.jsHelperLibrary, 1), | 3559 node, new Selector.call('_isTest', backend.jsHelperLibrary, 1), |
| (...skipping 1454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4991 HInstruction receiver, | 5014 HInstruction receiver, |
| 4992 Link<ast.Node> arguments) { | 5015 Link<ast.Node> arguments) { |
| 4993 HInstruction rhs; | 5016 HInstruction rhs; |
| 4994 if (node.isPrefix || node.isPostfix) { | 5017 if (node.isPrefix || node.isPostfix) { |
| 4995 rhs = graph.addConstantInt(1, compiler); | 5018 rhs = graph.addConstantInt(1, compiler); |
| 4996 } else { | 5019 } else { |
| 4997 visit(arguments.head); | 5020 visit(arguments.head); |
| 4998 assert(arguments.tail.isEmpty); | 5021 assert(arguments.tail.isEmpty); |
| 4999 rhs = pop(); | 5022 rhs = pop(); |
| 5000 } | 5023 } |
| 5001 visitBinarySend(receiver, node.assignmentOperator, rhs, | 5024 visitBinarySend(receiver, rhs, |
| 5002 elements.getOperatorSelectorInComplexSendSet(node), node); | 5025 elements.getOperatorSelectorInComplexSendSet(node), |
| 5026 node, |
| 5027 location: node.assignmentOperator); |
| 5003 } | 5028 } |
| 5004 | 5029 |
| 5005 @override | 5030 @override |
| 5006 handleSendSet(ast.SendSet node) { | 5031 handleSendSet(ast.SendSet node) { |
| 5007 generateIsDeferredLoadedCheckIfNeeded(node); | 5032 generateIsDeferredLoadedCheckIfNeeded(node); |
| 5008 Element element = elements[node]; | 5033 Element element = elements[node]; |
| 5009 if (!Elements.isUnresolved(element) && element.impliesType) { | 5034 if (!Elements.isUnresolved(element) && element.impliesType) { |
| 5010 ast.Identifier selector = node.selector; | 5035 ast.Identifier selector = node.selector; |
| 5011 generateThrowNoSuchMethod(node, selector.source, | 5036 generateThrowNoSuchMethod(node, selector.source, |
| 5012 argumentNodes: node.arguments); | 5037 argumentNodes: node.arguments); |
| (...skipping 2024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7037 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7062 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 7038 unaliased.accept(this, builder); | 7063 unaliased.accept(this, builder); |
| 7039 } | 7064 } |
| 7040 | 7065 |
| 7041 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7066 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 7042 JavaScriptBackend backend = builder.compiler.backend; | 7067 JavaScriptBackend backend = builder.compiler.backend; |
| 7043 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 7068 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 7044 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7069 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 7045 } | 7070 } |
| 7046 } | 7071 } |
| OLD | NEW |