| 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 SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 final SourceInformationFactory sourceInformationFactory; | 10 final SourceInformationStrategy sourceInformationFactory; |
| 11 | 11 |
| 12 SsaCodeGeneratorTask(JavaScriptBackend backend, | 12 SsaCodeGeneratorTask(JavaScriptBackend backend, |
| 13 this.sourceInformationFactory) | 13 this.sourceInformationFactory) |
| 14 : this.backend = backend, | 14 : this.backend = backend, |
| 15 super(backend.compiler); | 15 super(backend.compiler); |
| 16 | 16 |
| 17 String get name => 'SSA code generator'; | 17 String get name => 'SSA code generator'; |
| 18 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; | 18 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; |
| 19 | 19 |
| 20 | |
| 21 js.Node attachPosition(js.Node node, AstElement element) { | |
| 22 return node.withSourceInformation( | |
| 23 StartEndSourceInformation.computeSourceInformation(element)); | |
| 24 } | |
| 25 | |
| 26 js.Fun buildJavaScriptFunction(FunctionElement element, | 20 js.Fun buildJavaScriptFunction(FunctionElement element, |
| 27 List<js.Parameter> parameters, | 21 List<js.Parameter> parameters, |
| 28 js.Block body) { | 22 js.Block body) { |
| 29 js.AsyncModifier asyncModifier = element.asyncMarker.isAsync | 23 js.AsyncModifier asyncModifier = element.asyncMarker.isAsync |
| 30 ? (element.asyncMarker.isYielding | 24 ? (element.asyncMarker.isYielding |
| 31 ? const js.AsyncModifier.asyncStar() | 25 ? const js.AsyncModifier.asyncStar() |
| 32 : const js.AsyncModifier.async()) | 26 : const js.AsyncModifier.async()) |
| 33 : (element.asyncMarker.isYielding | 27 : (element.asyncMarker.isYielding |
| 34 ? const js.AsyncModifier.syncStar() | 28 ? const js.AsyncModifier.syncStar() |
| 35 : const js.AsyncModifier.sync()); | 29 : const js.AsyncModifier.sync()); |
| 36 | 30 |
| 37 return new js.Fun(parameters, body, asyncModifier: asyncModifier) | 31 return new js.Fun(parameters, body, asyncModifier: asyncModifier) |
| 38 .withSourceInformation(sourceInformationFactory.forContext(element) | 32 .withSourceInformation( |
| 39 .buildDeclaration(element)); | 33 sourceInformationFactory.createBuilderForContext(element) |
| 34 .buildDeclaration(element)); |
| 40 } | 35 } |
| 41 | 36 |
| 42 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { | 37 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { |
| 43 if (work.element.isField) { | 38 if (work.element.isField) { |
| 44 return generateLazyInitializer(work, graph); | 39 return generateLazyInitializer(work, graph); |
| 45 } else { | 40 } else { |
| 46 return generateMethod(work, graph); | 41 return generateMethod(work, graph); |
| 47 } | 42 } |
| 48 } | 43 } |
| 49 | 44 |
| 50 js.Expression generateLazyInitializer(work, graph) { | 45 js.Expression generateLazyInitializer(work, graph) { |
| 51 return measure(() { | 46 return measure(() { |
| 52 compiler.tracer.traceGraph("codegen", graph); | 47 compiler.tracer.traceGraph("codegen", graph); |
| 53 SourceInformation sourceInformation = | 48 SourceInformation sourceInformation = |
| 54 sourceInformationFactory.forContext(work.element) | 49 sourceInformationFactory.createBuilderForContext(work.element) |
| 55 .buildDeclaration(work.element); | 50 .buildDeclaration(work.element); |
| 56 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); | 51 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); |
| 57 codegen.visitGraph(graph); | 52 codegen.visitGraph(graph); |
| 58 return new js.Fun(codegen.parameters, codegen.body) | 53 return new js.Fun(codegen.parameters, codegen.body) |
| 59 .withSourceInformation(sourceInformation); | 54 .withSourceInformation(sourceInformation); |
| 60 }); | 55 }); |
| 61 } | 56 } |
| 62 | 57 |
| 63 js.Expression generateMethod(CodegenWorkItem work, HGraph graph) { | 58 js.Expression generateMethod(CodegenWorkItem work, HGraph graph) { |
| 64 return measure(() { | 59 return measure(() { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 if (instruction.isUInt31(compiler)) return false; | 177 if (instruction.isUInt31(compiler)) return false; |
| 183 // If the result of a bit-operation is only used by other bit | 178 // If the result of a bit-operation is only used by other bit |
| 184 // operations, we do not have to convert to an unsigned integer. | 179 // operations, we do not have to convert to an unsigned integer. |
| 185 return hasNonBitOpUser(instruction, new Set<HPhi>()); | 180 return hasNonBitOpUser(instruction, new Set<HPhi>()); |
| 186 } | 181 } |
| 187 | 182 |
| 188 /** | 183 /** |
| 189 * If the [instruction] is not `null` it will be used to attach the position | 184 * If the [instruction] is not `null` it will be used to attach the position |
| 190 * to the [statement]. | 185 * to the [statement]. |
| 191 */ | 186 */ |
| 192 void pushStatement(js.Statement statement, [HInstruction instruction]) { | 187 void pushStatement(js.Statement statement) { |
| 193 assert(expressionStack.isEmpty); | 188 assert(expressionStack.isEmpty); |
| 194 if (instruction != null) { | |
| 195 statement = attachLocation(statement, instruction); | |
| 196 } | |
| 197 currentContainer.statements.add(statement); | 189 currentContainer.statements.add(statement); |
| 198 } | 190 } |
| 199 | 191 |
| 200 void insertStatementAtStart(js.Statement statement) { | 192 void insertStatementAtStart(js.Statement statement) { |
| 201 currentContainer.statements.insert(0, statement); | 193 currentContainer.statements.insert(0, statement); |
| 202 } | 194 } |
| 203 | 195 |
| 204 /** | 196 /** |
| 205 * If the [instruction] is not `null` it will be used to attach the position | 197 * If the [instruction] is not `null` it will be used to attach the position |
| 206 * to the [expression]. | 198 * to the [expression]. |
| 207 */ | 199 */ |
| 208 pushExpressionAsStatement(js.Expression expression, | 200 pushExpressionAsStatement(js.Expression expression, |
| 209 [HInstruction instruction]) { | 201 SourceInformation sourceInformation) { |
| 210 pushStatement(new js.ExpressionStatement(expression), instruction); | 202 pushStatement(new js.ExpressionStatement(expression) |
| 203 .withSourceInformation(sourceInformation)); |
| 211 } | 204 } |
| 212 | 205 |
| 213 /** | 206 /** |
| 214 * If the [instruction] is not `null` it will be used to attach the position | 207 * If the [instruction] is not `null` it will be used to attach the position |
| 215 * to the [expression]. | 208 * to the [expression]. |
| 216 */ | 209 */ |
| 217 push(js.Expression expression, [HInstruction instruction]) { | 210 push(js.Expression expression) { |
| 218 if (instruction != null) { | |
| 219 expression = attachLocation(expression, instruction); | |
| 220 } | |
| 221 expressionStack.add(expression); | 211 expressionStack.add(expression); |
| 222 } | 212 } |
| 223 | 213 |
| 224 js.Expression pop() { | 214 js.Expression pop() { |
| 225 return expressionStack.removeLast(); | 215 return expressionStack.removeLast(); |
| 226 } | 216 } |
| 227 | 217 |
| 228 attachLocationToLast(HInstruction instruction) { | |
| 229 int index = expressionStack.length - 1; | |
| 230 expressionStack[index] = | |
| 231 attachLocation(expressionStack[index], instruction); | |
| 232 } | |
| 233 | |
| 234 js.Node attachLocation(js.Node jsNode, HInstruction instruction) { | |
| 235 return attachSourceInformation(jsNode, instruction.sourceInformation); | |
| 236 } | |
| 237 | |
| 238 js.Node attachSourceInformation(js.Node jsNode, | |
| 239 SourceInformation sourceInformation) { | |
| 240 return jsNode.withSourceInformation(sourceInformation); | |
| 241 } | |
| 242 | |
| 243 void preGenerateMethod(HGraph graph) { | 218 void preGenerateMethod(HGraph graph) { |
| 244 new SsaInstructionSelection(compiler).visitGraph(graph); | 219 new SsaInstructionSelection(compiler).visitGraph(graph); |
| 245 new SsaTypeKnownRemover().visitGraph(graph); | 220 new SsaTypeKnownRemover().visitGraph(graph); |
| 246 new SsaTrustedCheckRemover(compiler).visitGraph(graph); | 221 new SsaTrustedCheckRemover(compiler).visitGraph(graph); |
| 247 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph); | 222 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph); |
| 248 new SsaConditionMerger( | 223 new SsaConditionMerger( |
| 249 generateAtUseSite, controlFlowOperators).visitGraph(graph); | 224 generateAtUseSite, controlFlowOperators).visitGraph(graph); |
| 250 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder( | 225 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder( |
| 251 compiler, generateAtUseSite, controlFlowOperators); | 226 compiler, generateAtUseSite, controlFlowOperators); |
| 252 intervalBuilder.visitGraph(graph); | 227 intervalBuilder.visitGraph(graph); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 // Also check for the shortcut where y equals 1: x++ and x--. | 467 // Also check for the shortcut where y equals 1: x++ and x--. |
| 493 if ((op == '+' || op == '-') && | 468 if ((op == '+' || op == '-') && |
| 494 binary.right is js.LiteralNumber && | 469 binary.right is js.LiteralNumber && |
| 495 (binary.right as js.LiteralNumber).value == "1") { | 470 (binary.right as js.LiteralNumber).value == "1") { |
| 496 return new js.Prefix(op == '+' ? '++' : '--', binary.left); | 471 return new js.Prefix(op == '+' ? '++' : '--', binary.left); |
| 497 } | 472 } |
| 498 return new js.Assignment.compound(binary.left, op, binary.right); | 473 return new js.Assignment.compound(binary.left, op, binary.right); |
| 499 } | 474 } |
| 500 } | 475 } |
| 501 } | 476 } |
| 502 return new js.Assignment(new js.VariableUse(variableName), value); | 477 return new js.Assignment(new js.VariableUse(variableName), value) |
| 478 .withSourceInformation(value.sourceInformation); |
| 503 } | 479 } |
| 504 | 480 |
| 505 void assignVariable(String variableName, js.Expression value) { | 481 void assignVariable(String variableName, |
| 482 js.Expression value, |
| 483 SourceInformation sourceInformation) { |
| 506 if (isGeneratingExpression) { | 484 if (isGeneratingExpression) { |
| 507 // If we are in an expression then we can't declare the variable here. | 485 // If we are in an expression then we can't declare the variable here. |
| 508 // We have no choice, but to use it and then declare it separately. | 486 // We have no choice, but to use it and then declare it separately. |
| 509 if (!isVariableDeclared(variableName)) { | 487 if (!isVariableDeclared(variableName)) { |
| 510 collectedVariableDeclarations.add(variableName); | 488 collectedVariableDeclarations.add(variableName); |
| 511 } | 489 } |
| 512 push(generateExpressionAssignment(variableName, value)); | 490 push(generateExpressionAssignment(variableName, value)); |
| 513 // Otherwise if we are trying to declare inline and we are in a statement | 491 // Otherwise if we are trying to declare inline and we are in a statement |
| 514 // then we declare (unless it was already declared). | 492 // then we declare (unless it was already declared). |
| 515 } else if (!shouldGroupVarDeclarations && | 493 } else if (!shouldGroupVarDeclarations && |
| 516 !declaredLocals.contains(variableName)) { | 494 !declaredLocals.contains(variableName)) { |
| 517 // It may be necessary to remove it from the ones to be declared later. | 495 // It may be necessary to remove it from the ones to be declared later. |
| 518 collectedVariableDeclarations.remove(variableName); | 496 collectedVariableDeclarations.remove(variableName); |
| 519 declaredLocals.add(variableName); | 497 declaredLocals.add(variableName); |
| 520 js.VariableDeclaration decl = new js.VariableDeclaration(variableName); | 498 js.VariableDeclaration decl = new js.VariableDeclaration(variableName); |
| 521 js.VariableInitialization initialization = | 499 js.VariableInitialization initialization = |
| 522 new js.VariableInitialization(decl, value); | 500 new js.VariableInitialization(decl, value); |
| 523 | 501 |
| 524 pushExpressionAsStatement(new js.VariableDeclarationList( | 502 pushExpressionAsStatement(new js.VariableDeclarationList( |
| 525 <js.VariableInitialization>[initialization])); | 503 <js.VariableInitialization>[initialization]), |
| 504 sourceInformation); |
| 526 } else { | 505 } else { |
| 527 // Otherwise we are just going to use it. If we have not already declared | 506 // Otherwise we are just going to use it. If we have not already declared |
| 528 // it then we make sure we will declare it later. | 507 // it then we make sure we will declare it later. |
| 529 if (!declaredLocals.contains(variableName)) { | 508 if (!declaredLocals.contains(variableName)) { |
| 530 collectedVariableDeclarations.add(variableName); | 509 collectedVariableDeclarations.add(variableName); |
| 531 } | 510 } |
| 532 pushExpressionAsStatement( | 511 pushExpressionAsStatement( |
| 533 generateExpressionAssignment(variableName, value)); | 512 generateExpressionAssignment(variableName, value), |
| 513 sourceInformation); |
| 534 } | 514 } |
| 535 } | 515 } |
| 536 | 516 |
| 537 void define(HInstruction instruction) { | 517 void define(HInstruction instruction) { |
| 538 // For simple type checks like i = intTypeCheck(i), we don't have to | 518 // For simple type checks like i = intTypeCheck(i), we don't have to |
| 539 // emit an assignment, because the intTypeCheck just returns its | 519 // emit an assignment, because the intTypeCheck just returns its |
| 540 // argument. | 520 // argument. |
| 541 bool needsAssignment = true; | 521 bool needsAssignment = true; |
| 542 if (instruction is HTypeConversion) { | 522 if (instruction is HTypeConversion) { |
| 543 HTypeConversion typeConversion = instruction; | 523 HTypeConversion typeConversion = instruction; |
| 544 String inputName = variableNames.getName(typeConversion.checkedInput); | 524 String inputName = variableNames.getName(typeConversion.checkedInput); |
| 545 if (variableNames.getName(instruction) == inputName) { | 525 if (variableNames.getName(instruction) == inputName) { |
| 546 needsAssignment = false; | 526 needsAssignment = false; |
| 547 } | 527 } |
| 548 } | 528 } |
| 549 if (instruction is HLocalValue) { | 529 if (instruction is HLocalValue) { |
| 550 needsAssignment = false; | 530 needsAssignment = false; |
| 551 } | 531 } |
| 552 | 532 |
| 553 if (needsAssignment && | 533 if (needsAssignment && |
| 554 !instruction.isControlFlow() && variableNames.hasName(instruction)) { | 534 !instruction.isControlFlow() && variableNames.hasName(instruction)) { |
| 555 visitExpression(instruction); | 535 visitExpression(instruction); |
| 556 assignVariable(variableNames.getName(instruction), pop()); | 536 assignVariable(variableNames.getName(instruction), pop(), |
| 537 instruction.sourceInformation); |
| 557 return; | 538 return; |
| 558 } | 539 } |
| 559 | 540 |
| 560 if (isGeneratingExpression) { | 541 if (isGeneratingExpression) { |
| 561 visitExpression(instruction); | 542 visitExpression(instruction); |
| 562 } else { | 543 } else { |
| 563 visitStatement(instruction); | 544 visitStatement(instruction); |
| 564 } | 545 } |
| 565 } | 546 } |
| 566 | 547 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 587 isGeneratingExpression = true; | 568 isGeneratingExpression = true; |
| 588 visit(node); | 569 visit(node); |
| 589 isGeneratingExpression = oldIsGeneratingExpression; | 570 isGeneratingExpression = oldIsGeneratingExpression; |
| 590 } | 571 } |
| 591 | 572 |
| 592 visitStatement(HInstruction node) { | 573 visitStatement(HInstruction node) { |
| 593 assert(!isGeneratingExpression); | 574 assert(!isGeneratingExpression); |
| 594 visit(node); | 575 visit(node); |
| 595 if (!expressionStack.isEmpty) { | 576 if (!expressionStack.isEmpty) { |
| 596 assert(expressionStack.length == 1); | 577 assert(expressionStack.length == 1); |
| 597 pushExpressionAsStatement(pop()); | 578 js.Expression expression = pop(); |
| 579 pushExpressionAsStatement(expression, node.sourceInformation); |
| 598 } | 580 } |
| 599 } | 581 } |
| 600 | 582 |
| 601 void continueAsBreak(LabelDefinition target) { | 583 void continueAsBreak(LabelDefinition target) { |
| 602 pushStatement(new js.Break(backend.namer.continueLabelName(target))); | 584 pushStatement(new js.Break(backend.namer.continueLabelName(target))); |
| 603 } | 585 } |
| 604 | 586 |
| 605 void implicitContinueAsBreak(JumpTarget target) { | 587 void implicitContinueAsBreak(JumpTarget target) { |
| 606 pushStatement(new js.Break( | 588 pushStatement(new js.Break( |
| 607 backend.namer.implicitContinueLabelName(target))); | 589 backend.namer.implicitContinueLabelName(target))); |
| 608 } | 590 } |
| 609 | 591 |
| 610 void implicitBreakWithLabel(JumpTarget target) { | 592 void implicitBreakWithLabel(JumpTarget target) { |
| 611 pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target))); | 593 pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target))); |
| 612 } | 594 } |
| 613 | 595 |
| 614 js.Statement wrapIntoLabels(js.Statement result, List<LabelDefinition> labels)
{ | 596 js.Statement wrapIntoLabels(js.Statement result, |
| 597 List<LabelDefinition> labels) { |
| 615 for (LabelDefinition label in labels) { | 598 for (LabelDefinition label in labels) { |
| 616 if (label.isTarget) { | 599 if (label.isTarget) { |
| 617 String breakLabelString = backend.namer.breakLabelName(label); | 600 String breakLabelString = backend.namer.breakLabelName(label); |
| 618 result = new js.LabeledStatement(breakLabelString, result); | 601 result = new js.LabeledStatement(breakLabelString, result); |
| 619 } | 602 } |
| 620 } | 603 } |
| 621 return result; | 604 return result; |
| 622 } | 605 } |
| 623 | 606 |
| 624 | 607 |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 827 // The body might be labeled. Ignore this when recursing on the | 810 // The body might be labeled. Ignore this when recursing on the |
| 828 // subgraph. | 811 // subgraph. |
| 829 // TODO(lrn): Remove this extra labeling when handling all loops | 812 // TODO(lrn): Remove this extra labeling when handling all loops |
| 830 // using subgraphs. | 813 // using subgraphs. |
| 831 oldContainer = currentContainer; | 814 oldContainer = currentContainer; |
| 832 js.Statement body = new js.Block.empty(); | 815 js.Statement body = new js.Block.empty(); |
| 833 currentContainer = body; | 816 currentContainer = body; |
| 834 visitBodyIgnoreLabels(info); | 817 visitBodyIgnoreLabels(info); |
| 835 currentContainer = oldContainer; | 818 currentContainer = oldContainer; |
| 836 body = unwrapStatement(body); | 819 body = unwrapStatement(body); |
| 837 loop = new js.For(jsInitialization, jsCondition, jsUpdates, body); | 820 loop = new js.For(jsInitialization, jsCondition, jsUpdates, body) |
| 821 .withSourceInformation(info.sourceInformation); |
| 838 } else { | 822 } else { |
| 839 // We have either no update graph, or it's too complex to | 823 // We have either no update graph, or it's too complex to |
| 840 // put in an expression. | 824 // put in an expression. |
| 841 if (initialization != null) { | 825 if (initialization != null) { |
| 842 generateStatements(initialization); | 826 generateStatements(initialization); |
| 843 } | 827 } |
| 844 js.Expression jsCondition; | 828 js.Expression jsCondition; |
| 845 js.Block oldContainer = currentContainer; | 829 js.Block oldContainer = currentContainer; |
| 846 js.Statement body = new js.Block.empty(); | 830 js.Statement body = new js.Block.empty(); |
| 847 if (isConditionExpression && !hasPhiUpdates) { | 831 if (isConditionExpression && !hasPhiUpdates) { |
| 848 jsCondition = generateExpression(condition); | 832 jsCondition = generateExpression(condition); |
| 849 currentContainer = body; | 833 currentContainer = body; |
| 850 } else { | 834 } else { |
| 851 jsCondition = newLiteralBool(true); | 835 jsCondition = newLiteralBool(true, info.sourceInformation); |
| 852 currentContainer = body; | 836 currentContainer = body; |
| 853 generateStatements(condition); | 837 generateStatements(condition); |
| 854 use(condition.conditionExpression); | 838 use(condition.conditionExpression); |
| 855 js.Expression ifTest = new js.Prefix("!", pop()); | 839 js.Expression ifTest = new js.Prefix("!", pop()); |
| 856 js.Statement jsBreak = new js.Break(null); | 840 js.Statement jsBreak = new js.Break(null); |
| 857 js.Statement exitLoop; | 841 js.Statement exitLoop; |
| 858 if (avoidContainer.statements.isEmpty) { | 842 if (avoidContainer.statements.isEmpty) { |
| 859 exitLoop = jsBreak; | 843 exitLoop = jsBreak; |
| 860 } else { | 844 } else { |
| 861 avoidContainer.statements.add(jsBreak); | 845 avoidContainer.statements.add(jsBreak); |
| 862 exitLoop = avoidContainer; | 846 exitLoop = avoidContainer; |
| 863 } | 847 } |
| 864 pushStatement(new js.If.noElse(ifTest, exitLoop)); | 848 pushStatement(new js.If.noElse(ifTest, exitLoop)); |
| 865 } | 849 } |
| 866 if (info.updates != null) { | 850 if (info.updates != null) { |
| 867 wrapLoopBodyForContinue(info); | 851 wrapLoopBodyForContinue(info); |
| 868 generateStatements(info.updates); | 852 generateStatements(info.updates); |
| 869 } else { | 853 } else { |
| 870 visitBodyIgnoreLabels(info); | 854 visitBodyIgnoreLabels(info); |
| 871 } | 855 } |
| 872 currentContainer = oldContainer; | 856 currentContainer = oldContainer; |
| 873 body = unwrapStatement(body); | 857 body = unwrapStatement(body); |
| 874 loop = new js.While(jsCondition, body); | 858 loop = new js.While(jsCondition, body) |
| 859 .withSourceInformation(info.sourceInformation); |
| 875 } | 860 } |
| 876 break; | 861 break; |
| 877 case HLoopBlockInformation.DO_WHILE_LOOP: | 862 case HLoopBlockInformation.DO_WHILE_LOOP: |
| 878 if (info.initializer != null) { | 863 if (info.initializer != null) { |
| 879 generateStatements(info.initializer); | 864 generateStatements(info.initializer); |
| 880 } | 865 } |
| 881 // We inserted a basic block to avoid critical edges. This block is | 866 // We inserted a basic block to avoid critical edges. This block is |
| 882 // part of the LoopBlockInformation and must therefore be handled here. | 867 // part of the LoopBlockInformation and must therefore be handled here. |
| 883 js.Block oldContainer = currentContainer; | 868 js.Block oldContainer = currentContainer; |
| 884 js.Block exitAvoidContainer = new js.Block.empty(); | 869 js.Block exitAvoidContainer = new js.Block.empty(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 915 push(generateExpression(condition)); | 900 push(generateExpression(condition)); |
| 916 } else { | 901 } else { |
| 917 generateStatements(condition); | 902 generateStatements(condition); |
| 918 use(condition.conditionExpression); | 903 use(condition.conditionExpression); |
| 919 } | 904 } |
| 920 js.Expression jsCondition = pop(); | 905 js.Expression jsCondition = pop(); |
| 921 if (jsCondition == null) { | 906 if (jsCondition == null) { |
| 922 // If the condition is dead code, we turn the do-while into | 907 // If the condition is dead code, we turn the do-while into |
| 923 // a simpler while because we will never reach the condition | 908 // a simpler while because we will never reach the condition |
| 924 // at the end of the loop anyway. | 909 // at the end of the loop anyway. |
| 925 loop = new js.While(newLiteralBool(true), unwrapStatement(body)); | 910 loop = new js.While( |
| 911 newLiteralBool(true, info.sourceInformation), |
| 912 unwrapStatement(body)) |
| 913 .withSourceInformation(info.sourceInformation); |
| 926 } else { | 914 } else { |
| 927 if (hasPhiUpdates || hasExitPhiUpdates) { | 915 if (hasPhiUpdates || hasExitPhiUpdates) { |
| 928 updateBody.statements.add(new js.Continue(null)); | 916 updateBody.statements.add(new js.Continue(null)); |
| 929 js.Statement jsBreak = new js.Break(null); | 917 js.Statement jsBreak = new js.Break(null); |
| 930 js.Statement exitLoop; | 918 js.Statement exitLoop; |
| 931 if (exitAvoidContainer.statements.isEmpty) { | 919 if (exitAvoidContainer.statements.isEmpty) { |
| 932 exitLoop = jsBreak; | 920 exitLoop = jsBreak; |
| 933 } else { | 921 } else { |
| 934 exitAvoidContainer.statements.add(jsBreak); | 922 exitAvoidContainer.statements.add(jsBreak); |
| 935 exitLoop = exitAvoidContainer; | 923 exitLoop = exitAvoidContainer; |
| 936 } | 924 } |
| 937 body.statements.add( | 925 body.statements.add( |
| 938 new js.If(jsCondition, updateBody, exitLoop)); | 926 new js.If(jsCondition, updateBody, exitLoop)); |
| 939 jsCondition = newLiteralBool(true); | 927 jsCondition = newLiteralBool(true, info.sourceInformation); |
| 940 } | 928 } |
| 941 loop = new js.Do(unwrapStatement(body), jsCondition); | 929 loop = new js.Do(unwrapStatement(body), jsCondition) |
| 930 .withSourceInformation(info.sourceInformation); |
| 942 } | 931 } |
| 943 currentContainer = oldContainer; | 932 currentContainer = oldContainer; |
| 944 break; | 933 break; |
| 945 default: | 934 default: |
| 946 compiler.internalError(condition.conditionExpression, | 935 compiler.internalError(condition.conditionExpression, |
| 947 'Unexpected loop kind: ${info.kind}.'); | 936 'Unexpected loop kind: ${info.kind}.'); |
| 948 } | 937 } |
| 949 js.Statement result = attachSourceInformation(loop, info.sourceInformation); | 938 js.Statement result = loop; |
| 950 if (info.kind == HLoopBlockInformation.SWITCH_CONTINUE_LOOP) { | 939 if (info.kind == HLoopBlockInformation.SWITCH_CONTINUE_LOOP) { |
| 951 String continueLabelString = | 940 String continueLabelString = |
| 952 backend.namer.implicitContinueLabelName(info.target); | 941 backend.namer.implicitContinueLabelName(info.target); |
| 953 result = new js.LabeledStatement(continueLabelString, result); | 942 result = new js.LabeledStatement(continueLabelString, result); |
| 954 } | 943 } |
| 955 pushStatement(wrapIntoLabels(result, info.labels)); | 944 pushStatement(wrapIntoLabels(result, info.labels)); |
| 956 return true; | 945 return true; |
| 957 } | 946 } |
| 958 | 947 |
| 959 bool visitLabeledBlockInfo(HLabeledBlockInformation labeledBlockInfo) { | 948 bool visitLabeledBlockInfo(HLabeledBlockInformation labeledBlockInfo) { |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 | 1075 |
| 1087 // If this node has block-structure based information attached, | 1076 // If this node has block-structure based information attached, |
| 1088 // try using that to traverse from here. | 1077 // try using that to traverse from here. |
| 1089 if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) { | 1078 if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) { |
| 1090 return; | 1079 return; |
| 1091 } | 1080 } |
| 1092 iterateBasicBlock(node); | 1081 iterateBasicBlock(node); |
| 1093 } | 1082 } |
| 1094 | 1083 |
| 1095 void emitAssignment(String destination, String source) { | 1084 void emitAssignment(String destination, String source) { |
| 1096 assignVariable(destination, new js.VariableUse(source)); | 1085 assignVariable(destination, new js.VariableUse(source), null); |
| 1097 } | 1086 } |
| 1098 | 1087 |
| 1099 /** | 1088 /** |
| 1100 * Sequentialize a list of conceptually parallel copies. Parallel | 1089 * Sequentialize a list of conceptually parallel copies. Parallel |
| 1101 * copies may contain cycles, that this method breaks. | 1090 * copies may contain cycles, that this method breaks. |
| 1102 */ | 1091 */ |
| 1103 void sequentializeCopies(Iterable<Copy> copies, | 1092 void sequentializeCopies(Iterable<Copy> copies, |
| 1104 String tempName, | 1093 String tempName, |
| 1105 void doAssignment(String target, String source)) { | 1094 void doAssignment(String target, String source)) { |
| 1106 // Map to keep track of the current location (ie the variable that | 1095 // Map to keep track of the current location (ie the variable that |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 Iterable<Copy> copies = handler.copies.map((Copy copy) { | 1175 Iterable<Copy> copies = handler.copies.map((Copy copy) { |
| 1187 return new Copy(variableNames.getName(copy.source), | 1176 return new Copy(variableNames.getName(copy.source), |
| 1188 variableNames.getName(copy.destination)); | 1177 variableNames.getName(copy.destination)); |
| 1189 }); | 1178 }); |
| 1190 | 1179 |
| 1191 sequentializeCopies(copies, variableNames.getSwapTemp(), emitAssignment); | 1180 sequentializeCopies(copies, variableNames.getSwapTemp(), emitAssignment); |
| 1192 | 1181 |
| 1193 for (Copy copy in handler.assignments) { | 1182 for (Copy copy in handler.assignments) { |
| 1194 String name = variableNames.getName(copy.destination); | 1183 String name = variableNames.getName(copy.destination); |
| 1195 use(copy.source); | 1184 use(copy.source); |
| 1196 assignVariable(name, pop()); | 1185 assignVariable(name, pop(), null); |
| 1197 } | 1186 } |
| 1198 } | 1187 } |
| 1199 | 1188 |
| 1200 void iterateBasicBlock(HBasicBlock node) { | 1189 void iterateBasicBlock(HBasicBlock node) { |
| 1201 HInstruction instruction = node.first; | 1190 HInstruction instruction = node.first; |
| 1202 while (!identical(instruction, node.last)) { | 1191 while (!identical(instruction, node.last)) { |
| 1203 if (!isGenerateAtUseSite(instruction)) { | 1192 if (!isGenerateAtUseSite(instruction)) { |
| 1204 define(instruction); | 1193 define(instruction); |
| 1205 } | 1194 } |
| 1206 instruction = instruction.next; | 1195 instruction = instruction.next; |
| 1207 } | 1196 } |
| 1208 assignPhisOfSuccessors(node); | 1197 assignPhisOfSuccessors(node); |
| 1209 visit(instruction); | 1198 visit(instruction); |
| 1210 } | 1199 } |
| 1211 | 1200 |
| 1212 visitInvokeBinary(HInvokeBinary node, String op) { | 1201 void handleInvokeBinary(HInvokeBinary node, |
| 1202 String op, |
| 1203 SourceInformation sourceInformation) { |
| 1213 use(node.left); | 1204 use(node.left); |
| 1214 js.Expression jsLeft = pop(); | 1205 js.Expression jsLeft = pop(); |
| 1215 use(node.right); | 1206 use(node.right); |
| 1216 push(new js.Binary(op, jsLeft, pop()), node); | 1207 push(new js.Binary(op, jsLeft, pop()) |
| 1208 .withSourceInformation(sourceInformation)); |
| 1217 } | 1209 } |
| 1218 | 1210 |
| 1219 visitRelational(HRelational node, String op) => visitInvokeBinary(node, op); | 1211 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1212 handleInvokeBinary(node, op, node.sourceInformation); |
| 1213 } |
| 1214 |
| 1215 visitRelational(HRelational node, String op) { |
| 1216 handleInvokeBinary(node, op, node.sourceInformation); |
| 1217 } |
| 1220 | 1218 |
| 1221 // We want the outcome of bit-operations to be positive. We use the unsigned | 1219 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1222 // shift operator to achieve this. | 1220 // shift operator to achieve this. |
| 1223 visitBitInvokeBinary(HBinaryBitOp node, String op) { | 1221 visitBitInvokeBinary(HBinaryBitOp node, String op) { |
| 1224 visitInvokeBinary(node, op); | 1222 visitInvokeBinary(node, op); |
| 1225 if (op != '>>>' && requiresUintConversion(node)) { | 1223 if (op != '>>>' && requiresUintConversion(node)) { |
| 1226 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); | 1224 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")) |
| 1225 .withSourceInformation(node.sourceInformation)); |
| 1227 } | 1226 } |
| 1228 } | 1227 } |
| 1229 | 1228 |
| 1230 visitInvokeUnary(HInvokeUnary node, String op) { | 1229 visitInvokeUnary(HInvokeUnary node, String op) { |
| 1231 use(node.operand); | 1230 use(node.operand); |
| 1232 push(new js.Prefix(op, pop()), node); | 1231 push(new js.Prefix(op, pop()) |
| 1232 .withSourceInformation(node.sourceInformation)); |
| 1233 } | 1233 } |
| 1234 | 1234 |
| 1235 // We want the outcome of bit-operations to be positive. We use the unsigned | 1235 // We want the outcome of bit-operations to be positive. We use the unsigned |
| 1236 // shift operator to achieve this. | 1236 // shift operator to achieve this. |
| 1237 visitBitInvokeUnary(HInvokeUnary node, String op) { | 1237 visitBitInvokeUnary(HInvokeUnary node, String op) { |
| 1238 visitInvokeUnary(node, op); | 1238 visitInvokeUnary(node, op); |
| 1239 if (requiresUintConversion(node)) { | 1239 if (requiresUintConversion(node)) { |
| 1240 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node); | 1240 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")) |
| 1241 .withSourceInformation(node.sourceInformation)); |
| 1241 } | 1242 } |
| 1242 } | 1243 } |
| 1243 | 1244 |
| 1244 void emitIdentityComparison(HIdentity instruction, bool inverse) { | 1245 void emitIdentityComparison(HIdentity instruction, |
| 1246 SourceInformation sourceInformation, |
| 1247 {bool inverse: false}) { |
| 1245 String op = instruction.singleComparisonOp; | 1248 String op = instruction.singleComparisonOp; |
| 1246 HInstruction left = instruction.left; | 1249 HInstruction left = instruction.left; |
| 1247 HInstruction right = instruction.right; | 1250 HInstruction right = instruction.right; |
| 1248 if (op != null) { | 1251 if (op != null) { |
| 1249 use(left); | 1252 use(left); |
| 1250 js.Expression jsLeft = pop(); | 1253 js.Expression jsLeft = pop(); |
| 1251 use(right); | 1254 use(right); |
| 1252 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop())); | 1255 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop()) |
| 1256 .withSourceInformation(sourceInformation)); |
| 1253 } else { | 1257 } else { |
| 1254 assert(NullConstantValue.JsNull == 'null'); | 1258 assert(NullConstantValue.JsNull == 'null'); |
| 1255 use(left); | 1259 use(left); |
| 1256 js.Binary leftEqualsNull = | 1260 js.Binary leftEqualsNull = |
| 1257 new js.Binary("==", pop(), new js.LiteralNull()); | 1261 new js.Binary("==", pop(), new js.LiteralNull()); |
| 1258 use(right); | 1262 use(right); |
| 1259 js.Binary rightEqualsNull = | 1263 js.Binary rightEqualsNull = |
| 1260 new js.Binary(mapRelationalOperator("==", inverse), | 1264 new js.Binary(mapRelationalOperator("==", inverse), |
| 1261 pop(), new js.LiteralNull()); | 1265 pop(), new js.LiteralNull()); |
| 1262 use(right); | 1266 use(right); |
| 1263 use(left); | 1267 use(left); |
| 1264 js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse), | 1268 js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse), |
| 1265 pop(), pop()); | 1269 pop(), pop()); |
| 1266 | 1270 |
| 1267 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)); | 1271 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq) |
| 1272 .withSourceInformation(sourceInformation)); |
| 1268 } | 1273 } |
| 1269 } | 1274 } |
| 1270 | 1275 |
| 1271 visitIdentity(HIdentity node) { | 1276 visitIdentity(HIdentity node) { |
| 1272 emitIdentityComparison(node, false); | 1277 emitIdentityComparison(node, node.sourceInformation, inverse: false); |
| 1273 } | 1278 } |
| 1274 | 1279 |
| 1275 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); | 1280 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); |
| 1276 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); | 1281 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); |
| 1277 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); | 1282 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); |
| 1278 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); | 1283 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); |
| 1279 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); | 1284 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); |
| 1280 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); | 1285 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); |
| 1281 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); | 1286 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); |
| 1282 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); | 1287 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); |
| 1283 visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<'); | 1288 visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<'); |
| 1284 visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>'); | 1289 visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>'); |
| 1285 | 1290 |
| 1286 visitTruncatingDivide(HTruncatingDivide node) { | 1291 visitTruncatingDivide(HTruncatingDivide node) { |
| 1287 assert(node.isUInt31(compiler)); | 1292 assert(node.isUInt31(compiler)); |
| 1288 // TODO(karlklose): Enable this assertion again when type propagation is | 1293 // TODO(karlklose): Enable this assertion again when type propagation is |
| 1289 // fixed. Issue 23555. | 1294 // fixed. Issue 23555. |
| 1290 // assert(node.left.isUInt32(compiler)); | 1295 // assert(node.left.isUInt32(compiler)); |
| 1291 assert(node.right.isPositiveInteger(compiler)); | 1296 assert(node.right.isPositiveInteger(compiler)); |
| 1292 use(node.left); | 1297 use(node.left); |
| 1293 js.Expression jsLeft = pop(); | 1298 js.Expression jsLeft = pop(); |
| 1294 use(node.right); | 1299 use(node.right); |
| 1295 push(new js.Binary('/', jsLeft, pop()), node); | 1300 push(new js.Binary('/', jsLeft, pop()) |
| 1296 push(new js.Binary('|', pop(), new js.LiteralNumber("0")), node); | 1301 .withSourceInformation(node.sourceInformation)); |
| 1302 push(new js.Binary('|', pop(), new js.LiteralNumber("0")) |
| 1303 .withSourceInformation(node.sourceInformation)); |
| 1297 } | 1304 } |
| 1298 | 1305 |
| 1299 visitNegate(HNegate node) => visitInvokeUnary(node, '-'); | 1306 visitNegate(HNegate node) => visitInvokeUnary(node, '-'); |
| 1300 | 1307 |
| 1301 visitLess(HLess node) => visitRelational(node, '<'); | 1308 visitLess(HLess node) => visitRelational(node, '<'); |
| 1302 visitLessEqual(HLessEqual node) => visitRelational(node, '<='); | 1309 visitLessEqual(HLessEqual node) => visitRelational(node, '<='); |
| 1303 visitGreater(HGreater node) => visitRelational(node, '>'); | 1310 visitGreater(HGreater node) => visitRelational(node, '>'); |
| 1304 visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>='); | 1311 visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>='); |
| 1305 | 1312 |
| 1306 visitBoolify(HBoolify node) { | 1313 visitBoolify(HBoolify node) { |
| 1307 assert(node.inputs.length == 1); | 1314 assert(node.inputs.length == 1); |
| 1308 use(node.inputs[0]); | 1315 use(node.inputs[0]); |
| 1309 push(new js.Binary('===', pop(), newLiteralBool(true)), node); | 1316 push(new js.Binary('===', pop(), |
| 1317 newLiteralBool(true, node.sourceInformation)) |
| 1318 .withSourceInformation(node.sourceInformation)); |
| 1310 } | 1319 } |
| 1311 | 1320 |
| 1312 visitExit(HExit node) { | 1321 visitExit(HExit node) { |
| 1313 // Don't do anything. | 1322 // Don't do anything. |
| 1314 } | 1323 } |
| 1315 | 1324 |
| 1316 visitGoto(HGoto node) { | 1325 visitGoto(HGoto node) { |
| 1317 HBasicBlock block = node.block; | 1326 HBasicBlock block = node.block; |
| 1318 assert(block.successors.length == 1); | 1327 assert(block.successors.length == 1); |
| 1319 List<HBasicBlock> dominated = block.dominatedBlocks; | 1328 List<HBasicBlock> dominated = block.dominatedBlocks; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1355 if (action == null) return false; | 1364 if (action == null) return false; |
| 1356 action(entity); | 1365 action(entity); |
| 1357 return true; | 1366 return true; |
| 1358 } | 1367 } |
| 1359 | 1368 |
| 1360 visitBreak(HBreak node) { | 1369 visitBreak(HBreak node) { |
| 1361 assert(node.block.successors.length == 1); | 1370 assert(node.block.successors.length == 1); |
| 1362 if (node.label != null) { | 1371 if (node.label != null) { |
| 1363 LabelDefinition label = node.label; | 1372 LabelDefinition label = node.label; |
| 1364 if (!tryCallAction(breakAction, label)) { | 1373 if (!tryCallAction(breakAction, label)) { |
| 1365 pushStatement(new js.Break(backend.namer.breakLabelName(label)), node); | 1374 pushStatement( |
| 1375 new js.Break(backend.namer.breakLabelName(label)) |
| 1376 .withSourceInformation(node.sourceInformation)); |
| 1366 } | 1377 } |
| 1367 } else { | 1378 } else { |
| 1368 JumpTarget target = node.target; | 1379 JumpTarget target = node.target; |
| 1369 if (!tryCallAction(breakAction, target)) { | 1380 if (!tryCallAction(breakAction, target)) { |
| 1370 if (node.breakSwitchContinueLoop) { | 1381 if (node.breakSwitchContinueLoop) { |
| 1371 pushStatement(new js.Break( | 1382 pushStatement( |
| 1372 backend.namer.implicitContinueLabelName(target)), node); | 1383 new js.Break(backend.namer.implicitContinueLabelName(target)) |
| 1384 .withSourceInformation(node.sourceInformation)); |
| 1373 } else { | 1385 } else { |
| 1374 pushStatement(new js.Break(null), node); | 1386 pushStatement(new js.Break(null) |
| 1387 .withSourceInformation(node.sourceInformation)); |
| 1375 } | 1388 } |
| 1376 } | 1389 } |
| 1377 } | 1390 } |
| 1378 } | 1391 } |
| 1379 | 1392 |
| 1380 visitContinue(HContinue node) { | 1393 visitContinue(HContinue node) { |
| 1381 assert(node.block.successors.length == 1); | 1394 assert(node.block.successors.length == 1); |
| 1382 if (node.label != null) { | 1395 if (node.label != null) { |
| 1383 LabelDefinition label = node.label; | 1396 LabelDefinition label = node.label; |
| 1384 if (!tryCallAction(continueAction, label)) { | 1397 if (!tryCallAction(continueAction, label)) { |
| 1385 // TODO(floitsch): should this really be the breakLabelName? | 1398 // TODO(floitsch): should this really be the breakLabelName? |
| 1386 pushStatement(new js.Continue(backend.namer.breakLabelName(label)), | 1399 pushStatement( |
| 1387 node); | 1400 new js.Continue(backend.namer.breakLabelName(label)) |
| 1401 .withSourceInformation(node.sourceInformation)); |
| 1388 } | 1402 } |
| 1389 } else { | 1403 } else { |
| 1390 JumpTarget target = node.target; | 1404 JumpTarget target = node.target; |
| 1391 if (!tryCallAction(continueAction, target)) { | 1405 if (!tryCallAction(continueAction, target)) { |
| 1392 if (target.statement is ast.SwitchStatement) { | 1406 if (target.statement is ast.SwitchStatement) { |
| 1393 pushStatement(new js.Continue( | 1407 pushStatement( |
| 1394 backend.namer.implicitContinueLabelName(target)), node); | 1408 new js.Continue(backend.namer.implicitContinueLabelName(target)) |
| 1409 .withSourceInformation(node.sourceInformation)); |
| 1395 } else { | 1410 } else { |
| 1396 pushStatement(new js.Continue(null), node); | 1411 pushStatement(new js.Continue(null) |
| 1412 .withSourceInformation(node.sourceInformation)); |
| 1397 } | 1413 } |
| 1398 } | 1414 } |
| 1399 } | 1415 } |
| 1400 } | 1416 } |
| 1401 | 1417 |
| 1402 visitExitTry(HExitTry node) { | 1418 visitExitTry(HExitTry node) { |
| 1403 // An [HExitTry] is used to represent the control flow graph of a | 1419 // An [HExitTry] is used to represent the control flow graph of a |
| 1404 // try/catch block, ie the try body is always a predecessor | 1420 // try/catch block, ie the try body is always a predecessor |
| 1405 // of the catch and finally. Here, we continue visiting the try | 1421 // of the catch and finally. Here, we continue visiting the try |
| 1406 // body by visiting the block that contains the user-level control | 1422 // body by visiting the block that contains the user-level control |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1437 use(node.inputs[0]); | 1453 use(node.inputs[0]); |
| 1438 js.Expression test = pop(); | 1454 js.Expression test = pop(); |
| 1439 | 1455 |
| 1440 HStatementInformation thenGraph = info.thenGraph; | 1456 HStatementInformation thenGraph = info.thenGraph; |
| 1441 HStatementInformation elseGraph = info.elseGraph; | 1457 HStatementInformation elseGraph = info.elseGraph; |
| 1442 js.Statement thenPart = | 1458 js.Statement thenPart = |
| 1443 unwrapStatement(generateStatementsInNewBlock(thenGraph)); | 1459 unwrapStatement(generateStatementsInNewBlock(thenGraph)); |
| 1444 js.Statement elsePart = | 1460 js.Statement elsePart = |
| 1445 unwrapStatement(generateStatementsInNewBlock(elseGraph)); | 1461 unwrapStatement(generateStatementsInNewBlock(elseGraph)); |
| 1446 | 1462 |
| 1447 pushStatement(new js.If(test, thenPart, elsePart), node); | 1463 pushStatement(new js.If(test, thenPart, elsePart) |
| 1464 .withSourceInformation(node.sourceInformation)); |
| 1448 } | 1465 } |
| 1449 | 1466 |
| 1450 visitIf(HIf node) { | 1467 visitIf(HIf node) { |
| 1451 if (tryControlFlowOperation(node)) return; | 1468 if (tryControlFlowOperation(node)) return; |
| 1452 | 1469 |
| 1453 HInstruction condition = node.inputs[0]; | 1470 HInstruction condition = node.inputs[0]; |
| 1454 HIfBlockInformation info = node.blockInformation.body; | 1471 HIfBlockInformation info = node.blockInformation.body; |
| 1455 | 1472 |
| 1456 if (condition.isConstant()) { | 1473 if (condition.isConstant()) { |
| 1457 HConstant constant = condition; | 1474 HConstant constant = condition; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1492 push(js.js('# && #', [receiverExpression, constant])); | 1509 push(js.js('# && #', [receiverExpression, constant])); |
| 1493 } else { | 1510 } else { |
| 1494 assert(node.inputs.length == 1); | 1511 assert(node.inputs.length == 1); |
| 1495 registry.registerSpecializedGetInterceptor(node.interceptedClasses); | 1512 registry.registerSpecializedGetInterceptor(node.interceptedClasses); |
| 1496 js.Name name = | 1513 js.Name name = |
| 1497 backend.namer.nameForGetInterceptor(node.interceptedClasses); | 1514 backend.namer.nameForGetInterceptor(node.interceptedClasses); |
| 1498 var isolate = new js.VariableUse( | 1515 var isolate = new js.VariableUse( |
| 1499 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1516 backend.namer.globalObjectFor(backend.interceptorsLibrary)); |
| 1500 use(node.receiver); | 1517 use(node.receiver); |
| 1501 List<js.Expression> arguments = <js.Expression>[pop()]; | 1518 List<js.Expression> arguments = <js.Expression>[pop()]; |
| 1502 push(js.propertyCall(isolate, name, arguments), node); | 1519 push(js.propertyCall(isolate, name, arguments) |
| 1520 .withSourceInformation(node.sourceInformation)); |
| 1503 registry.registerUseInterceptor(); | 1521 registry.registerUseInterceptor(); |
| 1504 } | 1522 } |
| 1505 } | 1523 } |
| 1506 | 1524 |
| 1507 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 1525 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 1508 use(node.receiver); | 1526 use(node.receiver); |
| 1509 js.Expression object = pop(); | 1527 js.Expression object = pop(); |
| 1510 String methodName; | 1528 String methodName; |
| 1511 List<js.Expression> arguments = visitArguments(node.inputs); | 1529 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1512 Element target = node.element; | 1530 Element target = node.element; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1531 } | 1549 } |
| 1532 } | 1550 } |
| 1533 | 1551 |
| 1534 js.Name methodLiteral; | 1552 js.Name methodLiteral; |
| 1535 if (methodName == null) { | 1553 if (methodName == null) { |
| 1536 methodLiteral = backend.namer.invocationName(node.selector); | 1554 methodLiteral = backend.namer.invocationName(node.selector); |
| 1537 registerMethodInvoke(node); | 1555 registerMethodInvoke(node); |
| 1538 } else { | 1556 } else { |
| 1539 methodLiteral = backend.namer.asName(methodName); | 1557 methodLiteral = backend.namer.asName(methodName); |
| 1540 } | 1558 } |
| 1541 push(js.propertyCall(object, methodLiteral, arguments), node); | 1559 push(js.propertyCall(object, methodLiteral, arguments) |
| 1560 .withSourceInformation(node.sourceInformation)); |
| 1542 } | 1561 } |
| 1543 | 1562 |
| 1544 void visitInvokeConstructorBody(HInvokeConstructorBody node) { | 1563 void visitInvokeConstructorBody(HInvokeConstructorBody node) { |
| 1545 use(node.inputs[0]); | 1564 use(node.inputs[0]); |
| 1546 js.Expression object = pop(); | 1565 js.Expression object = pop(); |
| 1547 js.Name methodName = backend.namer.instanceMethodName(node.element); | 1566 js.Name methodName = backend.namer.instanceMethodName(node.element); |
| 1548 List<js.Expression> arguments = visitArguments(node.inputs); | 1567 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1549 push(js.propertyCall(object, methodName, arguments), node); | 1568 push(js.propertyCall(object, methodName, arguments) |
| 1569 .withSourceInformation(node.sourceInformation)); |
| 1550 registry.registerStaticUse(node.element); | 1570 registry.registerStaticUse(node.element); |
| 1551 } | 1571 } |
| 1552 | 1572 |
| 1553 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1573 void visitOneShotInterceptor(HOneShotInterceptor node) { |
| 1554 List<js.Expression> arguments = visitArguments(node.inputs); | 1574 List<js.Expression> arguments = visitArguments(node.inputs); |
| 1555 var isolate = new js.VariableUse( | 1575 var isolate = new js.VariableUse( |
| 1556 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1576 backend.namer.globalObjectFor(backend.interceptorsLibrary)); |
| 1557 Selector selector = node.selector; | 1577 Selector selector = node.selector; |
| 1558 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1578 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
| 1559 js.Name methodName = backend.registerOneShotInterceptor(selector); | 1579 js.Name methodName = backend.registerOneShotInterceptor(selector); |
| 1560 push(js.propertyCall(isolate, methodName, arguments), node); | 1580 push(js.propertyCall(isolate, methodName, arguments) |
| 1581 .withSourceInformation(node.sourceInformation)); |
| 1561 if (selector.isGetter) { | 1582 if (selector.isGetter) { |
| 1562 registerGetter(node); | 1583 registerGetter(node); |
| 1563 } else if (selector.isSetter) { | 1584 } else if (selector.isSetter) { |
| 1564 registerSetter(node); | 1585 registerSetter(node); |
| 1565 } else { | 1586 } else { |
| 1566 registerMethodInvoke(node); | 1587 registerMethodInvoke(node); |
| 1567 } | 1588 } |
| 1568 registry.registerUseInterceptor(); | 1589 registry.registerUseInterceptor(); |
| 1569 } | 1590 } |
| 1570 | 1591 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1615 void registerGetter(HInvokeDynamic node) { | 1636 void registerGetter(HInvokeDynamic node) { |
| 1616 Selector selector = node.selector; | 1637 Selector selector = node.selector; |
| 1617 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); | 1638 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); |
| 1618 registry.registerDynamicGetter( | 1639 registry.registerDynamicGetter( |
| 1619 new UniverseSelector(selector, mask)); | 1640 new UniverseSelector(selector, mask)); |
| 1620 } | 1641 } |
| 1621 | 1642 |
| 1622 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1643 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 1623 use(node.receiver); | 1644 use(node.receiver); |
| 1624 js.Name name = backend.namer.invocationName(node.selector); | 1645 js.Name name = backend.namer.invocationName(node.selector); |
| 1625 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1646 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
| 1647 .withSourceInformation(node.sourceInformation)); |
| 1626 registerSetter(node); | 1648 registerSetter(node); |
| 1627 } | 1649 } |
| 1628 | 1650 |
| 1629 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1651 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 1630 use(node.receiver); | 1652 use(node.receiver); |
| 1631 js.Name name = backend.namer.invocationName(node.selector); | 1653 js.Name name = backend.namer.invocationName(node.selector); |
| 1632 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1654 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
| 1655 .withSourceInformation(node.sourceInformation)); |
| 1633 registerGetter(node); | 1656 registerGetter(node); |
| 1634 } | 1657 } |
| 1635 | 1658 |
| 1636 visitInvokeClosure(HInvokeClosure node) { | 1659 visitInvokeClosure(HInvokeClosure node) { |
| 1637 Selector call = new Selector.callClosureFrom(node.selector); | 1660 Selector call = new Selector.callClosureFrom(node.selector); |
| 1638 use(node.receiver); | 1661 use(node.receiver); |
| 1639 push(js.propertyCall(pop(), | 1662 push(js.propertyCall(pop(), |
| 1640 backend.namer.invocationName(call), | 1663 backend.namer.invocationName(call), |
| 1641 visitArguments(node.inputs)), | 1664 visitArguments(node.inputs)) |
| 1642 node); | 1665 .withSourceInformation(node.sourceInformation)); |
| 1643 registry.registerDynamicInvocation( | 1666 registry.registerDynamicInvocation( |
| 1644 new UniverseSelector(call, null)); | 1667 new UniverseSelector(call, null)); |
| 1645 } | 1668 } |
| 1646 | 1669 |
| 1647 visitInvokeStatic(HInvokeStatic node) { | 1670 visitInvokeStatic(HInvokeStatic node) { |
| 1648 Element element = node.element; | 1671 Element element = node.element; |
| 1649 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1672 List<DartType> instantiatedTypes = node.instantiatedTypes; |
| 1650 | 1673 |
| 1651 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1674 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
| 1652 instantiatedTypes.forEach((type) { | 1675 instantiatedTypes.forEach((type) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1674 // more optimizations available to the loop. This form is 50% faster on | 1697 // more optimizations available to the loop. This form is 50% faster on |
| 1675 // some small loop, almost as fast as loops with no concurrent | 1698 // some small loop, almost as fast as loops with no concurrent |
| 1676 // modification check. | 1699 // modification check. |
| 1677 push(js.js('# || (0, #)(#)',[ | 1700 push(js.js('# || (0, #)(#)',[ |
| 1678 arguments[0], | 1701 arguments[0], |
| 1679 backend.emitter.staticFunctionAccess(throwFunction), | 1702 backend.emitter.staticFunctionAccess(throwFunction), |
| 1680 arguments[1]])); | 1703 arguments[1]])); |
| 1681 } else { | 1704 } else { |
| 1682 registry.registerStaticInvocation(element); | 1705 registry.registerStaticInvocation(element); |
| 1683 push(backend.emitter.staticFunctionAccess(element)); | 1706 push(backend.emitter.staticFunctionAccess(element)); |
| 1684 push(new js.Call(pop(), arguments), node); | 1707 push(new js.Call(pop(), arguments, |
| 1708 sourceInformation: node.sourceInformation)); |
| 1685 } | 1709 } |
| 1686 | 1710 |
| 1687 } | 1711 } |
| 1688 | 1712 |
| 1689 visitInvokeSuper(HInvokeSuper node) { | 1713 visitInvokeSuper(HInvokeSuper node) { |
| 1690 Element superMethod = node.element; | 1714 Element superMethod = node.element; |
| 1691 registry.registerSuperInvocation(superMethod); | 1715 registry.registerSuperInvocation(superMethod); |
| 1692 ClassElement superClass = superMethod.enclosingClass; | 1716 ClassElement superClass = superMethod.enclosingClass; |
| 1693 if (superMethod.kind == ElementKind.FIELD) { | 1717 if (superMethod.kind == ElementKind.FIELD) { |
| 1694 js.Name fieldName = | 1718 js.Name fieldName = |
| 1695 backend.namer.instanceFieldPropertyName(superMethod); | 1719 backend.namer.instanceFieldPropertyName(superMethod); |
| 1696 use(node.inputs[0]); | 1720 use(node.inputs[0]); |
| 1697 js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName); | 1721 js.PropertyAccess access = |
| 1722 new js.PropertyAccess(pop(), fieldName) |
| 1723 .withSourceInformation(node.sourceInformation); |
| 1698 if (node.isSetter) { | 1724 if (node.isSetter) { |
| 1699 use(node.value); | 1725 use(node.value); |
| 1700 push(new js.Assignment(access, pop()), node); | 1726 push(new js.Assignment(access, pop()) |
| 1727 .withSourceInformation(node.sourceInformation)); |
| 1701 } else { | 1728 } else { |
| 1702 push(access, node); | 1729 push(access); |
| 1703 } | 1730 } |
| 1704 } else { | 1731 } else { |
| 1705 Selector selector = node.selector; | 1732 Selector selector = node.selector; |
| 1706 | 1733 |
| 1707 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { | 1734 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { |
| 1708 js.Name methodName; | 1735 js.Name methodName; |
| 1709 if (selector.isGetter) { | 1736 if (selector.isGetter) { |
| 1710 // If the selector we need to register a typed getter to the | 1737 // If the selector we need to register a typed getter to the |
| 1711 // [world]. The emitter needs to know if it needs to emit a | 1738 // [world]. The emitter needs to know if it needs to emit a |
| 1712 // bound closure for a method. | 1739 // bound closure for a method. |
| 1713 TypeMask receiverType = | 1740 TypeMask receiverType = |
| 1714 new TypeMask.nonNullExact(superClass, compiler.world); | 1741 new TypeMask.nonNullExact(superClass, compiler.world); |
| 1715 // TODO(floitsch): we know the target. We shouldn't register a | 1742 // TODO(floitsch): we know the target. We shouldn't register a |
| 1716 // dynamic getter. | 1743 // dynamic getter. |
| 1717 registry.registerDynamicGetter( | 1744 registry.registerDynamicGetter( |
| 1718 new UniverseSelector(selector, receiverType)); | 1745 new UniverseSelector(selector, receiverType)); |
| 1719 registry.registerGetterForSuperMethod(node.element); | 1746 registry.registerGetterForSuperMethod(node.element); |
| 1720 methodName = backend.namer.invocationName(selector); | 1747 methodName = backend.namer.invocationName(selector); |
| 1721 } else { | 1748 } else { |
| 1722 assert(invariant(node, compiler.hasIncrementalSupport)); | 1749 assert(invariant(node, compiler.hasIncrementalSupport)); |
| 1723 methodName = backend.namer.instanceMethodName(superMethod); | 1750 methodName = backend.namer.instanceMethodName(superMethod); |
| 1724 } | 1751 } |
| 1725 push(js.js('#.#.call(#)', | 1752 push(js.js('#.#.call(#)', |
| 1726 [backend.emitter.prototypeAccess(superClass, | 1753 [backend.emitter.prototypeAccess(superClass, |
| 1727 hasBeenInstantiated: true), | 1754 hasBeenInstantiated: true), |
| 1728 methodName, visitArguments(node.inputs, start: 0)]), | 1755 methodName, visitArguments(node.inputs, start: 0)]) |
| 1729 node); | 1756 .withSourceInformation(node.sourceInformation)); |
| 1730 } else { | 1757 } else { |
| 1731 use(node.receiver); | 1758 use(node.receiver); |
| 1732 push( | 1759 push( |
| 1733 js.js('#.#(#)', [ | 1760 js.js('#.#(#)', [ |
| 1734 pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod), | 1761 pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod), |
| 1735 visitArguments(node.inputs, start: 1)]), // Skip receiver argument. | 1762 visitArguments(node.inputs, start: 1)]) // Skip receiver argument. |
| 1736 node); | 1763 .withSourceInformation(node.sourceInformation)); |
| 1737 } | 1764 } |
| 1738 } | 1765 } |
| 1739 } | 1766 } |
| 1740 | 1767 |
| 1741 visitFieldGet(HFieldGet node) { | 1768 visitFieldGet(HFieldGet node) { |
| 1742 use(node.receiver); | 1769 use(node.receiver); |
| 1743 Element element = node.element; | 1770 Element element = node.element; |
| 1744 if (node.isNullCheck) { | 1771 if (node.isNullCheck) { |
| 1745 // We access a JavaScript member we know all objects besides | 1772 // We access a JavaScript member we know all objects besides |
| 1746 // null and undefined have: V8 does not like accessing a member | 1773 // null and undefined have: V8 does not like accessing a member |
| 1747 // that does not exist. | 1774 // that does not exist. |
| 1748 push(new js.PropertyAccess.field(pop(), 'toString'), node); | 1775 push(new js.PropertyAccess.field(pop(), 'toString') |
| 1776 .withSourceInformation(node.sourceInformation)); |
| 1749 } else if (element == backend.jsIndexableLength) { | 1777 } else if (element == backend.jsIndexableLength) { |
| 1750 // We're accessing a native JavaScript property called 'length' | 1778 // We're accessing a native JavaScript property called 'length' |
| 1751 // on a JS String or a JS array. Therefore, the name of that | 1779 // on a JS String or a JS array. Therefore, the name of that |
| 1752 // property should not be mangled. | 1780 // property should not be mangled. |
| 1753 push(new js.PropertyAccess.field(pop(), 'length'), node); | 1781 push(new js.PropertyAccess.field(pop(), 'length') |
| 1782 .withSourceInformation(node.sourceInformation)); |
| 1754 } else { | 1783 } else { |
| 1755 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1784 js.Name name = backend.namer.instanceFieldPropertyName(element); |
| 1756 push(new js.PropertyAccess(pop(), name), node); | 1785 push(new js.PropertyAccess(pop(), name) |
| 1786 .withSourceInformation(node.sourceInformation)); |
| 1757 registry.registerFieldGetter(element); | 1787 registry.registerFieldGetter(element); |
| 1758 } | 1788 } |
| 1759 } | 1789 } |
| 1760 | 1790 |
| 1761 visitFieldSet(HFieldSet node) { | 1791 visitFieldSet(HFieldSet node) { |
| 1762 Element element = node.element; | 1792 Element element = node.element; |
| 1763 registry.registerFieldSetter(element); | 1793 registry.registerFieldSetter(element); |
| 1764 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1794 js.Name name = backend.namer.instanceFieldPropertyName(element); |
| 1765 use(node.receiver); | 1795 use(node.receiver); |
| 1766 js.Expression receiver = pop(); | 1796 js.Expression receiver = pop(); |
| 1767 use(node.value); | 1797 use(node.value); |
| 1768 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()), | 1798 push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()) |
| 1769 node); | 1799 .withSourceInformation(node.sourceInformation)); |
| 1770 } | 1800 } |
| 1771 | 1801 |
| 1772 visitReadModifyWrite(HReadModifyWrite node) { | 1802 visitReadModifyWrite(HReadModifyWrite node) { |
| 1773 Element element = node.element; | 1803 Element element = node.element; |
| 1774 registry.registerFieldSetter(element); | 1804 registry.registerFieldSetter(element); |
| 1775 js.Name name = backend.namer.instanceFieldPropertyName(element); | 1805 js.Name name = backend.namer.instanceFieldPropertyName(element); |
| 1776 use(node.receiver); | 1806 use(node.receiver); |
| 1777 js.Expression fieldReference = new js.PropertyAccess(pop(), name); | 1807 js.Expression fieldReference = new js.PropertyAccess(pop(), name); |
| 1778 if (node.isPreOp) { | 1808 if (node.isPreOp) { |
| 1779 push(new js.Prefix(node.jsOp, fieldReference), node); | 1809 push(new js.Prefix(node.jsOp, fieldReference) |
| 1810 .withSourceInformation(node.sourceInformation)); |
| 1780 } else if (node.isPostOp) { | 1811 } else if (node.isPostOp) { |
| 1781 push(new js.Postfix(node.jsOp, fieldReference), node); | 1812 push(new js.Postfix(node.jsOp, fieldReference) |
| 1813 .withSourceInformation(node.sourceInformation)); |
| 1782 } else { | 1814 } else { |
| 1783 use(node.value); | 1815 use(node.value); |
| 1784 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()), node); | 1816 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()) |
| 1817 .withSourceInformation(node.sourceInformation)); |
| 1785 } | 1818 } |
| 1786 } | 1819 } |
| 1787 | 1820 |
| 1788 visitLocalGet(HLocalGet node) { | 1821 visitLocalGet(HLocalGet node) { |
| 1789 use(node.receiver); | 1822 use(node.receiver); |
| 1790 } | 1823 } |
| 1791 | 1824 |
| 1792 visitLocalSet(HLocalSet node) { | 1825 visitLocalSet(HLocalSet node) { |
| 1793 use(node.value); | 1826 use(node.value); |
| 1794 assignVariable(variableNames.getName(node.receiver), pop()); | 1827 assignVariable(variableNames.getName(node.receiver), |
| 1828 pop(), |
| 1829 node.sourceInformation); |
| 1795 } | 1830 } |
| 1796 | 1831 |
| 1797 void registerForeignTypes(HForeign node) { | 1832 void registerForeignTypes(HForeign node) { |
| 1798 native.NativeBehavior nativeBehavior = node.nativeBehavior; | 1833 native.NativeBehavior nativeBehavior = node.nativeBehavior; |
| 1799 if (nativeBehavior == null) return; | 1834 if (nativeBehavior == null) return; |
| 1800 nativeBehavior.typesReturned.forEach((type) { | 1835 nativeBehavior.typesReturned.forEach((type) { |
| 1801 if (type is InterfaceType) { | 1836 if (type is InterfaceType) { |
| 1802 registry.registerInstantiatedType(type); | 1837 registry.registerInstantiatedType(type); |
| 1803 } | 1838 } |
| 1804 }); | 1839 }); |
| 1805 } | 1840 } |
| 1806 | 1841 |
| 1807 visitForeignCode(HForeignCode node) { | 1842 visitForeignCode(HForeignCode node) { |
| 1808 List<HInstruction> inputs = node.inputs; | 1843 List<HInstruction> inputs = node.inputs; |
| 1809 if (node.isJsStatement()) { | 1844 if (node.isJsStatement()) { |
| 1810 List<js.Expression> interpolatedExpressions = <js.Expression>[]; | 1845 List<js.Expression> interpolatedExpressions = <js.Expression>[]; |
| 1811 for (int i = 0; i < inputs.length; i++) { | 1846 for (int i = 0; i < inputs.length; i++) { |
| 1812 use(inputs[i]); | 1847 use(inputs[i]); |
| 1813 interpolatedExpressions.add(pop()); | 1848 interpolatedExpressions.add(pop()); |
| 1814 } | 1849 } |
| 1815 pushStatement(node.codeTemplate.instantiate(interpolatedExpressions)); | 1850 pushStatement(node.codeTemplate.instantiate(interpolatedExpressions) |
| 1851 .withSourceInformation(node.sourceInformation)); |
| 1816 } else { | 1852 } else { |
| 1817 List<js.Expression> interpolatedExpressions = <js.Expression>[]; | 1853 List<js.Expression> interpolatedExpressions = <js.Expression>[]; |
| 1818 for (int i = 0; i < inputs.length; i++) { | 1854 for (int i = 0; i < inputs.length; i++) { |
| 1819 use(inputs[i]); | 1855 use(inputs[i]); |
| 1820 interpolatedExpressions.add(pop()); | 1856 interpolatedExpressions.add(pop()); |
| 1821 } | 1857 } |
| 1822 push(node.codeTemplate.instantiate(interpolatedExpressions)); | 1858 push(node.codeTemplate.instantiate(interpolatedExpressions) |
| 1859 .withSourceInformation(node.sourceInformation)); |
| 1823 } | 1860 } |
| 1824 | 1861 |
| 1825 // TODO(sra): Tell world.nativeEnqueuer about the types created here. | 1862 // TODO(sra): Tell world.nativeEnqueuer about the types created here. |
| 1826 registerForeignTypes(node); | 1863 registerForeignTypes(node); |
| 1827 } | 1864 } |
| 1828 | 1865 |
| 1829 visitForeignNew(HForeignNew node) { | 1866 visitForeignNew(HForeignNew node) { |
| 1830 js.Expression jsClassReference = | 1867 js.Expression jsClassReference = |
| 1831 backend.emitter.constructorAccess(node.element); | 1868 backend.emitter.constructorAccess(node.element); |
| 1832 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); | 1869 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); |
| 1833 push(new js.New(jsClassReference, arguments), node); | 1870 push(new js.New(jsClassReference, arguments) |
| 1871 .withSourceInformation(node.sourceInformation)); |
| 1834 registerForeignTypes(node); | 1872 registerForeignTypes(node); |
| 1835 // We also use ForeignNew to instantiate closure classes that belong to | 1873 // We also use ForeignNew to instantiate closure classes that belong to |
| 1836 // function expressions. We have to register their use here, as otherwise | 1874 // function expressions. We have to register their use here, as otherwise |
| 1837 // code for them might not be emitted. | 1875 // code for them might not be emitted. |
| 1838 if (node.element.isClosure) { | 1876 if (node.element.isClosure) { |
| 1839 registry.registerInstantiatedClass(node.element); | 1877 registry.registerInstantiatedClass(node.element); |
| 1840 } | 1878 } |
| 1841 if (node.instantiatedTypes == null) { | 1879 if (node.instantiatedTypes == null) { |
| 1842 return; | 1880 return; |
| 1843 } | 1881 } |
| 1844 node.instantiatedTypes.forEach((type) { | 1882 node.instantiatedTypes.forEach((type) { |
| 1845 registry.registerInstantiatedType(type); | 1883 registry.registerInstantiatedType(type); |
| 1846 }); | 1884 }); |
| 1847 } | 1885 } |
| 1848 | 1886 |
| 1849 js.Expression newLiteralBool(bool value) { | 1887 js.Expression newLiteralBool(bool value, |
| 1888 SourceInformation sourceInformation) { |
| 1850 if (compiler.enableMinification) { | 1889 if (compiler.enableMinification) { |
| 1851 // Use !0 for true, !1 for false. | 1890 // Use !0 for true, !1 for false. |
| 1852 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")); | 1891 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")) |
| 1892 .withSourceInformation(sourceInformation); |
| 1853 } else { | 1893 } else { |
| 1854 return new js.LiteralBool(value); | 1894 return new js.LiteralBool(value) |
| 1895 .withSourceInformation(sourceInformation); |
| 1855 } | 1896 } |
| 1856 } | 1897 } |
| 1857 | 1898 |
| 1858 void generateConstant(ConstantValue constant) { | 1899 void generateConstant(ConstantValue constant, |
| 1900 SourceInformation sourceInformation) { |
| 1859 if (constant.isFunction) { | 1901 if (constant.isFunction) { |
| 1860 FunctionConstantValue function = constant; | 1902 FunctionConstantValue function = constant; |
| 1861 registry.registerStaticUse(function.element); | 1903 registry.registerStaticUse(function.element); |
| 1862 } | 1904 } |
| 1863 if (constant.isType) { | 1905 if (constant.isType) { |
| 1864 // If the type is a web component, we need to ensure the constructors are | 1906 // If the type is a web component, we need to ensure the constructors are |
| 1865 // available to 'upgrade' the native object. | 1907 // available to 'upgrade' the native object. |
| 1866 TypeConstantValue type = constant; | 1908 TypeConstantValue type = constant; |
| 1867 Element element = type.representedType.element; | 1909 Element element = type.representedType.element; |
| 1868 if (element != null && element.isClass) { | 1910 if (element != null && element.isClass) { |
| 1869 registry.registerTypeConstant(element); | 1911 registry.registerTypeConstant(element); |
| 1870 } | 1912 } |
| 1871 } | 1913 } |
| 1872 push(backend.emitter.constantReference(constant)); | 1914 push(backend.emitter.constantReference(constant) |
| 1915 .withSourceInformation(sourceInformation)); |
| 1873 } | 1916 } |
| 1874 | 1917 |
| 1875 visitConstant(HConstant node) { | 1918 visitConstant(HConstant node) { |
| 1876 assert(isGenerateAtUseSite(node)); | 1919 assert(isGenerateAtUseSite(node)); |
| 1877 generateConstant(node.constant); | 1920 generateConstant(node.constant, node.sourceInformation); |
| 1878 | 1921 |
| 1879 registry.registerCompileTimeConstant(node.constant); | 1922 registry.registerCompileTimeConstant(node.constant); |
| 1880 backend.constants.addCompileTimeConstantForEmission(node.constant); | 1923 backend.constants.addCompileTimeConstantForEmission(node.constant); |
| 1881 } | 1924 } |
| 1882 | 1925 |
| 1883 visitNot(HNot node) { | 1926 visitNot(HNot node) { |
| 1884 assert(node.inputs.length == 1); | 1927 assert(node.inputs.length == 1); |
| 1885 generateNot(node.inputs[0]); | 1928 generateNot(node.inputs[0], node.sourceInformation); |
| 1886 attachLocationToLast(node); | |
| 1887 } | 1929 } |
| 1888 | 1930 |
| 1889 static String mapRelationalOperator(String op, bool inverse) { | 1931 static String mapRelationalOperator(String op, bool inverse) { |
| 1890 Map<String, String> inverseOperator = const <String, String>{ | 1932 Map<String, String> inverseOperator = const <String, String>{ |
| 1891 "==" : "!=", | 1933 "==" : "!=", |
| 1892 "!=" : "==", | 1934 "!=" : "==", |
| 1893 "===": "!==", | 1935 "===": "!==", |
| 1894 "!==": "===", | 1936 "!==": "===", |
| 1895 "<" : ">=", | 1937 "<" : ">=", |
| 1896 "<=" : ">", | 1938 "<=" : ">", |
| 1897 ">" : "<=", | 1939 ">" : "<=", |
| 1898 ">=" : "<" | 1940 ">=" : "<" |
| 1899 }; | 1941 }; |
| 1900 return inverse ? inverseOperator[op] : op; | 1942 return inverse ? inverseOperator[op] : op; |
| 1901 } | 1943 } |
| 1902 | 1944 |
| 1903 void generateNot(HInstruction input) { | 1945 void generateNot(HInstruction input, SourceInformation sourceInformation) { |
| 1904 bool canGenerateOptimizedComparison(HInstruction instruction) { | 1946 bool canGenerateOptimizedComparison(HInstruction instruction) { |
| 1905 if (instruction is !HRelational) return false; | 1947 if (instruction is !HRelational) return false; |
| 1906 | 1948 |
| 1907 HRelational relational = instruction; | 1949 HRelational relational = instruction; |
| 1908 | 1950 |
| 1909 HInstruction left = relational.left; | 1951 HInstruction left = relational.left; |
| 1910 HInstruction right = relational.right; | 1952 HInstruction right = relational.right; |
| 1911 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) { | 1953 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) { |
| 1912 return true; | 1954 return true; |
| 1913 } | 1955 } |
| 1914 | 1956 |
| 1915 // This optimization doesn't work for NaN, so we only do it if the | 1957 // This optimization doesn't work for NaN, so we only do it if the |
| 1916 // type is known to be an integer. | 1958 // type is known to be an integer. |
| 1917 return left.isInteger(compiler) && right.isInteger(compiler); | 1959 return left.isInteger(compiler) && right.isInteger(compiler); |
| 1918 } | 1960 } |
| 1919 | 1961 |
| 1920 bool handledBySpecialCase = false; | 1962 bool handledBySpecialCase = false; |
| 1921 if (isGenerateAtUseSite(input)) { | 1963 if (isGenerateAtUseSite(input)) { |
| 1922 handledBySpecialCase = true; | 1964 handledBySpecialCase = true; |
| 1923 if (input is HIs) { | 1965 if (input is HIs) { |
| 1924 emitIs(input, '!=='); | 1966 emitIs(input, '!==', sourceInformation); |
| 1925 } else if (input is HIsViaInterceptor) { | 1967 } else if (input is HIsViaInterceptor) { |
| 1926 emitIsViaInterceptor(input, true); | 1968 emitIsViaInterceptor(input, sourceInformation, negative: true); |
| 1927 } else if (input is HNot) { | 1969 } else if (input is HNot) { |
| 1928 use(input.inputs[0]); | 1970 use(input.inputs[0]); |
| 1929 } else if (input is HIdentity) { | 1971 } else if (input is HIdentity) { |
| 1930 emitIdentityComparison(input, true); | 1972 emitIdentityComparison(input, sourceInformation, inverse: true); |
| 1931 } else if (input is HBoolify) { | 1973 } else if (input is HBoolify) { |
| 1932 use(input.inputs[0]); | 1974 use(input.inputs[0]); |
| 1933 push(new js.Binary("!==", pop(), newLiteralBool(true)), input); | 1975 push(new js.Binary("!==", pop(), |
| 1976 newLiteralBool(true, input.sourceInformation)) |
| 1977 .withSourceInformation(sourceInformation)); |
| 1934 } else if (canGenerateOptimizedComparison(input)) { | 1978 } else if (canGenerateOptimizedComparison(input)) { |
| 1935 HRelational relational = input; | 1979 HRelational relational = input; |
| 1936 BinaryOperation operation = | 1980 BinaryOperation operation = |
| 1937 relational.operation(backend.constantSystem); | 1981 relational.operation(backend.constantSystem); |
| 1938 String op = mapRelationalOperator(operation.name, true); | 1982 String op = mapRelationalOperator(operation.name, true); |
| 1939 visitRelational(input, op); | 1983 handleInvokeBinary(input, op, sourceInformation); |
| 1940 } else { | 1984 } else { |
| 1941 handledBySpecialCase = false; | 1985 handledBySpecialCase = false; |
| 1942 } | 1986 } |
| 1943 } | 1987 } |
| 1944 if (!handledBySpecialCase) { | 1988 if (!handledBySpecialCase) { |
| 1945 use(input); | 1989 use(input); |
| 1946 push(new js.Prefix("!", pop())); | 1990 push(new js.Prefix("!", pop()).withSourceInformation(sourceInformation)); |
| 1947 } | 1991 } |
| 1948 } | 1992 } |
| 1949 | 1993 |
| 1950 visitParameterValue(HParameterValue node) { | 1994 visitParameterValue(HParameterValue node) { |
| 1951 assert(!isGenerateAtUseSite(node)); | 1995 assert(!isGenerateAtUseSite(node)); |
| 1952 String name = variableNames.getName(node); | 1996 String name = variableNames.getName(node); |
| 1953 parameters.add(new js.Parameter(name)); | 1997 parameters.add(new js.Parameter(name)); |
| 1954 declaredLocals.add(name); | 1998 declaredLocals.add(name); |
| 1955 } | 1999 } |
| 1956 | 2000 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1967 HBasicBlock ifBlock = node.block.dominator; | 2011 HBasicBlock ifBlock = node.block.dominator; |
| 1968 assert(controlFlowOperators.contains(ifBlock.last)); | 2012 assert(controlFlowOperators.contains(ifBlock.last)); |
| 1969 HInstruction input = ifBlock.last.inputs[0]; | 2013 HInstruction input = ifBlock.last.inputs[0]; |
| 1970 if (input.isConstantFalse()) { | 2014 if (input.isConstantFalse()) { |
| 1971 use(node.inputs[1]); | 2015 use(node.inputs[1]); |
| 1972 } else if (input.isConstantTrue()) { | 2016 } else if (input.isConstantTrue()) { |
| 1973 use(node.inputs[0]); | 2017 use(node.inputs[0]); |
| 1974 } else if (node.inputs[1].isConstantBoolean()) { | 2018 } else if (node.inputs[1].isConstantBoolean()) { |
| 1975 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; | 2019 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; |
| 1976 if (operation == '||') { | 2020 if (operation == '||') { |
| 1977 generateNot(input); | 2021 generateNot(input, input.sourceInformation); |
| 1978 } else { | 2022 } else { |
| 1979 use(input); | 2023 use(input); |
| 1980 } | 2024 } |
| 1981 js.Expression left = pop(); | 2025 js.Expression left = pop(); |
| 1982 use(node.inputs[0]); | 2026 use(node.inputs[0]); |
| 1983 push(new js.Binary(operation, left, pop())); | 2027 push(new js.Binary(operation, left, pop())); |
| 1984 } else { | 2028 } else { |
| 1985 use(input); | 2029 use(input); |
| 1986 js.Expression test = pop(); | 2030 js.Expression test = pop(); |
| 1987 use(node.inputs[0]); | 2031 use(node.inputs[0]); |
| 1988 js.Expression then = pop(); | 2032 js.Expression then = pop(); |
| 1989 use(node.inputs[1]); | 2033 use(node.inputs[1]); |
| 1990 push(new js.Conditional(test, then, pop())); | 2034 push(new js.Conditional(test, then, pop())); |
| 1991 } | 2035 } |
| 1992 } | 2036 } |
| 1993 | 2037 |
| 1994 visitReturn(HReturn node) { | 2038 visitReturn(HReturn node) { |
| 1995 assert(node.inputs.length == 1); | 2039 assert(node.inputs.length == 1); |
| 1996 HInstruction input = node.inputs[0]; | 2040 HInstruction input = node.inputs[0]; |
| 1997 if (input.isConstantNull()) { | 2041 if (input.isConstantNull()) { |
| 1998 pushStatement(new js.Return(null), node); | 2042 pushStatement(new js.Return() |
| 2043 .withSourceInformation(node.sourceInformation)); |
| 1999 } else { | 2044 } else { |
| 2000 use(node.inputs[0]); | 2045 use(node.inputs[0]); |
| 2001 pushStatement(new js.Return(pop()), node); | 2046 pushStatement(new js.Return(pop()) |
| 2047 .withSourceInformation(node.sourceInformation)); |
| 2002 } | 2048 } |
| 2003 } | 2049 } |
| 2004 | 2050 |
| 2005 visitThis(HThis node) { | 2051 visitThis(HThis node) { |
| 2006 push(new js.This()); | 2052 push(new js.This()); |
| 2007 } | 2053 } |
| 2008 | 2054 |
| 2009 visitThrow(HThrow node) { | 2055 visitThrow(HThrow node) { |
| 2010 if (node.isRethrow) { | 2056 if (node.isRethrow) { |
| 2011 use(node.inputs[0]); | 2057 use(node.inputs[0]); |
| 2012 pushStatement(new js.Throw(pop()), node); | 2058 pushStatement(new js.Throw(pop()) |
| 2059 .withSourceInformation(node.sourceInformation)); |
| 2013 } else { | 2060 } else { |
| 2014 generateThrowWithHelper('wrapException', node.inputs[0]); | 2061 generateThrowWithHelper('wrapException', node.inputs[0], |
| 2062 sourceInformation: node.sourceInformation); |
| 2015 } | 2063 } |
| 2016 } | 2064 } |
| 2017 | 2065 |
| 2018 visitAwait(HAwait node) { | 2066 visitAwait(HAwait node) { |
| 2019 use(node.inputs[0]); | 2067 use(node.inputs[0]); |
| 2020 push(new js.Await(pop()), node); | 2068 push(new js.Await(pop()) |
| 2069 .withSourceInformation(node.sourceInformation)); |
| 2021 } | 2070 } |
| 2022 | 2071 |
| 2023 visitYield(HYield node) { | 2072 visitYield(HYield node) { |
| 2024 use(node.inputs[0]); | 2073 use(node.inputs[0]); |
| 2025 pushStatement(new js.DartYield(pop(), node.hasStar), node); | 2074 pushStatement(new js.DartYield(pop(), node.hasStar) |
| 2075 .withSourceInformation(node.sourceInformation)); |
| 2026 } | 2076 } |
| 2027 | 2077 |
| 2028 visitRangeConversion(HRangeConversion node) { | 2078 visitRangeConversion(HRangeConversion node) { |
| 2029 // Range conversion instructions are removed by the value range | 2079 // Range conversion instructions are removed by the value range |
| 2030 // analyzer. | 2080 // analyzer. |
| 2031 assert(false); | 2081 assert(false); |
| 2032 } | 2082 } |
| 2033 | 2083 |
| 2034 visitBoundsCheck(HBoundsCheck node) { | 2084 visitBoundsCheck(HBoundsCheck node) { |
| 2035 // TODO(ngeoffray): Separate the two checks of the bounds check, so, | 2085 // TODO(ngeoffray): Separate the two checks of the bounds check, so, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2065 ? over | 2115 ? over |
| 2066 : over == null | 2116 : over == null |
| 2067 ? under | 2117 ? under |
| 2068 : new js.Binary("||", under, over); | 2118 : new js.Binary("||", under, over); |
| 2069 js.Statement thenBody = new js.Block.empty(); | 2119 js.Statement thenBody = new js.Block.empty(); |
| 2070 js.Block oldContainer = currentContainer; | 2120 js.Block oldContainer = currentContainer; |
| 2071 currentContainer = thenBody; | 2121 currentContainer = thenBody; |
| 2072 generateThrowWithHelper('ioore', [node.array, node.index]); | 2122 generateThrowWithHelper('ioore', [node.array, node.index]); |
| 2073 currentContainer = oldContainer; | 2123 currentContainer = oldContainer; |
| 2074 thenBody = unwrapStatement(thenBody); | 2124 thenBody = unwrapStatement(thenBody); |
| 2075 pushStatement(new js.If.noElse(underOver, thenBody), node); | 2125 pushStatement(new js.If.noElse(underOver, thenBody) |
| 2126 .withSourceInformation(node.sourceInformation)); |
| 2076 } else { | 2127 } else { |
| 2077 generateThrowWithHelper('ioore', [node.array, node.index]); | 2128 generateThrowWithHelper('ioore', [node.array, node.index]); |
| 2078 } | 2129 } |
| 2079 } | 2130 } |
| 2080 | 2131 |
| 2081 void generateThrowWithHelper(String helperName, argument) { | 2132 void generateThrowWithHelper(String helperName, argument, |
| 2133 {SourceInformation sourceInformation}) { |
| 2082 Element helper = backend.findHelper(helperName); | 2134 Element helper = backend.findHelper(helperName); |
| 2083 registry.registerStaticUse(helper); | 2135 registry.registerStaticUse(helper); |
| 2084 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2136 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
| 2085 List arguments = []; | 2137 List arguments = []; |
| 2086 var location; | 2138 var location; |
| 2087 if (argument is List) { | 2139 if (argument is List) { |
| 2088 location = argument[0]; | 2140 location = argument[0]; |
| 2089 argument.forEach((instruction) { | 2141 argument.forEach((instruction) { |
| 2090 use(instruction); | 2142 use(instruction); |
| 2091 arguments.add(pop()); | 2143 arguments.add(pop()); |
| 2092 }); | 2144 }); |
| 2093 } else { | 2145 } else { |
| 2094 location = argument; | 2146 location = argument; |
| 2095 use(argument); | 2147 use(argument); |
| 2096 arguments.add(pop()); | 2148 arguments.add(pop()); |
| 2097 } | 2149 } |
| 2098 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false)); | 2150 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
| 2099 value = attachLocation(value, location); | 2151 sourceInformation: sourceInformation); |
| 2100 // BUG(4906): Using throw/return here adds to the size of the generated code | 2152 // BUG(4906): Using throw/return here adds to the size of the generated code |
| 2101 // but it has the advantage of explicitly telling the JS engine that | 2153 // but it has the advantage of explicitly telling the JS engine that |
| 2102 // this code path will terminate abruptly. Needs more work. | 2154 // this code path will terminate abruptly. Needs more work. |
| 2103 if (helperName == 'wrapException') { | 2155 if (helperName == 'wrapException') { |
| 2104 pushStatement(new js.Throw(value)); | 2156 pushStatement(new js.Throw(value) |
| 2157 .withSourceInformation(sourceInformation)); |
| 2105 } else { | 2158 } else { |
| 2106 Element element = work.element; | 2159 Element element = work.element; |
| 2107 if (element is FunctionElement && element.asyncMarker.isYielding) { | 2160 if (element is FunctionElement && element.asyncMarker.isYielding) { |
| 2108 // `return <expr>;` is illegal in a sync* or async* function. | 2161 // `return <expr>;` is illegal in a sync* or async* function. |
| 2109 // To have the the async-translator working, we avoid introducing | 2162 // To have the the async-translator working, we avoid introducing |
| 2110 // `return` nodes. | 2163 // `return` nodes. |
| 2111 pushStatement(new js.ExpressionStatement(value)); | 2164 pushStatement(new js.ExpressionStatement(value) |
| 2165 .withSourceInformation(sourceInformation)); |
| 2112 } else { | 2166 } else { |
| 2113 pushStatement(new js.Return(value)); | 2167 pushStatement(new js.Return(value) |
| 2168 .withSourceInformation(sourceInformation)); |
| 2114 } | 2169 } |
| 2115 } | 2170 } |
| 2116 } | 2171 } |
| 2117 | 2172 |
| 2118 visitThrowExpression(HThrowExpression node) { | 2173 visitThrowExpression(HThrowExpression node) { |
| 2119 HInstruction argument = node.inputs[0]; | 2174 HInstruction argument = node.inputs[0]; |
| 2120 use(argument); | 2175 use(argument); |
| 2121 | 2176 |
| 2122 Element helper = backend.findHelper("throwExpression"); | 2177 Element helper = backend.findHelper("throwExpression"); |
| 2123 registry.registerStaticUse(helper); | 2178 registry.registerStaticUse(helper); |
| 2124 | 2179 |
| 2125 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2180 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
| 2126 js.Call value = new js.Call(jsHelper, [pop()]); | 2181 js.Call value = new js.Call(jsHelper, [pop()]) |
| 2127 value = attachLocation(value, argument); | 2182 .withSourceInformation(node.sourceInformation); |
| 2128 push(value, node); | 2183 push(value); |
| 2129 } | 2184 } |
| 2130 | 2185 |
| 2131 void visitSwitch(HSwitch node) { | 2186 void visitSwitch(HSwitch node) { |
| 2132 // Switches are handled using [visitSwitchInfo]. | 2187 // Switches are handled using [visitSwitchInfo]. |
| 2133 } | 2188 } |
| 2134 | 2189 |
| 2135 void visitStatic(HStatic node) { | 2190 void visitStatic(HStatic node) { |
| 2136 Element element = node.element; | 2191 Element element = node.element; |
| 2137 assert(element.isFunction || element.isField); | 2192 assert(element.isFunction || element.isField); |
| 2138 if (element.isFunction) { | 2193 if (element.isFunction) { |
| 2139 push(backend.emitter.isolateStaticClosureAccess(element)); | 2194 push(backend.emitter.isolateStaticClosureAccess(element) |
| 2195 .withSourceInformation(node.sourceInformation)); |
| 2140 registry.registerGetOfStaticFunction(element); | 2196 registry.registerGetOfStaticFunction(element); |
| 2141 } else { | 2197 } else { |
| 2142 push(backend.emitter.staticFieldAccess(element)); | 2198 push(backend.emitter.staticFieldAccess(element) |
| 2199 .withSourceInformation(node.sourceInformation)); |
| 2143 } | 2200 } |
| 2144 registry.registerStaticUse(element); | 2201 registry.registerStaticUse(element); |
| 2145 } | 2202 } |
| 2146 | 2203 |
| 2147 void visitLazyStatic(HLazyStatic node) { | 2204 void visitLazyStatic(HLazyStatic node) { |
| 2148 Element element = node.element; | 2205 Element element = node.element; |
| 2149 registry.registerStaticUse(element); | 2206 registry.registerStaticUse(element); |
| 2150 js.Expression lazyGetter = | 2207 js.Expression lazyGetter = |
| 2151 backend.emitter.isolateLazyInitializerAccess(element); | 2208 backend.emitter.isolateLazyInitializerAccess(element); |
| 2152 js.Call call = new js.Call(lazyGetter, <js.Expression>[]); | 2209 js.Call call = new js.Call(lazyGetter, <js.Expression>[], |
| 2153 push(call, node); | 2210 sourceInformation: node.sourceInformation); |
| 2211 push(call); |
| 2154 } | 2212 } |
| 2155 | 2213 |
| 2156 void visitStaticStore(HStaticStore node) { | 2214 void visitStaticStore(HStaticStore node) { |
| 2157 registry.registerStaticUse(node.element); | 2215 registry.registerStaticUse(node.element); |
| 2158 js.Node variable = backend.emitter.staticFieldAccess(node.element); | 2216 js.Node variable = backend.emitter.staticFieldAccess(node.element); |
| 2159 use(node.inputs[0]); | 2217 use(node.inputs[0]); |
| 2160 push(new js.Assignment(variable, pop()), node); | 2218 push(new js.Assignment(variable, pop()) |
| 2219 .withSourceInformation(node.sourceInformation)); |
| 2161 } | 2220 } |
| 2162 | 2221 |
| 2163 void visitStringConcat(HStringConcat node) { | 2222 void visitStringConcat(HStringConcat node) { |
| 2164 use(node.left); | 2223 use(node.left); |
| 2165 js.Expression jsLeft = pop(); | 2224 js.Expression jsLeft = pop(); |
| 2166 use(node.right); | 2225 use(node.right); |
| 2167 push(new js.Binary('+', jsLeft, pop()), node); | 2226 push(new js.Binary('+', jsLeft, pop()) |
| 2227 .withSourceInformation(node.sourceInformation)); |
| 2168 } | 2228 } |
| 2169 | 2229 |
| 2170 void visitStringify(HStringify node) { | 2230 void visitStringify(HStringify node) { |
| 2171 HInstruction input = node.inputs.first; | 2231 HInstruction input = node.inputs.first; |
| 2172 if (input.isString(compiler)) { | 2232 if (input.isString(compiler)) { |
| 2173 use(input); | 2233 use(input); |
| 2174 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) { | 2234 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) { |
| 2175 // JavaScript's + operator with a string for the left operand will convert | 2235 // JavaScript's + operator with a string for the left operand will convert |
| 2176 // the right operand to a string, and the conversion result is correct. | 2236 // the right operand to a string, and the conversion result is correct. |
| 2177 use(input); | 2237 use(input); |
| 2178 if (node.usedBy.length == 1 | 2238 if (node.usedBy.length == 1 |
| 2179 && node.usedBy[0] is HStringConcat | 2239 && node.usedBy[0] is HStringConcat |
| 2180 && node.usedBy[0].inputs[1] == node) { | 2240 && node.usedBy[0].inputs[1] == node) { |
| 2181 // The context is already <string> + value. | 2241 // The context is already <string> + value. |
| 2182 } else { | 2242 } else { |
| 2183 // Force an empty string for the first operand. | 2243 // Force an empty string for the first operand. |
| 2184 push(new js.Binary('+', js.string(""), pop()), node); | 2244 push(new js.Binary('+', js.string(""), pop()) |
| 2245 .withSourceInformation(node.sourceInformation)); |
| 2185 } | 2246 } |
| 2186 } else { | 2247 } else { |
| 2187 Element convertToString = backend.getStringInterpolationHelper(); | 2248 Element convertToString = backend.getStringInterpolationHelper(); |
| 2188 registry.registerStaticUse(convertToString); | 2249 registry.registerStaticUse(convertToString); |
| 2189 js.Expression jsHelper = | 2250 js.Expression jsHelper = |
| 2190 backend.emitter.staticFunctionAccess(convertToString); | 2251 backend.emitter.staticFunctionAccess(convertToString); |
| 2191 use(input); | 2252 use(input); |
| 2192 push(new js.Call(jsHelper, <js.Expression>[pop()]), node); | 2253 push(new js.Call(jsHelper, <js.Expression>[pop()], |
| 2254 sourceInformation: node.sourceInformation)); |
| 2193 } | 2255 } |
| 2194 } | 2256 } |
| 2195 | 2257 |
| 2196 void visitLiteralList(HLiteralList node) { | 2258 void visitLiteralList(HLiteralList node) { |
| 2197 registry.registerInstantiatedClass(compiler.listClass); | 2259 registry.registerInstantiatedClass(compiler.listClass); |
| 2198 generateArrayLiteral(node); | 2260 generateArrayLiteral(node); |
| 2199 } | 2261 } |
| 2200 | 2262 |
| 2201 void generateArrayLiteral(HLiteralList node) { | 2263 void generateArrayLiteral(HLiteralList node) { |
| 2202 List<js.Expression> elements = node.inputs.map((HInstruction input) { | 2264 List<js.Expression> elements = node.inputs.map((HInstruction input) { |
| 2203 use(input); | 2265 use(input); |
| 2204 return pop(); | 2266 return pop(); |
| 2205 }).toList(); | 2267 }).toList(); |
| 2206 push(new js.ArrayInitializer(elements), node); | 2268 push(new js.ArrayInitializer(elements) |
| 2269 .withSourceInformation(node.sourceInformation)); |
| 2207 } | 2270 } |
| 2208 | 2271 |
| 2209 void visitIndex(HIndex node) { | 2272 void visitIndex(HIndex node) { |
| 2210 use(node.receiver); | 2273 use(node.receiver); |
| 2211 js.Expression receiver = pop(); | 2274 js.Expression receiver = pop(); |
| 2212 use(node.index); | 2275 use(node.index); |
| 2213 push(new js.PropertyAccess(receiver, pop()), node); | 2276 push(new js.PropertyAccess(receiver, pop()) |
| 2277 .withSourceInformation(node.sourceInformation)); |
| 2214 } | 2278 } |
| 2215 | 2279 |
| 2216 void visitIndexAssign(HIndexAssign node) { | 2280 void visitIndexAssign(HIndexAssign node) { |
| 2217 use(node.receiver); | 2281 use(node.receiver); |
| 2218 js.Expression receiver = pop(); | 2282 js.Expression receiver = pop(); |
| 2219 use(node.index); | 2283 use(node.index); |
| 2220 js.Expression index = pop(); | 2284 js.Expression index = pop(); |
| 2221 use(node.value); | 2285 use(node.value); |
| 2222 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), | 2286 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()) |
| 2223 node); | 2287 .withSourceInformation(node.sourceInformation)); |
| 2224 } | 2288 } |
| 2225 | 2289 |
| 2226 void checkInt(HInstruction input, String cmp) { | 2290 void checkInt(HInstruction input, String cmp) { |
| 2227 use(input); | 2291 use(input); |
| 2228 js.Expression left = pop(); | 2292 js.Expression left = pop(); |
| 2229 use(input); | 2293 use(input); |
| 2230 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); | 2294 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); |
| 2231 push(new js.Binary(cmp, left, or0)); | 2295 push(new js.Binary(cmp, left, or0)); |
| 2232 } | 2296 } |
| 2233 | 2297 |
| 2234 void checkBigInt(HInstruction input, String cmp) { | 2298 void checkBigInt(HInstruction input, String cmp, |
| 2299 SourceInformation sourceInformation) { |
| 2235 use(input); | 2300 use(input); |
| 2236 js.Expression left = pop(); | 2301 js.Expression left = pop(); |
| 2237 use(input); | 2302 use(input); |
| 2238 js.Expression right = pop(); | 2303 js.Expression right = pop(); |
| 2239 // TODO(4984): Deal with infinity and -0.0. | 2304 // TODO(4984): Deal with infinity and -0.0. |
| 2240 push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right])); | 2305 push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right]) |
| 2306 .withSourceInformation(sourceInformation)); |
| 2241 } | 2307 } |
| 2242 | 2308 |
| 2243 void checkTypeOf(HInstruction input, String cmp, String typeName) { | 2309 void checkTypeOf(HInstruction input, String cmp, String typeName, |
| 2310 SourceInformation sourceInformation) { |
| 2244 use(input); | 2311 use(input); |
| 2245 js.Expression typeOf = new js.Prefix("typeof", pop()); | 2312 js.Expression typeOf = new js.Prefix("typeof", pop()); |
| 2246 push(new js.Binary(cmp, typeOf, js.string(typeName))); | 2313 push(new js.Binary(cmp, typeOf, js.string(typeName))); |
| 2247 } | 2314 } |
| 2248 | 2315 |
| 2249 void checkNum(HInstruction input, String cmp) | 2316 void checkNum(HInstruction input, String cmp, |
| 2250 => checkTypeOf(input, cmp, 'number'); | 2317 SourceInformation sourceInformation) { |
| 2318 return checkTypeOf(input, cmp, 'number', sourceInformation); |
| 2319 } |
| 2251 | 2320 |
| 2252 void checkDouble(HInstruction input, String cmp) => checkNum(input, cmp); | 2321 void checkDouble(HInstruction input, String cmp, |
| 2322 SourceInformation sourceInformation) { |
| 2323 return checkNum(input, cmp, sourceInformation); |
| 2324 } |
| 2253 | 2325 |
| 2254 void checkString(HInstruction input, String cmp) | 2326 void checkString(HInstruction input, String cmp, |
| 2255 => checkTypeOf(input, cmp, 'string'); | 2327 SourceInformation sourceInformation) { |
| 2328 return checkTypeOf(input, cmp, 'string', sourceInformation); |
| 2329 } |
| 2256 | 2330 |
| 2257 void checkBool(HInstruction input, String cmp) | 2331 void checkBool(HInstruction input, String cmp, |
| 2258 => checkTypeOf(input, cmp, 'boolean'); | 2332 SourceInformation sourceInformation) { |
| 2333 return checkTypeOf(input, cmp, 'boolean', sourceInformation); |
| 2334 } |
| 2259 | 2335 |
| 2260 void checkObject(HInstruction input, String cmp) { | 2336 void checkObject(HInstruction input, String cmp, |
| 2337 SourceInformation sourceInformation) { |
| 2261 assert(NullConstantValue.JsNull == 'null'); | 2338 assert(NullConstantValue.JsNull == 'null'); |
| 2262 if (cmp == "===") { | 2339 if (cmp == "===") { |
| 2263 checkTypeOf(input, '===', 'object'); | 2340 checkTypeOf(input, '===', 'object', sourceInformation); |
| 2264 js.Expression left = pop(); | 2341 js.Expression left = pop(); |
| 2265 use(input); | 2342 use(input); |
| 2266 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); | 2343 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); |
| 2267 push(new js.Binary("&&", left, notNull)); | 2344 push(new js.Binary("&&", left, notNull) |
| 2345 .withSourceInformation(sourceInformation)); |
| 2268 } else { | 2346 } else { |
| 2269 assert(cmp == "!=="); | 2347 assert(cmp == "!=="); |
| 2270 checkTypeOf(input, '!==', 'object'); | 2348 checkTypeOf(input, '!==', 'object', sourceInformation); |
| 2271 js.Expression left = pop(); | 2349 js.Expression left = pop(); |
| 2272 use(input); | 2350 use(input); |
| 2273 js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull()); | 2351 js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull()); |
| 2274 push(new js.Binary("||", left, eqNull)); | 2352 push(new js.Binary("||", left, eqNull) |
| 2353 .withSourceInformation(sourceInformation)); |
| 2275 } | 2354 } |
| 2276 } | 2355 } |
| 2277 | 2356 |
| 2278 void checkArray(HInstruction input, String cmp) { | 2357 void checkArray(HInstruction input, String cmp) { |
| 2279 use(input); | 2358 use(input); |
| 2280 js.PropertyAccess constructor = | 2359 js.PropertyAccess constructor = |
| 2281 new js.PropertyAccess.field(pop(), 'constructor'); | 2360 new js.PropertyAccess.field(pop(), 'constructor'); |
| 2282 push(new js.Binary(cmp, constructor, new js.VariableUse('Array'))); | 2361 push(new js.Binary(cmp, constructor, new js.VariableUse('Array'))); |
| 2283 } | 2362 } |
| 2284 | 2363 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2315 use(input); | 2394 use(input); |
| 2316 push(new js.Binary('==', pop(), new js.LiteralNull())); | 2395 push(new js.Binary('==', pop(), new js.LiteralNull())); |
| 2317 } | 2396 } |
| 2318 | 2397 |
| 2319 void checkNonNull(HInstruction input) { | 2398 void checkNonNull(HInstruction input) { |
| 2320 use(input); | 2399 use(input); |
| 2321 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2400 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
| 2322 } | 2401 } |
| 2323 | 2402 |
| 2324 void checkType(HInstruction input, HInstruction interceptor, | 2403 void checkType(HInstruction input, HInstruction interceptor, |
| 2325 DartType type, {bool negative: false}) { | 2404 DartType type, |
| 2405 SourceInformation sourceInformation, |
| 2406 {bool negative: false}) { |
| 2326 Element element = type.element; | 2407 Element element = type.element; |
| 2327 if (element == backend.jsArrayClass) { | 2408 if (element == backend.jsArrayClass) { |
| 2328 checkArray(input, negative ? '!==': '==='); | 2409 checkArray(input, negative ? '!==': '==='); |
| 2329 return; | 2410 return; |
| 2330 } else if (element == backend.jsMutableArrayClass) { | 2411 } else if (element == backend.jsMutableArrayClass) { |
| 2331 if (negative) { | 2412 if (negative) { |
| 2332 checkImmutableArray(input); | 2413 checkImmutableArray(input); |
| 2333 } else { | 2414 } else { |
| 2334 checkMutableArray(input); | 2415 checkMutableArray(input); |
| 2335 } | 2416 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2350 return; | 2431 return; |
| 2351 } else if (element == backend.jsUnmodifiableArrayClass) { | 2432 } else if (element == backend.jsUnmodifiableArrayClass) { |
| 2352 if (negative) { | 2433 if (negative) { |
| 2353 checkMutableArray(input); | 2434 checkMutableArray(input); |
| 2354 } else { | 2435 } else { |
| 2355 checkImmutableArray(input); | 2436 checkImmutableArray(input); |
| 2356 } | 2437 } |
| 2357 return; | 2438 return; |
| 2358 } | 2439 } |
| 2359 if (interceptor != null) { | 2440 if (interceptor != null) { |
| 2360 checkTypeViaProperty(interceptor, type, negative); | 2441 checkTypeViaProperty(interceptor, type, sourceInformation, |
| 2442 negative: negative); |
| 2361 } else { | 2443 } else { |
| 2362 checkTypeViaProperty(input, type, negative); | 2444 checkTypeViaProperty(input, type, sourceInformation, negative: negative); |
| 2363 } | 2445 } |
| 2364 } | 2446 } |
| 2365 | 2447 |
| 2366 void checkTypeViaProperty(HInstruction input, DartType type, bool negative) { | 2448 void checkTypeViaProperty(HInstruction input, DartType type, |
| 2449 SourceInformation sourceInformation, |
| 2450 {bool negative: false}) { |
| 2367 registry.registerIsCheck(type); | 2451 registry.registerIsCheck(type); |
| 2368 | 2452 |
| 2369 use(input); | 2453 use(input); |
| 2370 | 2454 |
| 2371 js.PropertyAccess field = | 2455 js.PropertyAccess field = |
| 2372 new js.PropertyAccess(pop(), backend.namer.operatorIsType(type)); | 2456 new js.PropertyAccess(pop(), backend.namer.operatorIsType(type)) |
| 2457 .withSourceInformation(sourceInformation); |
| 2373 // We always negate at least once so that the result is boolified. | 2458 // We always negate at least once so that the result is boolified. |
| 2374 push(new js.Prefix('!', field)); | 2459 push(new js.Prefix('!', field) |
| 2460 .withSourceInformation(sourceInformation)); |
| 2375 // If the result is not negated, put another '!' in front. | 2461 // If the result is not negated, put another '!' in front. |
| 2376 if (!negative) push(new js.Prefix('!', pop())); | 2462 if (!negative) { |
| 2463 push(new js.Prefix('!', pop()) |
| 2464 .withSourceInformation(sourceInformation)); |
| 2465 } |
| 2377 } | 2466 } |
| 2378 | 2467 |
| 2379 void checkTypeViaInstanceof( | 2468 void checkTypeViaInstanceof( |
| 2380 HInstruction input, DartType type, bool negative) { | 2469 HInstruction input, DartType type, |
| 2470 SourceInformation sourceInformation, |
| 2471 {bool negative: false}) { |
| 2381 registry.registerIsCheck(type); | 2472 registry.registerIsCheck(type); |
| 2382 | 2473 |
| 2383 use(input); | 2474 use(input); |
| 2384 | 2475 |
| 2385 js.Expression jsClassReference = | 2476 js.Expression jsClassReference = |
| 2386 backend.emitter.constructorAccess(type.element); | 2477 backend.emitter.constructorAccess(type.element); |
| 2387 push(js.js('# instanceof #', [pop(), jsClassReference])); | 2478 push(js.js('# instanceof #', [pop(), jsClassReference]) |
| 2388 if (negative) push(new js.Prefix('!', pop())); | 2479 .withSourceInformation(sourceInformation)); |
| 2480 if (negative) { |
| 2481 push(new js.Prefix('!', pop()) |
| 2482 .withSourceInformation(sourceInformation)); |
| 2483 } |
| 2389 registry.registerInstantiatedType(type); | 2484 registry.registerInstantiatedType(type); |
| 2390 } | 2485 } |
| 2391 | 2486 |
| 2392 void handleNumberOrStringSupertypeCheck(HInstruction input, | 2487 void handleNumberOrStringSupertypeCheck(HInstruction input, |
| 2393 HInstruction interceptor, | 2488 HInstruction interceptor, |
| 2394 DartType type, | 2489 DartType type, |
| 2395 { bool negative: false }) { | 2490 SourceInformation sourceInformation, |
| 2396 assert(!identical(type.element, compiler.listClass) | 2491 {bool negative: false}) { |
| 2397 && !Elements.isListSupertype(type.element, compiler) | 2492 assert(!identical(type.element, compiler.listClass) && |
| 2398 && !Elements.isStringOnlySupertype(type.element, compiler)); | 2493 !Elements.isListSupertype(type.element, compiler) && |
| 2494 !Elements.isStringOnlySupertype(type.element, compiler)); |
| 2399 String relation = negative ? '!==' : '==='; | 2495 String relation = negative ? '!==' : '==='; |
| 2400 checkNum(input, relation); | 2496 checkNum(input, relation, sourceInformation); |
| 2401 js.Expression numberTest = pop(); | 2497 js.Expression numberTest = pop(); |
| 2402 checkString(input, relation); | 2498 checkString(input, relation, sourceInformation); |
| 2403 js.Expression stringTest = pop(); | 2499 js.Expression stringTest = pop(); |
| 2404 checkObject(input, relation); | 2500 checkObject(input, relation, sourceInformation); |
| 2405 js.Expression objectTest = pop(); | 2501 js.Expression objectTest = pop(); |
| 2406 checkType(input, interceptor, type, negative: negative); | 2502 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2407 String combiner = negative ? '&&' : '||'; | 2503 String combiner = negative ? '&&' : '||'; |
| 2408 String combiner2 = negative ? '||' : '&&'; | 2504 String combiner2 = negative ? '||' : '&&'; |
| 2409 push(new js.Binary(combiner, | 2505 push(new js.Binary(combiner, |
| 2410 new js.Binary(combiner, numberTest, stringTest), | 2506 new js.Binary(combiner, numberTest, stringTest) |
| 2411 new js.Binary(combiner2, objectTest, pop()))); | 2507 .withSourceInformation(sourceInformation), |
| 2508 new js.Binary(combiner2, objectTest, pop()) |
| 2509 .withSourceInformation(sourceInformation)) |
| 2510 .withSourceInformation(sourceInformation)); |
| 2412 } | 2511 } |
| 2413 | 2512 |
| 2414 void handleStringSupertypeCheck(HInstruction input, | 2513 void handleStringSupertypeCheck(HInstruction input, |
| 2415 HInstruction interceptor, | 2514 HInstruction interceptor, |
| 2416 DartType type, | 2515 DartType type, |
| 2417 { bool negative: false }) { | 2516 SourceInformation sourceInformation, |
| 2517 {bool negative: false}) { |
| 2418 assert(!identical(type.element, compiler.listClass) | 2518 assert(!identical(type.element, compiler.listClass) |
| 2419 && !Elements.isListSupertype(type.element, compiler) | 2519 && !Elements.isListSupertype(type.element, compiler) |
| 2420 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2520 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
| 2421 String relation = negative ? '!==' : '==='; | 2521 String relation = negative ? '!==' : '==='; |
| 2422 checkString(input, relation); | 2522 checkString(input, relation, sourceInformation); |
| 2423 js.Expression stringTest = pop(); | 2523 js.Expression stringTest = pop(); |
| 2424 checkObject(input, relation); | 2524 checkObject(input, relation, sourceInformation); |
| 2425 js.Expression objectTest = pop(); | 2525 js.Expression objectTest = pop(); |
| 2426 checkType(input, interceptor, type, negative: negative); | 2526 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2427 String combiner = negative ? '||' : '&&'; | 2527 String combiner = negative ? '||' : '&&'; |
| 2428 push(new js.Binary(negative ? '&&' : '||', | 2528 push(new js.Binary(negative ? '&&' : '||', |
| 2429 stringTest, | 2529 stringTest, |
| 2430 new js.Binary(combiner, objectTest, pop()))); | 2530 new js.Binary(combiner, objectTest, pop()))); |
| 2431 } | 2531 } |
| 2432 | 2532 |
| 2433 void handleListOrSupertypeCheck(HInstruction input, | 2533 void handleListOrSupertypeCheck(HInstruction input, |
| 2434 HInstruction interceptor, | 2534 HInstruction interceptor, |
| 2435 DartType type, | 2535 DartType type, |
| 2536 SourceInformation sourceInformation, |
| 2436 { bool negative: false }) { | 2537 { bool negative: false }) { |
| 2437 assert(!identical(type.element, compiler.stringClass) | 2538 assert(!identical(type.element, compiler.stringClass) |
| 2438 && !Elements.isStringOnlySupertype(type.element, compiler) | 2539 && !Elements.isStringOnlySupertype(type.element, compiler) |
| 2439 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2540 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
| 2440 String relation = negative ? '!==' : '==='; | 2541 String relation = negative ? '!==' : '==='; |
| 2441 checkObject(input, relation); | 2542 checkObject(input, relation, sourceInformation); |
| 2442 js.Expression objectTest = pop(); | 2543 js.Expression objectTest = pop(); |
| 2443 checkArray(input, relation); | 2544 checkArray(input, relation); |
| 2444 js.Expression arrayTest = pop(); | 2545 js.Expression arrayTest = pop(); |
| 2445 checkType(input, interceptor, type, negative: negative); | 2546 checkType(input, interceptor, type, sourceInformation, negative: negative); |
| 2446 String combiner = negative ? '&&' : '||'; | 2547 String combiner = negative ? '&&' : '||'; |
| 2447 push(new js.Binary(negative ? '||' : '&&', | 2548 push(new js.Binary(negative ? '||' : '&&', |
| 2448 objectTest, | 2549 objectTest, |
| 2449 new js.Binary(combiner, arrayTest, pop()))); | 2550 new js.Binary(combiner, arrayTest, pop())) |
| 2551 .withSourceInformation(sourceInformation)); |
| 2450 } | 2552 } |
| 2451 | 2553 |
| 2452 void visitIs(HIs node) { | 2554 void visitIs(HIs node) { |
| 2453 emitIs(node, "==="); | 2555 emitIs(node, "===", node.sourceInformation); |
| 2454 } | 2556 } |
| 2455 | 2557 |
| 2456 void visitIsViaInterceptor(HIsViaInterceptor node) { | 2558 void visitIsViaInterceptor(HIsViaInterceptor node) { |
| 2457 emitIsViaInterceptor(node, false); | 2559 emitIsViaInterceptor(node, node.sourceInformation, negative: false); |
| 2458 } | 2560 } |
| 2459 | 2561 |
| 2460 void emitIs(HIs node, String relation) { | 2562 void emitIs(HIs node, String relation, SourceInformation sourceInformation) { |
| 2461 DartType type = node.typeExpression; | 2563 DartType type = node.typeExpression; |
| 2462 registry.registerIsCheck(type); | 2564 registry.registerIsCheck(type); |
| 2463 HInstruction input = node.expression; | 2565 HInstruction input = node.expression; |
| 2464 | 2566 |
| 2465 // If this is changed to single == there are several places below that must | 2567 // If this is changed to single == there are several places below that must |
| 2466 // be changed to match. | 2568 // be changed to match. |
| 2467 assert(relation == '===' || relation == '!=='); | 2569 assert(relation == '===' || relation == '!=='); |
| 2468 bool negative = relation == '!=='; | 2570 bool negative = relation == '!=='; |
| 2469 | 2571 |
| 2470 if (node.isVariableCheck || node.isCompoundCheck) { | 2572 if (node.isVariableCheck || node.isCompoundCheck) { |
| 2471 use(node.checkCall); | 2573 use(node.checkCall); |
| 2472 if (negative) push(new js.Prefix('!', pop())); | 2574 if (negative) push(new js.Prefix('!', pop())); |
| 2473 } else { | 2575 } else { |
| 2474 assert(node.isRawCheck); | 2576 assert(node.isRawCheck); |
| 2475 HInstruction interceptor = node.interceptor; | 2577 HInstruction interceptor = node.interceptor; |
| 2476 ClassElement objectClass = compiler.objectClass; | 2578 ClassElement objectClass = compiler.objectClass; |
| 2477 Element element = type.element; | 2579 Element element = type.element; |
| 2478 if (element == compiler.nullClass) { | 2580 if (element == compiler.nullClass) { |
| 2479 if (negative) { | 2581 if (negative) { |
| 2480 checkNonNull(input); | 2582 checkNonNull(input); |
| 2481 } else { | 2583 } else { |
| 2482 checkNull(input); | 2584 checkNull(input); |
| 2483 } | 2585 } |
| 2484 } else if (identical(element, objectClass) || type.treatAsDynamic) { | 2586 } else if (identical(element, objectClass) || type.treatAsDynamic) { |
| 2485 // The constant folder also does this optimization, but we make | 2587 // The constant folder also does this optimization, but we make |
| 2486 // it safe by assuming it may have not run. | 2588 // it safe by assuming it may have not run. |
| 2487 push(newLiteralBool(!negative), node); | 2589 push(newLiteralBool(!negative, sourceInformation)); |
| 2488 } else if (element == compiler.stringClass) { | 2590 } else if (element == compiler.stringClass) { |
| 2489 checkString(input, relation); | 2591 checkString(input, relation, sourceInformation); |
| 2490 attachLocationToLast(node); | |
| 2491 } else if (element == compiler.doubleClass) { | 2592 } else if (element == compiler.doubleClass) { |
| 2492 checkDouble(input, relation); | 2593 checkDouble(input, relation, sourceInformation); |
| 2493 attachLocationToLast(node); | |
| 2494 } else if (element == compiler.numClass) { | 2594 } else if (element == compiler.numClass) { |
| 2495 checkNum(input, relation); | 2595 checkNum(input, relation, sourceInformation); |
| 2496 attachLocationToLast(node); | |
| 2497 } else if (element == compiler.boolClass) { | 2596 } else if (element == compiler.boolClass) { |
| 2498 checkBool(input, relation); | 2597 checkBool(input, relation, sourceInformation); |
| 2499 attachLocationToLast(node); | |
| 2500 } else if (element == compiler.intClass) { | 2598 } else if (element == compiler.intClass) { |
| 2501 // The is check in the code tells us that it might not be an | 2599 // The is check in the code tells us that it might not be an |
| 2502 // int. So we do a typeof first to avoid possible | 2600 // int. So we do a typeof first to avoid possible |
| 2503 // deoptimizations on the JS engine due to the Math.floor check. | 2601 // deoptimizations on the JS engine due to the Math.floor check. |
| 2504 checkNum(input, relation); | 2602 checkNum(input, relation, sourceInformation); |
| 2505 js.Expression numTest = pop(); | 2603 js.Expression numTest = pop(); |
| 2506 checkBigInt(input, relation); | 2604 checkBigInt(input, relation, sourceInformation); |
| 2507 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); | 2605 push(new js.Binary(negative ? '||' : '&&', numTest, pop()) |
| 2606 .withSourceInformation(sourceInformation)); |
| 2508 } else if (node.useInstanceOf) { | 2607 } else if (node.useInstanceOf) { |
| 2509 assert(interceptor == null); | 2608 assert(interceptor == null); |
| 2510 checkTypeViaInstanceof(input, type, negative); | 2609 checkTypeViaInstanceof(input, type, |
| 2511 attachLocationToLast(node); | 2610 sourceInformation, |
| 2611 negative: negative); |
| 2512 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { | 2612 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { |
| 2513 handleNumberOrStringSupertypeCheck( | 2613 handleNumberOrStringSupertypeCheck( |
| 2514 input, interceptor, type, negative: negative); | 2614 input, interceptor, type, |
| 2515 attachLocationToLast(node); | 2615 sourceInformation, |
| 2616 negative: negative); |
| 2516 } else if (Elements.isStringOnlySupertype(element, compiler)) { | 2617 } else if (Elements.isStringOnlySupertype(element, compiler)) { |
| 2517 handleStringSupertypeCheck( | 2618 handleStringSupertypeCheck( |
| 2518 input, interceptor, type, negative: negative); | 2619 input, interceptor, type, |
| 2519 attachLocationToLast(node); | 2620 sourceInformation, |
| 2520 } else if (identical(element, compiler.listClass) | 2621 negative: negative); |
| 2521 || Elements.isListSupertype(element, compiler)) { | 2622 } else if (identical(element, compiler.listClass) || |
| 2623 Elements.isListSupertype(element, compiler)) { |
| 2522 handleListOrSupertypeCheck( | 2624 handleListOrSupertypeCheck( |
| 2523 input, interceptor, type, negative: negative); | 2625 input, interceptor, type, |
| 2524 attachLocationToLast(node); | 2626 sourceInformation, |
| 2627 negative: negative); |
| 2525 } else if (type.isFunctionType) { | 2628 } else if (type.isFunctionType) { |
| 2526 checkType(input, interceptor, type, negative: negative); | 2629 checkType(input, interceptor, type, |
| 2527 attachLocationToLast(node); | 2630 sourceInformation, |
| 2631 negative: negative); |
| 2528 } else if ((input.canBePrimitive(compiler) | 2632 } else if ((input.canBePrimitive(compiler) |
| 2529 && !input.canBePrimitiveArray(compiler)) | 2633 && !input.canBePrimitiveArray(compiler)) |
| 2530 || input.canBeNull()) { | 2634 || input.canBeNull()) { |
| 2531 checkObject(input, relation); | 2635 checkObject(input, relation, node.sourceInformation); |
| 2532 js.Expression objectTest = pop(); | 2636 js.Expression objectTest = pop(); |
| 2533 checkType(input, interceptor, type, negative: negative); | 2637 checkType(input, interceptor, type, |
| 2534 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); | 2638 sourceInformation, |
| 2639 negative: negative); |
| 2640 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()) |
| 2641 .withSourceInformation(sourceInformation)); |
| 2535 } else { | 2642 } else { |
| 2536 checkType(input, interceptor, type, negative: negative); | 2643 checkType(input, interceptor, type, |
| 2537 attachLocationToLast(node); | 2644 sourceInformation, |
| 2645 negative: negative); |
| 2538 } | 2646 } |
| 2539 } | 2647 } |
| 2540 } | 2648 } |
| 2541 | 2649 |
| 2542 void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) { | 2650 void emitIsViaInterceptor(HIsViaInterceptor node, |
| 2543 checkTypeViaProperty(node.interceptor, node.typeExpression, negative); | 2651 SourceInformation sourceInformation, |
| 2544 attachLocationToLast(node); | 2652 {bool negative: false}) { |
| 2653 checkTypeViaProperty(node.interceptor, node.typeExpression, |
| 2654 sourceInformation, |
| 2655 negative: negative); |
| 2545 } | 2656 } |
| 2546 | 2657 |
| 2547 js.Expression generateReceiverOrArgumentTypeTest( | 2658 js.Expression generateReceiverOrArgumentTypeTest( |
| 2548 HInstruction input, TypeMask checkedType) { | 2659 HInstruction input, TypeMask checkedType) { |
| 2549 ClassWorld classWorld = compiler.world; | 2660 ClassWorld classWorld = compiler.world; |
| 2550 TypeMask inputType = input.instructionType; | 2661 TypeMask inputType = input.instructionType; |
| 2551 // Figure out if it is beneficial to turn this into a null check. | 2662 // Figure out if it is beneficial to turn this into a null check. |
| 2552 // V8 generally prefers 'typeof' checks, but for integers and | 2663 // V8 generally prefers 'typeof' checks, but for integers and |
| 2553 // indexable primitives we cannot compile this test into a single | 2664 // indexable primitives we cannot compile this test into a single |
| 2554 // typeof check so the null check is cheaper. | 2665 // typeof check so the null check is cheaper. |
| 2555 bool isIntCheck = checkedType.containsOnlyInt(classWorld); | 2666 bool isIntCheck = checkedType.containsOnlyInt(classWorld); |
| 2556 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); | 2667 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); |
| 2557 bool turnIntoNullCheck = !turnIntoNumCheck | 2668 bool turnIntoNullCheck = !turnIntoNumCheck |
| 2558 && (checkedType.nullable() == inputType) | 2669 && (checkedType.nullable() == inputType) |
| 2559 && (isIntCheck | 2670 && (isIntCheck |
| 2560 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); | 2671 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); |
| 2561 | 2672 |
| 2562 if (turnIntoNullCheck) { | 2673 if (turnIntoNullCheck) { |
| 2563 use(input); | 2674 use(input); |
| 2564 return new js.Binary("==", pop(), new js.LiteralNull()); | 2675 return new js.Binary("==", pop(), new js.LiteralNull()) |
| 2676 .withSourceInformation(input.sourceInformation); |
| 2565 } else if (isIntCheck && !turnIntoNumCheck) { | 2677 } else if (isIntCheck && !turnIntoNumCheck) { |
| 2566 // input is !int | 2678 // input is !int |
| 2567 checkBigInt(input, '!=='); | 2679 checkBigInt(input, '!==', input.sourceInformation); |
| 2568 return pop(); | 2680 return pop(); |
| 2569 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { | 2681 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { |
| 2570 // input is !num | 2682 // input is !num |
| 2571 checkNum(input, '!=='); | 2683 checkNum(input, '!==', input.sourceInformation); |
| 2572 return pop(); | 2684 return pop(); |
| 2573 } else if (checkedType.containsOnlyBool(classWorld)) { | 2685 } else if (checkedType.containsOnlyBool(classWorld)) { |
| 2574 // input is !bool | 2686 // input is !bool |
| 2575 checkBool(input, '!=='); | 2687 checkBool(input, '!==', input.sourceInformation); |
| 2576 return pop(); | 2688 return pop(); |
| 2577 } else if (checkedType.containsOnlyString(classWorld)) { | 2689 } else if (checkedType.containsOnlyString(classWorld)) { |
| 2578 // input is !string | 2690 // input is !string |
| 2579 checkString(input, '!=='); | 2691 checkString(input, '!==', input.sourceInformation); |
| 2580 return pop(); | 2692 return pop(); |
| 2581 } | 2693 } |
| 2582 compiler.internalError(input, 'Unexpected check.'); | 2694 compiler.internalError(input, 'Unexpected check.'); |
| 2583 return null; | 2695 return null; |
| 2584 } | 2696 } |
| 2585 | 2697 |
| 2586 void visitTypeConversion(HTypeConversion node) { | 2698 void visitTypeConversion(HTypeConversion node) { |
| 2587 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { | 2699 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
| 2588 ClassWorld classWorld = compiler.world; | 2700 ClassWorld classWorld = compiler.world; |
| 2589 // An int check if the input is not int or null, is not | 2701 // An int check if the input is not int or null, is not |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2600 generateThrowWithHelper('iae', node.checkedInput); | 2712 generateThrowWithHelper('iae', node.checkedInput); |
| 2601 } else if (node.isReceiverTypeCheck) { | 2713 } else if (node.isReceiverTypeCheck) { |
| 2602 use(node.checkedInput); | 2714 use(node.checkedInput); |
| 2603 js.Name methodName = | 2715 js.Name methodName = |
| 2604 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2716 backend.namer.invocationName(node.receiverTypeCheckSelector); |
| 2605 js.Expression call = js.propertyCall(pop(), methodName, []); | 2717 js.Expression call = js.propertyCall(pop(), methodName, []); |
| 2606 pushStatement(new js.Return(call)); | 2718 pushStatement(new js.Return(call)); |
| 2607 } | 2719 } |
| 2608 currentContainer = oldContainer; | 2720 currentContainer = oldContainer; |
| 2609 body = unwrapStatement(body); | 2721 body = unwrapStatement(body); |
| 2610 pushStatement(new js.If.noElse(test, body), node); | 2722 pushStatement(new js.If.noElse(test, body) |
| 2723 .withSourceInformation(node.sourceInformation)); |
| 2611 return; | 2724 return; |
| 2612 } | 2725 } |
| 2613 | 2726 |
| 2614 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2727 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
| 2615 DartType type = node.typeExpression; | 2728 DartType type = node.typeExpression; |
| 2616 assert(type.kind != TypeKind.TYPEDEF); | 2729 assert(type.kind != TypeKind.TYPEDEF); |
| 2617 if (type.isFunctionType) { | 2730 if (type.isFunctionType) { |
| 2618 // TODO(5022): We currently generate $isFunction checks for | 2731 // TODO(5022): We currently generate $isFunction checks for |
| 2619 // function types. | 2732 // function types. |
| 2620 registry.registerIsCheck(compiler.functionClass.rawType); | 2733 registry.registerIsCheck(compiler.functionClass.rawType); |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2740 js.PropertyAccess accessHelper(String name) { | 2853 js.PropertyAccess accessHelper(String name) { |
| 2741 Element helper = backend.findHelper(name); | 2854 Element helper = backend.findHelper(name); |
| 2742 if (helper == null) { | 2855 if (helper == null) { |
| 2743 // For mocked-up tests. | 2856 // For mocked-up tests. |
| 2744 return js.js('(void 0).$name'); | 2857 return js.js('(void 0).$name'); |
| 2745 } | 2858 } |
| 2746 registry.registerStaticUse(helper); | 2859 registry.registerStaticUse(helper); |
| 2747 return backend.emitter.staticFunctionAccess(helper); | 2860 return backend.emitter.staticFunctionAccess(helper); |
| 2748 } | 2861 } |
| 2749 } | 2862 } |
| OLD | NEW |