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 |