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 String name = | 1513 String 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 14 matching lines...) Expand all Loading... |
1527 // optimization. The optimization ensures any type checks or | 1545 // optimization. The optimization ensures any type checks or |
1528 // conversions have been satisified. | 1546 // conversions have been satisified. |
1529 methodName = target.fixedBackendName; | 1547 methodName = target.fixedBackendName; |
1530 } | 1548 } |
1531 } | 1549 } |
1532 | 1550 |
1533 if (methodName == null) { | 1551 if (methodName == null) { |
1534 methodName = backend.namer.invocationName(node.selector); | 1552 methodName = backend.namer.invocationName(node.selector); |
1535 registerMethodInvoke(node); | 1553 registerMethodInvoke(node); |
1536 } | 1554 } |
1537 push(js.propertyCall(object, methodName, arguments), node); | 1555 push(js.propertyCall(object, methodName, arguments) |
| 1556 .withSourceInformation(node.sourceInformation)); |
1538 } | 1557 } |
1539 | 1558 |
1540 void visitInvokeConstructorBody(HInvokeConstructorBody node) { | 1559 void visitInvokeConstructorBody(HInvokeConstructorBody node) { |
1541 use(node.inputs[0]); | 1560 use(node.inputs[0]); |
1542 js.Expression object = pop(); | 1561 js.Expression object = pop(); |
1543 String methodName = backend.namer.instanceMethodName(node.element); | 1562 String methodName = backend.namer.instanceMethodName(node.element); |
1544 List<js.Expression> arguments = visitArguments(node.inputs); | 1563 List<js.Expression> arguments = visitArguments(node.inputs); |
1545 push(js.propertyCall(object, methodName, arguments), node); | 1564 push(js.propertyCall(object, methodName, arguments) |
| 1565 .withSourceInformation(node.sourceInformation)); |
1546 registry.registerStaticUse(node.element); | 1566 registry.registerStaticUse(node.element); |
1547 } | 1567 } |
1548 | 1568 |
1549 void visitOneShotInterceptor(HOneShotInterceptor node) { | 1569 void visitOneShotInterceptor(HOneShotInterceptor node) { |
1550 List<js.Expression> arguments = visitArguments(node.inputs); | 1570 List<js.Expression> arguments = visitArguments(node.inputs); |
1551 var isolate = new js.VariableUse( | 1571 var isolate = new js.VariableUse( |
1552 backend.namer.globalObjectFor(backend.interceptorsLibrary)); | 1572 backend.namer.globalObjectFor(backend.interceptorsLibrary)); |
1553 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1573 Selector selector = getOptimizedSelectorFor(node, node.selector); |
1554 String methodName = backend.registerOneShotInterceptor(selector); | 1574 String methodName = backend.registerOneShotInterceptor(selector); |
1555 push(js.propertyCall(isolate, methodName, arguments), node); | 1575 push(js.propertyCall(isolate, methodName, arguments) |
| 1576 .withSourceInformation(node.sourceInformation)); |
1556 if (selector.isGetter) { | 1577 if (selector.isGetter) { |
1557 registerGetter(node); | 1578 registerGetter(node); |
1558 } else if (selector.isSetter) { | 1579 } else if (selector.isSetter) { |
1559 registerSetter(node); | 1580 registerSetter(node); |
1560 } else { | 1581 } else { |
1561 registerMethodInvoke(node); | 1582 registerMethodInvoke(node); |
1562 } | 1583 } |
1563 registry.registerUseInterceptor(); | 1584 registry.registerUseInterceptor(); |
1564 } | 1585 } |
1565 | 1586 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1602 } | 1623 } |
1603 | 1624 |
1604 void registerGetter(HInvokeDynamic node) { | 1625 void registerGetter(HInvokeDynamic node) { |
1605 Selector selector = getOptimizedSelectorFor(node, node.selector); | 1626 Selector selector = getOptimizedSelectorFor(node, node.selector); |
1606 registry.registerDynamicGetter(selector); | 1627 registry.registerDynamicGetter(selector); |
1607 } | 1628 } |
1608 | 1629 |
1609 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 1630 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
1610 use(node.receiver); | 1631 use(node.receiver); |
1611 String name = backend.namer.invocationName(node.selector); | 1632 String name = backend.namer.invocationName(node.selector); |
1612 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1633 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
| 1634 .withSourceInformation(node.sourceInformation)); |
1613 registerSetter(node); | 1635 registerSetter(node); |
1614 } | 1636 } |
1615 | 1637 |
1616 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 1638 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
1617 use(node.receiver); | 1639 use(node.receiver); |
1618 String name = backend.namer.invocationName(node.selector); | 1640 String name = backend.namer.invocationName(node.selector); |
1619 push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node); | 1641 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) |
| 1642 .withSourceInformation(node.sourceInformation)); |
1620 registerGetter(node); | 1643 registerGetter(node); |
1621 } | 1644 } |
1622 | 1645 |
1623 visitInvokeClosure(HInvokeClosure node) { | 1646 visitInvokeClosure(HInvokeClosure node) { |
1624 Selector call = new Selector.callClosureFrom(node.selector); | 1647 Selector call = new Selector.callClosureFrom(node.selector); |
1625 use(node.receiver); | 1648 use(node.receiver); |
1626 push(js.propertyCall(pop(), | 1649 push(js.propertyCall(pop(), |
1627 backend.namer.invocationName(call), | 1650 backend.namer.invocationName(call), |
1628 visitArguments(node.inputs)), | 1651 visitArguments(node.inputs)) |
1629 node); | 1652 .withSourceInformation(node.sourceInformation)); |
1630 registry.registerDynamicInvocation(call); | 1653 registry.registerDynamicInvocation(call); |
1631 } | 1654 } |
1632 | 1655 |
1633 visitInvokeStatic(HInvokeStatic node) { | 1656 visitInvokeStatic(HInvokeStatic node) { |
1634 Element element = node.element; | 1657 Element element = node.element; |
1635 List<DartType> instantiatedTypes = node.instantiatedTypes; | 1658 List<DartType> instantiatedTypes = node.instantiatedTypes; |
1636 | 1659 |
1637 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { | 1660 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { |
1638 instantiatedTypes.forEach((type) { | 1661 instantiatedTypes.forEach((type) { |
1639 registry.registerInstantiatedType(type); | 1662 registry.registerInstantiatedType(type); |
(...skipping 20 matching lines...) Expand all Loading... |
1660 // more optimizations available to the loop. This form is 50% faster on | 1683 // more optimizations available to the loop. This form is 50% faster on |
1661 // some small loop, almost as fast as loops with no concurrent | 1684 // some small loop, almost as fast as loops with no concurrent |
1662 // modification check. | 1685 // modification check. |
1663 push(js.js('# || (0, #)(#)',[ | 1686 push(js.js('# || (0, #)(#)',[ |
1664 arguments[0], | 1687 arguments[0], |
1665 backend.emitter.staticFunctionAccess(throwFunction), | 1688 backend.emitter.staticFunctionAccess(throwFunction), |
1666 arguments[1]])); | 1689 arguments[1]])); |
1667 } else { | 1690 } else { |
1668 registry.registerStaticInvocation(element); | 1691 registry.registerStaticInvocation(element); |
1669 push(backend.emitter.staticFunctionAccess(element)); | 1692 push(backend.emitter.staticFunctionAccess(element)); |
1670 push(new js.Call(pop(), arguments), node); | 1693 push(new js.Call(pop(), arguments, |
| 1694 sourceInformation: node.sourceInformation)); |
1671 } | 1695 } |
1672 | 1696 |
1673 } | 1697 } |
1674 | 1698 |
1675 visitInvokeSuper(HInvokeSuper node) { | 1699 visitInvokeSuper(HInvokeSuper node) { |
1676 Element superMethod = node.element; | 1700 Element superMethod = node.element; |
1677 registry.registerSuperInvocation(superMethod); | 1701 registry.registerSuperInvocation(superMethod); |
1678 ClassElement superClass = superMethod.enclosingClass; | 1702 ClassElement superClass = superMethod.enclosingClass; |
1679 if (superMethod.kind == ElementKind.FIELD) { | 1703 if (superMethod.kind == ElementKind.FIELD) { |
1680 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); | 1704 String fieldName = backend.namer.instanceFieldPropertyName(superMethod); |
1681 use(node.inputs[0]); | 1705 use(node.inputs[0]); |
1682 js.PropertyAccess access = | 1706 js.PropertyAccess access = |
1683 new js.PropertyAccess.field(pop(), fieldName); | 1707 new js.PropertyAccess.field(pop(), fieldName) |
| 1708 .withSourceInformation(node.sourceInformation); |
1684 if (node.isSetter) { | 1709 if (node.isSetter) { |
1685 use(node.value); | 1710 use(node.value); |
1686 push(new js.Assignment(access, pop()), node); | 1711 push(new js.Assignment(access, pop()) |
| 1712 .withSourceInformation(node.sourceInformation)); |
1687 } else { | 1713 } else { |
1688 push(access, node); | 1714 push(access); |
1689 } | 1715 } |
1690 } else { | 1716 } else { |
1691 Selector selector = node.selector; | 1717 Selector selector = node.selector; |
1692 | 1718 |
1693 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { | 1719 if (!backend.maybeRegisterAliasedSuperMember(superMethod, selector)) { |
1694 String methodName; | 1720 String methodName; |
1695 if (selector.isGetter) { | 1721 if (selector.isGetter) { |
1696 // If the selector we need to register a typed getter to the | 1722 // If the selector we need to register a typed getter to the |
1697 // [world]. The emitter needs to know if it needs to emit a | 1723 // [world]. The emitter needs to know if it needs to emit a |
1698 // bound closure for a method. | 1724 // bound closure for a method. |
1699 TypeMask receiverType = | 1725 TypeMask receiverType = |
1700 new TypeMask.nonNullExact(superClass, compiler.world); | 1726 new TypeMask.nonNullExact(superClass, compiler.world); |
1701 selector = new TypedSelector(receiverType, selector, compiler.world); | 1727 selector = new TypedSelector(receiverType, selector, compiler.world); |
1702 // TODO(floitsch): we know the target. We shouldn't register a | 1728 // TODO(floitsch): we know the target. We shouldn't register a |
1703 // dynamic getter. | 1729 // dynamic getter. |
1704 registry.registerDynamicGetter(selector); | 1730 registry.registerDynamicGetter(selector); |
1705 registry.registerGetterForSuperMethod(node.element); | 1731 registry.registerGetterForSuperMethod(node.element); |
1706 methodName = backend.namer.invocationName(selector); | 1732 methodName = backend.namer.invocationName(selector); |
1707 } else { | 1733 } else { |
1708 assert(invariant(node, compiler.hasIncrementalSupport)); | 1734 assert(invariant(node, compiler.hasIncrementalSupport)); |
1709 methodName = backend.namer.instanceMethodName(superMethod); | 1735 methodName = backend.namer.instanceMethodName(superMethod); |
1710 } | 1736 } |
1711 push(js.js('#.#.call(#)', | 1737 push(js.js('#.#.call(#)', |
1712 [backend.emitter.prototypeAccess(superClass, | 1738 [backend.emitter.prototypeAccess(superClass, |
1713 hasBeenInstantiated: true), | 1739 hasBeenInstantiated: true), |
1714 methodName, visitArguments(node.inputs, start: 0)]), | 1740 methodName, visitArguments(node.inputs, start: 0)]) |
1715 node); | 1741 .withSourceInformation(node.sourceInformation)); |
1716 } else { | 1742 } else { |
1717 use(node.receiver); | 1743 use(node.receiver); |
1718 push( | 1744 push( |
1719 js.js('#.#(#)', [ | 1745 js.js('#.#(#)', [ |
1720 pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod), | 1746 pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod), |
1721 visitArguments(node.inputs, start: 1)]), // Skip receiver argument. | 1747 visitArguments(node.inputs, start: 1)]) // Skip receiver argument. |
1722 node); | 1748 .withSourceInformation(node.sourceInformation)); |
1723 } | 1749 } |
1724 } | 1750 } |
1725 } | 1751 } |
1726 | 1752 |
1727 visitFieldGet(HFieldGet node) { | 1753 visitFieldGet(HFieldGet node) { |
1728 use(node.receiver); | 1754 use(node.receiver); |
1729 Element element = node.element; | 1755 Element element = node.element; |
1730 if (node.isNullCheck) { | 1756 if (node.isNullCheck) { |
1731 // We access a JavaScript member we know all objects besides | 1757 // We access a JavaScript member we know all objects besides |
1732 // null and undefined have: V8 does not like accessing a member | 1758 // null and undefined have: V8 does not like accessing a member |
1733 // that does not exist. | 1759 // that does not exist. |
1734 push(new js.PropertyAccess.field(pop(), 'toString'), node); | 1760 push(new js.PropertyAccess.field(pop(), 'toString') |
| 1761 .withSourceInformation(node.sourceInformation)); |
1735 } else if (element == backend.jsIndexableLength) { | 1762 } else if (element == backend.jsIndexableLength) { |
1736 // We're accessing a native JavaScript property called 'length' | 1763 // We're accessing a native JavaScript property called 'length' |
1737 // on a JS String or a JS array. Therefore, the name of that | 1764 // on a JS String or a JS array. Therefore, the name of that |
1738 // property should not be mangled. | 1765 // property should not be mangled. |
1739 push(new js.PropertyAccess.field(pop(), 'length'), node); | 1766 push(new js.PropertyAccess.field(pop(), 'length') |
| 1767 .withSourceInformation(node.sourceInformation)); |
1740 } else { | 1768 } else { |
1741 String name = backend.namer.instanceFieldPropertyName(element); | 1769 String name = backend.namer.instanceFieldPropertyName(element); |
1742 push(new js.PropertyAccess.field(pop(), name), node); | 1770 push(new js.PropertyAccess.field(pop(), name) |
| 1771 .withSourceInformation(node.sourceInformation)); |
1743 registry.registerFieldGetter(element); | 1772 registry.registerFieldGetter(element); |
1744 } | 1773 } |
1745 } | 1774 } |
1746 | 1775 |
1747 visitFieldSet(HFieldSet node) { | 1776 visitFieldSet(HFieldSet node) { |
1748 Element element = node.element; | 1777 Element element = node.element; |
1749 registry.registerFieldSetter(element); | 1778 registry.registerFieldSetter(element); |
1750 String name = backend.namer.instanceFieldPropertyName(element); | 1779 String name = backend.namer.instanceFieldPropertyName(element); |
1751 use(node.receiver); | 1780 use(node.receiver); |
1752 js.Expression receiver = pop(); | 1781 js.Expression receiver = pop(); |
1753 use(node.value); | 1782 use(node.value); |
1754 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()), | 1783 push(new js.Assignment(new js.PropertyAccess.field(receiver, name), pop()) |
1755 node); | 1784 .withSourceInformation(node.sourceInformation)); |
1756 } | 1785 } |
1757 | 1786 |
1758 visitReadModifyWrite(HReadModifyWrite node) { | 1787 visitReadModifyWrite(HReadModifyWrite node) { |
1759 Element element = node.element; | 1788 Element element = node.element; |
1760 registry.registerFieldSetter(element); | 1789 registry.registerFieldSetter(element); |
1761 String name = backend.namer.instanceFieldPropertyName(element); | 1790 String name = backend.namer.instanceFieldPropertyName(element); |
1762 use(node.receiver); | 1791 use(node.receiver); |
1763 js.Expression fieldReference = new js.PropertyAccess.field(pop(), name); | 1792 js.Expression fieldReference = new js.PropertyAccess.field(pop(), name); |
1764 if (node.isPreOp) { | 1793 if (node.isPreOp) { |
1765 push(new js.Prefix(node.jsOp, fieldReference), node); | 1794 push(new js.Prefix(node.jsOp, fieldReference) |
| 1795 .withSourceInformation(node.sourceInformation)); |
1766 } else if (node.isPostOp) { | 1796 } else if (node.isPostOp) { |
1767 push(new js.Postfix(node.jsOp, fieldReference), node); | 1797 push(new js.Postfix(node.jsOp, fieldReference) |
| 1798 .withSourceInformation(node.sourceInformation)); |
1768 } else { | 1799 } else { |
1769 use(node.value); | 1800 use(node.value); |
1770 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()), node); | 1801 push(new js.Assignment.compound(fieldReference, node.jsOp, pop()) |
| 1802 .withSourceInformation(node.sourceInformation)); |
1771 } | 1803 } |
1772 } | 1804 } |
1773 | 1805 |
1774 visitLocalGet(HLocalGet node) { | 1806 visitLocalGet(HLocalGet node) { |
1775 use(node.receiver); | 1807 use(node.receiver); |
1776 } | 1808 } |
1777 | 1809 |
1778 visitLocalSet(HLocalSet node) { | 1810 visitLocalSet(HLocalSet node) { |
1779 use(node.value); | 1811 use(node.value); |
1780 assignVariable(variableNames.getName(node.receiver), pop()); | 1812 assignVariable(variableNames.getName(node.receiver), |
| 1813 pop(), |
| 1814 node.sourceInformation); |
1781 } | 1815 } |
1782 | 1816 |
1783 void registerForeignTypes(HForeign node) { | 1817 void registerForeignTypes(HForeign node) { |
1784 native.NativeBehavior nativeBehavior = node.nativeBehavior; | 1818 native.NativeBehavior nativeBehavior = node.nativeBehavior; |
1785 if (nativeBehavior == null) return; | 1819 if (nativeBehavior == null) return; |
1786 nativeBehavior.typesReturned.forEach((type) { | 1820 nativeBehavior.typesReturned.forEach((type) { |
1787 if (type is InterfaceType) { | 1821 if (type is InterfaceType) { |
1788 registry.registerInstantiatedType(type); | 1822 registry.registerInstantiatedType(type); |
1789 } | 1823 } |
1790 }); | 1824 }); |
1791 } | 1825 } |
1792 | 1826 |
1793 visitForeignCode(HForeignCode node) { | 1827 visitForeignCode(HForeignCode node) { |
1794 List<HInstruction> inputs = node.inputs; | 1828 List<HInstruction> inputs = node.inputs; |
1795 if (node.isJsStatement()) { | 1829 if (node.isJsStatement()) { |
1796 List<js.Expression> interpolatedExpressions = <js.Expression>[]; | 1830 List<js.Expression> interpolatedExpressions = <js.Expression>[]; |
1797 for (int i = 0; i < inputs.length; i++) { | 1831 for (int i = 0; i < inputs.length; i++) { |
1798 use(inputs[i]); | 1832 use(inputs[i]); |
1799 interpolatedExpressions.add(pop()); | 1833 interpolatedExpressions.add(pop()); |
1800 } | 1834 } |
1801 pushStatement(node.codeTemplate.instantiate(interpolatedExpressions)); | 1835 pushStatement(node.codeTemplate.instantiate(interpolatedExpressions) |
| 1836 .withSourceInformation(node.sourceInformation)); |
1802 } else { | 1837 } else { |
1803 List<js.Expression> interpolatedExpressions = <js.Expression>[]; | 1838 List<js.Expression> interpolatedExpressions = <js.Expression>[]; |
1804 for (int i = 0; i < inputs.length; i++) { | 1839 for (int i = 0; i < inputs.length; i++) { |
1805 use(inputs[i]); | 1840 use(inputs[i]); |
1806 interpolatedExpressions.add(pop()); | 1841 interpolatedExpressions.add(pop()); |
1807 } | 1842 } |
1808 push(node.codeTemplate.instantiate(interpolatedExpressions)); | 1843 push(node.codeTemplate.instantiate(interpolatedExpressions) |
| 1844 .withSourceInformation(node.sourceInformation)); |
1809 } | 1845 } |
1810 | 1846 |
1811 // TODO(sra): Tell world.nativeEnqueuer about the types created here. | 1847 // TODO(sra): Tell world.nativeEnqueuer about the types created here. |
1812 registerForeignTypes(node); | 1848 registerForeignTypes(node); |
1813 } | 1849 } |
1814 | 1850 |
1815 visitForeignNew(HForeignNew node) { | 1851 visitForeignNew(HForeignNew node) { |
1816 js.Expression jsClassReference = | 1852 js.Expression jsClassReference = |
1817 backend.emitter.constructorAccess(node.element); | 1853 backend.emitter.constructorAccess(node.element); |
1818 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); | 1854 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); |
1819 push(new js.New(jsClassReference, arguments), node); | 1855 push(new js.New(jsClassReference, arguments) |
| 1856 .withSourceInformation(node.sourceInformation)); |
1820 registerForeignTypes(node); | 1857 registerForeignTypes(node); |
1821 // We also use ForeignNew to instantiate closure classes that belong to | 1858 // We also use ForeignNew to instantiate closure classes that belong to |
1822 // function expressions. We have to register their use here, as otherwise | 1859 // function expressions. We have to register their use here, as otherwise |
1823 // code for them might not be emitted. | 1860 // code for them might not be emitted. |
1824 if (node.element.isClosure) { | 1861 if (node.element.isClosure) { |
1825 registry.registerInstantiatedClass(node.element); | 1862 registry.registerInstantiatedClass(node.element); |
1826 } | 1863 } |
1827 if (node.instantiatedTypes == null) { | 1864 if (node.instantiatedTypes == null) { |
1828 return; | 1865 return; |
1829 } | 1866 } |
1830 node.instantiatedTypes.forEach((type) { | 1867 node.instantiatedTypes.forEach((type) { |
1831 registry.registerInstantiatedType(type); | 1868 registry.registerInstantiatedType(type); |
1832 }); | 1869 }); |
1833 } | 1870 } |
1834 | 1871 |
1835 js.Expression newLiteralBool(bool value) { | 1872 js.Expression newLiteralBool(bool value, |
| 1873 SourceInformation sourceInformation) { |
1836 if (compiler.enableMinification) { | 1874 if (compiler.enableMinification) { |
1837 // Use !0 for true, !1 for false. | 1875 // Use !0 for true, !1 for false. |
1838 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")); | 1876 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")) |
| 1877 .withSourceInformation(sourceInformation); |
1839 } else { | 1878 } else { |
1840 return new js.LiteralBool(value); | 1879 return new js.LiteralBool(value) |
| 1880 .withSourceInformation(sourceInformation); |
1841 } | 1881 } |
1842 } | 1882 } |
1843 | 1883 |
1844 void generateConstant(ConstantValue constant) { | 1884 void generateConstant(ConstantValue constant, |
| 1885 SourceInformation sourceInformation) { |
1845 if (constant.isFunction) { | 1886 if (constant.isFunction) { |
1846 FunctionConstantValue function = constant; | 1887 FunctionConstantValue function = constant; |
1847 registry.registerStaticUse(function.element); | 1888 registry.registerStaticUse(function.element); |
1848 } | 1889 } |
1849 if (constant.isType) { | 1890 if (constant.isType) { |
1850 // If the type is a web component, we need to ensure the constructors are | 1891 // If the type is a web component, we need to ensure the constructors are |
1851 // available to 'upgrade' the native object. | 1892 // available to 'upgrade' the native object. |
1852 TypeConstantValue type = constant; | 1893 TypeConstantValue type = constant; |
1853 Element element = type.representedType.element; | 1894 Element element = type.representedType.element; |
1854 if (element != null && element.isClass) { | 1895 if (element != null && element.isClass) { |
1855 registry.registerTypeConstant(element); | 1896 registry.registerTypeConstant(element); |
1856 } | 1897 } |
1857 } | 1898 } |
1858 push(backend.emitter.constantReference(constant)); | 1899 push(backend.emitter.constantReference(constant) |
| 1900 .withSourceInformation(sourceInformation)); |
1859 } | 1901 } |
1860 | 1902 |
1861 visitConstant(HConstant node) { | 1903 visitConstant(HConstant node) { |
1862 assert(isGenerateAtUseSite(node)); | 1904 assert(isGenerateAtUseSite(node)); |
1863 generateConstant(node.constant); | 1905 generateConstant(node.constant, node.sourceInformation); |
1864 | 1906 |
1865 registry.registerCompileTimeConstant(node.constant); | 1907 registry.registerCompileTimeConstant(node.constant); |
1866 backend.constants.addCompileTimeConstantForEmission(node.constant); | 1908 backend.constants.addCompileTimeConstantForEmission(node.constant); |
1867 } | 1909 } |
1868 | 1910 |
1869 visitNot(HNot node) { | 1911 visitNot(HNot node) { |
1870 assert(node.inputs.length == 1); | 1912 assert(node.inputs.length == 1); |
1871 generateNot(node.inputs[0]); | 1913 generateNot(node.inputs[0], node.sourceInformation); |
1872 attachLocationToLast(node); | |
1873 } | 1914 } |
1874 | 1915 |
1875 static String mapRelationalOperator(String op, bool inverse) { | 1916 static String mapRelationalOperator(String op, bool inverse) { |
1876 Map<String, String> inverseOperator = const <String, String>{ | 1917 Map<String, String> inverseOperator = const <String, String>{ |
1877 "==" : "!=", | 1918 "==" : "!=", |
1878 "!=" : "==", | 1919 "!=" : "==", |
1879 "===": "!==", | 1920 "===": "!==", |
1880 "!==": "===", | 1921 "!==": "===", |
1881 "<" : ">=", | 1922 "<" : ">=", |
1882 "<=" : ">", | 1923 "<=" : ">", |
1883 ">" : "<=", | 1924 ">" : "<=", |
1884 ">=" : "<" | 1925 ">=" : "<" |
1885 }; | 1926 }; |
1886 return inverse ? inverseOperator[op] : op; | 1927 return inverse ? inverseOperator[op] : op; |
1887 } | 1928 } |
1888 | 1929 |
1889 void generateNot(HInstruction input) { | 1930 void generateNot(HInstruction input, SourceInformation sourceInformation) { |
1890 bool canGenerateOptimizedComparison(HInstruction instruction) { | 1931 bool canGenerateOptimizedComparison(HInstruction instruction) { |
1891 if (instruction is !HRelational) return false; | 1932 if (instruction is !HRelational) return false; |
1892 | 1933 |
1893 HRelational relational = instruction; | 1934 HRelational relational = instruction; |
1894 | 1935 |
1895 HInstruction left = relational.left; | 1936 HInstruction left = relational.left; |
1896 HInstruction right = relational.right; | 1937 HInstruction right = relational.right; |
1897 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) { | 1938 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) { |
1898 return true; | 1939 return true; |
1899 } | 1940 } |
1900 | 1941 |
1901 // This optimization doesn't work for NaN, so we only do it if the | 1942 // This optimization doesn't work for NaN, so we only do it if the |
1902 // type is known to be an integer. | 1943 // type is known to be an integer. |
1903 return left.isInteger(compiler) && right.isInteger(compiler); | 1944 return left.isInteger(compiler) && right.isInteger(compiler); |
1904 } | 1945 } |
1905 | 1946 |
1906 bool handledBySpecialCase = false; | 1947 bool handledBySpecialCase = false; |
1907 if (isGenerateAtUseSite(input)) { | 1948 if (isGenerateAtUseSite(input)) { |
1908 handledBySpecialCase = true; | 1949 handledBySpecialCase = true; |
1909 if (input is HIs) { | 1950 if (input is HIs) { |
1910 emitIs(input, '!=='); | 1951 emitIs(input, '!==', sourceInformation); |
1911 } else if (input is HIsViaInterceptor) { | 1952 } else if (input is HIsViaInterceptor) { |
1912 emitIsViaInterceptor(input, true); | 1953 emitIsViaInterceptor(input, sourceInformation, negative: true); |
1913 } else if (input is HNot) { | 1954 } else if (input is HNot) { |
1914 use(input.inputs[0]); | 1955 use(input.inputs[0]); |
1915 } else if (input is HIdentity) { | 1956 } else if (input is HIdentity) { |
1916 emitIdentityComparison(input, true); | 1957 emitIdentityComparison(input, sourceInformation, inverse: true); |
1917 } else if (input is HBoolify) { | 1958 } else if (input is HBoolify) { |
1918 use(input.inputs[0]); | 1959 use(input.inputs[0]); |
1919 push(new js.Binary("!==", pop(), newLiteralBool(true)), input); | 1960 push(new js.Binary("!==", pop(), |
| 1961 newLiteralBool(true, input.sourceInformation)) |
| 1962 .withSourceInformation(sourceInformation)); |
1920 } else if (canGenerateOptimizedComparison(input)) { | 1963 } else if (canGenerateOptimizedComparison(input)) { |
1921 HRelational relational = input; | 1964 HRelational relational = input; |
1922 BinaryOperation operation = | 1965 BinaryOperation operation = |
1923 relational.operation(backend.constantSystem); | 1966 relational.operation(backend.constantSystem); |
1924 String op = mapRelationalOperator(operation.name, true); | 1967 String op = mapRelationalOperator(operation.name, true); |
1925 visitRelational(input, op); | 1968 handleInvokeBinary(input, op, sourceInformation); |
1926 } else { | 1969 } else { |
1927 handledBySpecialCase = false; | 1970 handledBySpecialCase = false; |
1928 } | 1971 } |
1929 } | 1972 } |
1930 if (!handledBySpecialCase) { | 1973 if (!handledBySpecialCase) { |
1931 use(input); | 1974 use(input); |
1932 push(new js.Prefix("!", pop())); | 1975 push(new js.Prefix("!", pop()).withSourceInformation(sourceInformation)); |
1933 } | 1976 } |
1934 } | 1977 } |
1935 | 1978 |
1936 visitParameterValue(HParameterValue node) { | 1979 visitParameterValue(HParameterValue node) { |
1937 assert(!isGenerateAtUseSite(node)); | 1980 assert(!isGenerateAtUseSite(node)); |
1938 String name = variableNames.getName(node); | 1981 String name = variableNames.getName(node); |
1939 parameters.add(new js.Parameter(name)); | 1982 parameters.add(new js.Parameter(name)); |
1940 declaredLocals.add(name); | 1983 declaredLocals.add(name); |
1941 } | 1984 } |
1942 | 1985 |
(...skipping 10 matching lines...) Expand all Loading... |
1953 HBasicBlock ifBlock = node.block.dominator; | 1996 HBasicBlock ifBlock = node.block.dominator; |
1954 assert(controlFlowOperators.contains(ifBlock.last)); | 1997 assert(controlFlowOperators.contains(ifBlock.last)); |
1955 HInstruction input = ifBlock.last.inputs[0]; | 1998 HInstruction input = ifBlock.last.inputs[0]; |
1956 if (input.isConstantFalse()) { | 1999 if (input.isConstantFalse()) { |
1957 use(node.inputs[1]); | 2000 use(node.inputs[1]); |
1958 } else if (input.isConstantTrue()) { | 2001 } else if (input.isConstantTrue()) { |
1959 use(node.inputs[0]); | 2002 use(node.inputs[0]); |
1960 } else if (node.inputs[1].isConstantBoolean()) { | 2003 } else if (node.inputs[1].isConstantBoolean()) { |
1961 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; | 2004 String operation = node.inputs[1].isConstantFalse() ? '&&' : '||'; |
1962 if (operation == '||') { | 2005 if (operation == '||') { |
1963 generateNot(input); | 2006 generateNot(input, input.sourceInformation); |
1964 } else { | 2007 } else { |
1965 use(input); | 2008 use(input); |
1966 } | 2009 } |
1967 js.Expression left = pop(); | 2010 js.Expression left = pop(); |
1968 use(node.inputs[0]); | 2011 use(node.inputs[0]); |
1969 push(new js.Binary(operation, left, pop())); | 2012 push(new js.Binary(operation, left, pop())); |
1970 } else { | 2013 } else { |
1971 use(input); | 2014 use(input); |
1972 js.Expression test = pop(); | 2015 js.Expression test = pop(); |
1973 use(node.inputs[0]); | 2016 use(node.inputs[0]); |
1974 js.Expression then = pop(); | 2017 js.Expression then = pop(); |
1975 use(node.inputs[1]); | 2018 use(node.inputs[1]); |
1976 push(new js.Conditional(test, then, pop())); | 2019 push(new js.Conditional(test, then, pop())); |
1977 } | 2020 } |
1978 } | 2021 } |
1979 | 2022 |
1980 visitReturn(HReturn node) { | 2023 visitReturn(HReturn node) { |
1981 assert(node.inputs.length == 1); | 2024 assert(node.inputs.length == 1); |
1982 HInstruction input = node.inputs[0]; | 2025 HInstruction input = node.inputs[0]; |
1983 if (input.isConstantNull()) { | 2026 if (input.isConstantNull()) { |
1984 pushStatement(new js.Return(null), node); | 2027 pushStatement(new js.Return() |
| 2028 .withSourceInformation(node.sourceInformation)); |
1985 } else { | 2029 } else { |
1986 use(node.inputs[0]); | 2030 use(node.inputs[0]); |
1987 pushStatement(new js.Return(pop()), node); | 2031 pushStatement(new js.Return(pop()) |
| 2032 .withSourceInformation(node.sourceInformation)); |
1988 } | 2033 } |
1989 } | 2034 } |
1990 | 2035 |
1991 visitThis(HThis node) { | 2036 visitThis(HThis node) { |
1992 push(new js.This()); | 2037 push(new js.This()); |
1993 } | 2038 } |
1994 | 2039 |
1995 visitThrow(HThrow node) { | 2040 visitThrow(HThrow node) { |
1996 if (node.isRethrow) { | 2041 if (node.isRethrow) { |
1997 use(node.inputs[0]); | 2042 use(node.inputs[0]); |
1998 pushStatement(new js.Throw(pop()), node); | 2043 pushStatement(new js.Throw(pop()) |
| 2044 .withSourceInformation(node.sourceInformation)); |
1999 } else { | 2045 } else { |
2000 generateThrowWithHelper('wrapException', node.inputs[0]); | 2046 generateThrowWithHelper('wrapException', node.inputs[0], |
| 2047 sourceInformation: node.sourceInformation); |
2001 } | 2048 } |
2002 } | 2049 } |
2003 | 2050 |
2004 visitAwait(HAwait node) { | 2051 visitAwait(HAwait node) { |
2005 use(node.inputs[0]); | 2052 use(node.inputs[0]); |
2006 push(new js.Await(pop()), node); | 2053 push(new js.Await(pop()) |
| 2054 .withSourceInformation(node.sourceInformation)); |
2007 } | 2055 } |
2008 | 2056 |
2009 visitYield(HYield node) { | 2057 visitYield(HYield node) { |
2010 use(node.inputs[0]); | 2058 use(node.inputs[0]); |
2011 pushStatement(new js.DartYield(pop(), node.hasStar), node); | 2059 pushStatement(new js.DartYield(pop(), node.hasStar) |
| 2060 .withSourceInformation(node.sourceInformation)); |
2012 } | 2061 } |
2013 | 2062 |
2014 visitRangeConversion(HRangeConversion node) { | 2063 visitRangeConversion(HRangeConversion node) { |
2015 // Range conversion instructions are removed by the value range | 2064 // Range conversion instructions are removed by the value range |
2016 // analyzer. | 2065 // analyzer. |
2017 assert(false); | 2066 assert(false); |
2018 } | 2067 } |
2019 | 2068 |
2020 visitBoundsCheck(HBoundsCheck node) { | 2069 visitBoundsCheck(HBoundsCheck node) { |
2021 // TODO(ngeoffray): Separate the two checks of the bounds check, so, | 2070 // TODO(ngeoffray): Separate the two checks of the bounds check, so, |
(...skipping 29 matching lines...) Expand all Loading... |
2051 ? over | 2100 ? over |
2052 : over == null | 2101 : over == null |
2053 ? under | 2102 ? under |
2054 : new js.Binary("||", under, over); | 2103 : new js.Binary("||", under, over); |
2055 js.Statement thenBody = new js.Block.empty(); | 2104 js.Statement thenBody = new js.Block.empty(); |
2056 js.Block oldContainer = currentContainer; | 2105 js.Block oldContainer = currentContainer; |
2057 currentContainer = thenBody; | 2106 currentContainer = thenBody; |
2058 generateThrowWithHelper('ioore', [node.array, node.index]); | 2107 generateThrowWithHelper('ioore', [node.array, node.index]); |
2059 currentContainer = oldContainer; | 2108 currentContainer = oldContainer; |
2060 thenBody = unwrapStatement(thenBody); | 2109 thenBody = unwrapStatement(thenBody); |
2061 pushStatement(new js.If.noElse(underOver, thenBody), node); | 2110 pushStatement(new js.If.noElse(underOver, thenBody) |
| 2111 .withSourceInformation(node.sourceInformation)); |
2062 } else { | 2112 } else { |
2063 generateThrowWithHelper('ioore', [node.array, node.index]); | 2113 generateThrowWithHelper('ioore', [node.array, node.index]); |
2064 } | 2114 } |
2065 } | 2115 } |
2066 | 2116 |
2067 void generateThrowWithHelper(String helperName, argument) { | 2117 void generateThrowWithHelper(String helperName, argument, |
| 2118 {SourceInformation sourceInformation}) { |
2068 Element helper = backend.findHelper(helperName); | 2119 Element helper = backend.findHelper(helperName); |
2069 registry.registerStaticUse(helper); | 2120 registry.registerStaticUse(helper); |
2070 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2121 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2071 List arguments = []; | 2122 List arguments = []; |
2072 var location; | 2123 var location; |
2073 if (argument is List) { | 2124 if (argument is List) { |
2074 location = argument[0]; | 2125 location = argument[0]; |
2075 argument.forEach((instruction) { | 2126 argument.forEach((instruction) { |
2076 use(instruction); | 2127 use(instruction); |
2077 arguments.add(pop()); | 2128 arguments.add(pop()); |
2078 }); | 2129 }); |
2079 } else { | 2130 } else { |
2080 location = argument; | 2131 location = argument; |
2081 use(argument); | 2132 use(argument); |
2082 arguments.add(pop()); | 2133 arguments.add(pop()); |
2083 } | 2134 } |
2084 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false)); | 2135 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), |
2085 value = attachLocation(value, location); | 2136 sourceInformation: sourceInformation); |
2086 // BUG(4906): Using throw/return here adds to the size of the generated code | 2137 // BUG(4906): Using throw/return here adds to the size of the generated code |
2087 // but it has the advantage of explicitly telling the JS engine that | 2138 // but it has the advantage of explicitly telling the JS engine that |
2088 // this code path will terminate abruptly. Needs more work. | 2139 // this code path will terminate abruptly. Needs more work. |
2089 if (helperName == 'wrapException') { | 2140 if (helperName == 'wrapException') { |
2090 pushStatement(new js.Throw(value)); | 2141 pushStatement(new js.Throw(value) |
| 2142 .withSourceInformation(sourceInformation)); |
2091 } else { | 2143 } else { |
2092 Element element = work.element; | 2144 Element element = work.element; |
2093 if (element is FunctionElement && element.asyncMarker.isYielding) { | 2145 if (element is FunctionElement && element.asyncMarker.isYielding) { |
2094 // `return <expr>;` is illegal in a sync* or async* function. | 2146 // `return <expr>;` is illegal in a sync* or async* function. |
2095 // To have the the async-translator working, we avoid introducing | 2147 // To have the the async-translator working, we avoid introducing |
2096 // `return` nodes. | 2148 // `return` nodes. |
2097 pushStatement(new js.ExpressionStatement(value)); | 2149 pushStatement(new js.ExpressionStatement(value) |
| 2150 .withSourceInformation(sourceInformation)); |
2098 } else { | 2151 } else { |
2099 pushStatement(new js.Return(value)); | 2152 pushStatement(new js.Return(value) |
| 2153 .withSourceInformation(sourceInformation)); |
2100 } | 2154 } |
2101 } | 2155 } |
2102 } | 2156 } |
2103 | 2157 |
2104 visitThrowExpression(HThrowExpression node) { | 2158 visitThrowExpression(HThrowExpression node) { |
2105 HInstruction argument = node.inputs[0]; | 2159 HInstruction argument = node.inputs[0]; |
2106 use(argument); | 2160 use(argument); |
2107 | 2161 |
2108 Element helper = backend.findHelper("throwExpression"); | 2162 Element helper = backend.findHelper("throwExpression"); |
2109 registry.registerStaticUse(helper); | 2163 registry.registerStaticUse(helper); |
2110 | 2164 |
2111 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); | 2165 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); |
2112 js.Call value = new js.Call(jsHelper, [pop()]); | 2166 js.Call value = new js.Call(jsHelper, [pop()]) |
2113 value = attachLocation(value, argument); | 2167 .withSourceInformation(node.sourceInformation); |
2114 push(value, node); | 2168 push(value); |
2115 } | 2169 } |
2116 | 2170 |
2117 void visitSwitch(HSwitch node) { | 2171 void visitSwitch(HSwitch node) { |
2118 // Switches are handled using [visitSwitchInfo]. | 2172 // Switches are handled using [visitSwitchInfo]. |
2119 } | 2173 } |
2120 | 2174 |
2121 void visitStatic(HStatic node) { | 2175 void visitStatic(HStatic node) { |
2122 Element element = node.element; | 2176 Element element = node.element; |
2123 assert(element.isFunction || element.isField); | 2177 assert(element.isFunction || element.isField); |
2124 if (element.isFunction) { | 2178 if (element.isFunction) { |
2125 push(backend.emitter.isolateStaticClosureAccess(node.element)); | 2179 push(backend.emitter.isolateStaticClosureAccess(node.element) |
| 2180 .withSourceInformation(node.sourceInformation)); |
2126 } else { | 2181 } else { |
2127 push(backend.emitter.staticFieldAccess(node.element)); | 2182 push(backend.emitter.staticFieldAccess(node.element) |
| 2183 .withSourceInformation(node.sourceInformation)); |
2128 } | 2184 } |
2129 registry.registerStaticUse(element); | 2185 registry.registerStaticUse(element); |
2130 } | 2186 } |
2131 | 2187 |
2132 void visitLazyStatic(HLazyStatic node) { | 2188 void visitLazyStatic(HLazyStatic node) { |
2133 Element element = node.element; | 2189 Element element = node.element; |
2134 registry.registerStaticUse(element); | 2190 registry.registerStaticUse(element); |
2135 js.Expression lazyGetter = | 2191 js.Expression lazyGetter = |
2136 backend.emitter.isolateLazyInitializerAccess(element); | 2192 backend.emitter.isolateLazyInitializerAccess(element); |
2137 js.Call call = new js.Call(lazyGetter, <js.Expression>[]); | 2193 js.Call call = new js.Call(lazyGetter, <js.Expression>[], |
2138 push(call, node); | 2194 sourceInformation: node.sourceInformation); |
| 2195 push(call); |
2139 } | 2196 } |
2140 | 2197 |
2141 void visitStaticStore(HStaticStore node) { | 2198 void visitStaticStore(HStaticStore node) { |
2142 registry.registerStaticUse(node.element); | 2199 registry.registerStaticUse(node.element); |
2143 js.Node variable = backend.emitter.staticFieldAccess(node.element); | 2200 js.Node variable = backend.emitter.staticFieldAccess(node.element); |
2144 use(node.inputs[0]); | 2201 use(node.inputs[0]); |
2145 push(new js.Assignment(variable, pop()), node); | 2202 push(new js.Assignment(variable, pop()) |
| 2203 .withSourceInformation(node.sourceInformation)); |
2146 } | 2204 } |
2147 | 2205 |
2148 void visitStringConcat(HStringConcat node) { | 2206 void visitStringConcat(HStringConcat node) { |
2149 use(node.left); | 2207 use(node.left); |
2150 js.Expression jsLeft = pop(); | 2208 js.Expression jsLeft = pop(); |
2151 use(node.right); | 2209 use(node.right); |
2152 push(new js.Binary('+', jsLeft, pop()), node); | 2210 push(new js.Binary('+', jsLeft, pop()) |
| 2211 .withSourceInformation(node.sourceInformation)); |
2153 } | 2212 } |
2154 | 2213 |
2155 void visitStringify(HStringify node) { | 2214 void visitStringify(HStringify node) { |
2156 HInstruction input = node.inputs.first; | 2215 HInstruction input = node.inputs.first; |
2157 if (input.isString(compiler)) { | 2216 if (input.isString(compiler)) { |
2158 use(input); | 2217 use(input); |
2159 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) { | 2218 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) { |
2160 // JavaScript's + operator with a string for the left operand will convert | 2219 // JavaScript's + operator with a string for the left operand will convert |
2161 // the right operand to a string, and the conversion result is correct. | 2220 // the right operand to a string, and the conversion result is correct. |
2162 use(input); | 2221 use(input); |
2163 if (node.usedBy.length == 1 | 2222 if (node.usedBy.length == 1 |
2164 && node.usedBy[0] is HStringConcat | 2223 && node.usedBy[0] is HStringConcat |
2165 && node.usedBy[0].inputs[1] == node) { | 2224 && node.usedBy[0].inputs[1] == node) { |
2166 // The context is already <string> + value. | 2225 // The context is already <string> + value. |
2167 } else { | 2226 } else { |
2168 // Force an empty string for the first operand. | 2227 // Force an empty string for the first operand. |
2169 push(new js.Binary('+', js.string(""), pop()), node); | 2228 push(new js.Binary('+', js.string(""), pop()) |
| 2229 .withSourceInformation(node.sourceInformation)); |
2170 } | 2230 } |
2171 } else { | 2231 } else { |
2172 Element convertToString = backend.getStringInterpolationHelper(); | 2232 Element convertToString = backend.getStringInterpolationHelper(); |
2173 registry.registerStaticUse(convertToString); | 2233 registry.registerStaticUse(convertToString); |
2174 js.Expression jsHelper = | 2234 js.Expression jsHelper = |
2175 backend.emitter.staticFunctionAccess(convertToString); | 2235 backend.emitter.staticFunctionAccess(convertToString); |
2176 use(input); | 2236 use(input); |
2177 push(new js.Call(jsHelper, <js.Expression>[pop()]), node); | 2237 push(new js.Call(jsHelper, <js.Expression>[pop()], |
| 2238 sourceInformation: node.sourceInformation)); |
2178 } | 2239 } |
2179 } | 2240 } |
2180 | 2241 |
2181 void visitLiteralList(HLiteralList node) { | 2242 void visitLiteralList(HLiteralList node) { |
2182 registry.registerInstantiatedClass(compiler.listClass); | 2243 registry.registerInstantiatedClass(compiler.listClass); |
2183 generateArrayLiteral(node); | 2244 generateArrayLiteral(node); |
2184 } | 2245 } |
2185 | 2246 |
2186 void generateArrayLiteral(HLiteralList node) { | 2247 void generateArrayLiteral(HLiteralList node) { |
2187 List<js.Expression> elements = node.inputs.map((HInstruction input) { | 2248 List<js.Expression> elements = node.inputs.map((HInstruction input) { |
2188 use(input); | 2249 use(input); |
2189 return pop(); | 2250 return pop(); |
2190 }).toList(); | 2251 }).toList(); |
2191 push(new js.ArrayInitializer(elements), node); | 2252 push(new js.ArrayInitializer(elements) |
| 2253 .withSourceInformation(node.sourceInformation)); |
2192 } | 2254 } |
2193 | 2255 |
2194 void visitIndex(HIndex node) { | 2256 void visitIndex(HIndex node) { |
2195 use(node.receiver); | 2257 use(node.receiver); |
2196 js.Expression receiver = pop(); | 2258 js.Expression receiver = pop(); |
2197 use(node.index); | 2259 use(node.index); |
2198 push(new js.PropertyAccess(receiver, pop()), node); | 2260 push(new js.PropertyAccess(receiver, pop()) |
| 2261 .withSourceInformation(node.sourceInformation)); |
2199 } | 2262 } |
2200 | 2263 |
2201 void visitIndexAssign(HIndexAssign node) { | 2264 void visitIndexAssign(HIndexAssign node) { |
2202 use(node.receiver); | 2265 use(node.receiver); |
2203 js.Expression receiver = pop(); | 2266 js.Expression receiver = pop(); |
2204 use(node.index); | 2267 use(node.index); |
2205 js.Expression index = pop(); | 2268 js.Expression index = pop(); |
2206 use(node.value); | 2269 use(node.value); |
2207 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()), | 2270 push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()) |
2208 node); | 2271 .withSourceInformation(node.sourceInformation)); |
2209 } | 2272 } |
2210 | 2273 |
2211 void checkInt(HInstruction input, String cmp) { | 2274 void checkInt(HInstruction input, String cmp) { |
2212 use(input); | 2275 use(input); |
2213 js.Expression left = pop(); | 2276 js.Expression left = pop(); |
2214 use(input); | 2277 use(input); |
2215 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); | 2278 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); |
2216 push(new js.Binary(cmp, left, or0)); | 2279 push(new js.Binary(cmp, left, or0)); |
2217 } | 2280 } |
2218 | 2281 |
2219 void checkBigInt(HInstruction input, String cmp) { | 2282 void checkBigInt(HInstruction input, String cmp, |
| 2283 SourceInformation sourceInformation) { |
2220 use(input); | 2284 use(input); |
2221 js.Expression left = pop(); | 2285 js.Expression left = pop(); |
2222 use(input); | 2286 use(input); |
2223 js.Expression right = pop(); | 2287 js.Expression right = pop(); |
2224 // TODO(4984): Deal with infinity and -0.0. | 2288 // TODO(4984): Deal with infinity and -0.0. |
2225 push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right])); | 2289 push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right]) |
| 2290 .withSourceInformation(sourceInformation)); |
2226 } | 2291 } |
2227 | 2292 |
2228 void checkTypeOf(HInstruction input, String cmp, String typeName) { | 2293 void checkTypeOf(HInstruction input, String cmp, String typeName, |
| 2294 SourceInformation sourceInformation) { |
2229 use(input); | 2295 use(input); |
2230 js.Expression typeOf = new js.Prefix("typeof", pop()); | 2296 js.Expression typeOf = new js.Prefix("typeof", pop()); |
2231 push(new js.Binary(cmp, typeOf, js.string(typeName))); | 2297 push(new js.Binary(cmp, typeOf, js.string(typeName))); |
2232 } | 2298 } |
2233 | 2299 |
2234 void checkNum(HInstruction input, String cmp) | 2300 void checkNum(HInstruction input, String cmp, |
2235 => checkTypeOf(input, cmp, 'number'); | 2301 SourceInformation sourceInformation) { |
| 2302 return checkTypeOf(input, cmp, 'number', sourceInformation); |
| 2303 } |
2236 | 2304 |
2237 void checkDouble(HInstruction input, String cmp) => checkNum(input, cmp); | 2305 void checkDouble(HInstruction input, String cmp, |
| 2306 SourceInformation sourceInformation) { |
| 2307 return checkNum(input, cmp, sourceInformation); |
| 2308 } |
2238 | 2309 |
2239 void checkString(HInstruction input, String cmp) | 2310 void checkString(HInstruction input, String cmp, |
2240 => checkTypeOf(input, cmp, 'string'); | 2311 SourceInformation sourceInformation) { |
| 2312 return checkTypeOf(input, cmp, 'string', sourceInformation); |
| 2313 } |
2241 | 2314 |
2242 void checkBool(HInstruction input, String cmp) | 2315 void checkBool(HInstruction input, String cmp, |
2243 => checkTypeOf(input, cmp, 'boolean'); | 2316 SourceInformation sourceInformation) { |
| 2317 return checkTypeOf(input, cmp, 'boolean', sourceInformation); |
| 2318 } |
2244 | 2319 |
2245 void checkObject(HInstruction input, String cmp) { | 2320 void checkObject(HInstruction input, String cmp, |
| 2321 SourceInformation sourceInformation) { |
2246 assert(NullConstantValue.JsNull == 'null'); | 2322 assert(NullConstantValue.JsNull == 'null'); |
2247 if (cmp == "===") { | 2323 if (cmp == "===") { |
2248 checkTypeOf(input, '===', 'object'); | 2324 checkTypeOf(input, '===', 'object', sourceInformation); |
2249 js.Expression left = pop(); | 2325 js.Expression left = pop(); |
2250 use(input); | 2326 use(input); |
2251 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); | 2327 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); |
2252 push(new js.Binary("&&", left, notNull)); | 2328 push(new js.Binary("&&", left, notNull) |
| 2329 .withSourceInformation(sourceInformation)); |
2253 } else { | 2330 } else { |
2254 assert(cmp == "!=="); | 2331 assert(cmp == "!=="); |
2255 checkTypeOf(input, '!==', 'object'); | 2332 checkTypeOf(input, '!==', 'object', sourceInformation); |
2256 js.Expression left = pop(); | 2333 js.Expression left = pop(); |
2257 use(input); | 2334 use(input); |
2258 js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull()); | 2335 js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull()); |
2259 push(new js.Binary("||", left, eqNull)); | 2336 push(new js.Binary("||", left, eqNull) |
| 2337 .withSourceInformation(sourceInformation)); |
2260 } | 2338 } |
2261 } | 2339 } |
2262 | 2340 |
2263 void checkArray(HInstruction input, String cmp) { | 2341 void checkArray(HInstruction input, String cmp) { |
2264 use(input); | 2342 use(input); |
2265 js.PropertyAccess constructor = | 2343 js.PropertyAccess constructor = |
2266 new js.PropertyAccess.field(pop(), 'constructor'); | 2344 new js.PropertyAccess.field(pop(), 'constructor'); |
2267 push(new js.Binary(cmp, constructor, new js.VariableUse('Array'))); | 2345 push(new js.Binary(cmp, constructor, new js.VariableUse('Array'))); |
2268 } | 2346 } |
2269 | 2347 |
(...skipping 30 matching lines...) Expand all Loading... |
2300 use(input); | 2378 use(input); |
2301 push(new js.Binary('==', pop(), new js.LiteralNull())); | 2379 push(new js.Binary('==', pop(), new js.LiteralNull())); |
2302 } | 2380 } |
2303 | 2381 |
2304 void checkNonNull(HInstruction input) { | 2382 void checkNonNull(HInstruction input) { |
2305 use(input); | 2383 use(input); |
2306 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2384 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
2307 } | 2385 } |
2308 | 2386 |
2309 void checkType(HInstruction input, HInstruction interceptor, | 2387 void checkType(HInstruction input, HInstruction interceptor, |
2310 DartType type, {bool negative: false}) { | 2388 DartType type, |
| 2389 SourceInformation sourceInformation, |
| 2390 {bool negative: false}) { |
2311 Element element = type.element; | 2391 Element element = type.element; |
2312 if (element == backend.jsArrayClass) { | 2392 if (element == backend.jsArrayClass) { |
2313 checkArray(input, negative ? '!==': '==='); | 2393 checkArray(input, negative ? '!==': '==='); |
2314 return; | 2394 return; |
2315 } else if (element == backend.jsMutableArrayClass) { | 2395 } else if (element == backend.jsMutableArrayClass) { |
2316 if (negative) { | 2396 if (negative) { |
2317 checkImmutableArray(input); | 2397 checkImmutableArray(input); |
2318 } else { | 2398 } else { |
2319 checkMutableArray(input); | 2399 checkMutableArray(input); |
2320 } | 2400 } |
(...skipping 14 matching lines...) Expand all Loading... |
2335 return; | 2415 return; |
2336 } else if (element == backend.jsUnmodifiableArrayClass) { | 2416 } else if (element == backend.jsUnmodifiableArrayClass) { |
2337 if (negative) { | 2417 if (negative) { |
2338 checkMutableArray(input); | 2418 checkMutableArray(input); |
2339 } else { | 2419 } else { |
2340 checkImmutableArray(input); | 2420 checkImmutableArray(input); |
2341 } | 2421 } |
2342 return; | 2422 return; |
2343 } | 2423 } |
2344 if (interceptor != null) { | 2424 if (interceptor != null) { |
2345 checkTypeViaProperty(interceptor, type, negative); | 2425 checkTypeViaProperty(interceptor, type, sourceInformation, |
| 2426 negative: negative); |
2346 } else { | 2427 } else { |
2347 checkTypeViaProperty(input, type, negative); | 2428 checkTypeViaProperty(input, type, sourceInformation, negative: negative); |
2348 } | 2429 } |
2349 } | 2430 } |
2350 | 2431 |
2351 void checkTypeViaProperty(HInstruction input, DartType type, bool negative) { | 2432 void checkTypeViaProperty(HInstruction input, DartType type, |
| 2433 SourceInformation sourceInformation, |
| 2434 {bool negative: false}) { |
2352 registry.registerIsCheck(type); | 2435 registry.registerIsCheck(type); |
2353 | 2436 |
2354 use(input); | 2437 use(input); |
2355 | 2438 |
2356 js.PropertyAccess field = | 2439 js.PropertyAccess field = |
2357 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); | 2440 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)) |
| 2441 .withSourceInformation(sourceInformation); |
2358 // We always negate at least once so that the result is boolified. | 2442 // We always negate at least once so that the result is boolified. |
2359 push(new js.Prefix('!', field)); | 2443 push(new js.Prefix('!', field) |
| 2444 .withSourceInformation(sourceInformation)); |
2360 // If the result is not negated, put another '!' in front. | 2445 // If the result is not negated, put another '!' in front. |
2361 if (!negative) push(new js.Prefix('!', pop())); | 2446 if (!negative) { |
| 2447 push(new js.Prefix('!', pop()) |
| 2448 .withSourceInformation(sourceInformation)); |
| 2449 } |
2362 } | 2450 } |
2363 | 2451 |
2364 void checkTypeViaInstanceof( | 2452 void checkTypeViaInstanceof( |
2365 HInstruction input, DartType type, bool negative) { | 2453 HInstruction input, DartType type, |
| 2454 SourceInformation sourceInformation, |
| 2455 {bool negative: false}) { |
2366 registry.registerIsCheck(type); | 2456 registry.registerIsCheck(type); |
2367 | 2457 |
2368 use(input); | 2458 use(input); |
2369 | 2459 |
2370 js.Expression jsClassReference = | 2460 js.Expression jsClassReference = |
2371 backend.emitter.constructorAccess(type.element); | 2461 backend.emitter.constructorAccess(type.element); |
2372 push(js.js('# instanceof #', [pop(), jsClassReference])); | 2462 push(js.js('# instanceof #', [pop(), jsClassReference]) |
2373 if (negative) push(new js.Prefix('!', pop())); | 2463 .withSourceInformation(sourceInformation)); |
| 2464 if (negative) { |
| 2465 push(new js.Prefix('!', pop()) |
| 2466 .withSourceInformation(sourceInformation)); |
| 2467 } |
2374 registry.registerInstantiatedType(type); | 2468 registry.registerInstantiatedType(type); |
2375 } | 2469 } |
2376 | 2470 |
2377 void handleNumberOrStringSupertypeCheck(HInstruction input, | 2471 void handleNumberOrStringSupertypeCheck(HInstruction input, |
2378 HInstruction interceptor, | 2472 HInstruction interceptor, |
2379 DartType type, | 2473 DartType type, |
2380 { bool negative: false }) { | 2474 SourceInformation sourceInformation, |
2381 assert(!identical(type.element, compiler.listClass) | 2475 {bool negative: false}) { |
2382 && !Elements.isListSupertype(type.element, compiler) | 2476 assert(!identical(type.element, compiler.listClass) && |
2383 && !Elements.isStringOnlySupertype(type.element, compiler)); | 2477 !Elements.isListSupertype(type.element, compiler) && |
| 2478 !Elements.isStringOnlySupertype(type.element, compiler)); |
2384 String relation = negative ? '!==' : '==='; | 2479 String relation = negative ? '!==' : '==='; |
2385 checkNum(input, relation); | 2480 checkNum(input, relation, sourceInformation); |
2386 js.Expression numberTest = pop(); | 2481 js.Expression numberTest = pop(); |
2387 checkString(input, relation); | 2482 checkString(input, relation, sourceInformation); |
2388 js.Expression stringTest = pop(); | 2483 js.Expression stringTest = pop(); |
2389 checkObject(input, relation); | 2484 checkObject(input, relation, sourceInformation); |
2390 js.Expression objectTest = pop(); | 2485 js.Expression objectTest = pop(); |
2391 checkType(input, interceptor, type, negative: negative); | 2486 checkType(input, interceptor, type, sourceInformation, negative: negative); |
2392 String combiner = negative ? '&&' : '||'; | 2487 String combiner = negative ? '&&' : '||'; |
2393 String combiner2 = negative ? '||' : '&&'; | 2488 String combiner2 = negative ? '||' : '&&'; |
2394 push(new js.Binary(combiner, | 2489 push(new js.Binary(combiner, |
2395 new js.Binary(combiner, numberTest, stringTest), | 2490 new js.Binary(combiner, numberTest, stringTest) |
2396 new js.Binary(combiner2, objectTest, pop()))); | 2491 .withSourceInformation(sourceInformation), |
| 2492 new js.Binary(combiner2, objectTest, pop()) |
| 2493 .withSourceInformation(sourceInformation)) |
| 2494 .withSourceInformation(sourceInformation)); |
2397 } | 2495 } |
2398 | 2496 |
2399 void handleStringSupertypeCheck(HInstruction input, | 2497 void handleStringSupertypeCheck(HInstruction input, |
2400 HInstruction interceptor, | 2498 HInstruction interceptor, |
2401 DartType type, | 2499 DartType type, |
2402 { bool negative: false }) { | 2500 SourceInformation sourceInformation, |
| 2501 {bool negative: false}) { |
2403 assert(!identical(type.element, compiler.listClass) | 2502 assert(!identical(type.element, compiler.listClass) |
2404 && !Elements.isListSupertype(type.element, compiler) | 2503 && !Elements.isListSupertype(type.element, compiler) |
2405 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2504 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
2406 String relation = negative ? '!==' : '==='; | 2505 String relation = negative ? '!==' : '==='; |
2407 checkString(input, relation); | 2506 checkString(input, relation, sourceInformation); |
2408 js.Expression stringTest = pop(); | 2507 js.Expression stringTest = pop(); |
2409 checkObject(input, relation); | 2508 checkObject(input, relation, sourceInformation); |
2410 js.Expression objectTest = pop(); | 2509 js.Expression objectTest = pop(); |
2411 checkType(input, interceptor, type, negative: negative); | 2510 checkType(input, interceptor, type, sourceInformation, negative: negative); |
2412 String combiner = negative ? '||' : '&&'; | 2511 String combiner = negative ? '||' : '&&'; |
2413 push(new js.Binary(negative ? '&&' : '||', | 2512 push(new js.Binary(negative ? '&&' : '||', |
2414 stringTest, | 2513 stringTest, |
2415 new js.Binary(combiner, objectTest, pop()))); | 2514 new js.Binary(combiner, objectTest, pop()))); |
2416 } | 2515 } |
2417 | 2516 |
2418 void handleListOrSupertypeCheck(HInstruction input, | 2517 void handleListOrSupertypeCheck(HInstruction input, |
2419 HInstruction interceptor, | 2518 HInstruction interceptor, |
2420 DartType type, | 2519 DartType type, |
| 2520 SourceInformation sourceInformation, |
2421 { bool negative: false }) { | 2521 { bool negative: false }) { |
2422 assert(!identical(type.element, compiler.stringClass) | 2522 assert(!identical(type.element, compiler.stringClass) |
2423 && !Elements.isStringOnlySupertype(type.element, compiler) | 2523 && !Elements.isStringOnlySupertype(type.element, compiler) |
2424 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2524 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
2425 String relation = negative ? '!==' : '==='; | 2525 String relation = negative ? '!==' : '==='; |
2426 checkObject(input, relation); | 2526 checkObject(input, relation, sourceInformation); |
2427 js.Expression objectTest = pop(); | 2527 js.Expression objectTest = pop(); |
2428 checkArray(input, relation); | 2528 checkArray(input, relation); |
2429 js.Expression arrayTest = pop(); | 2529 js.Expression arrayTest = pop(); |
2430 checkType(input, interceptor, type, negative: negative); | 2530 checkType(input, interceptor, type, sourceInformation, negative: negative); |
2431 String combiner = negative ? '&&' : '||'; | 2531 String combiner = negative ? '&&' : '||'; |
2432 push(new js.Binary(negative ? '||' : '&&', | 2532 push(new js.Binary(negative ? '||' : '&&', |
2433 objectTest, | 2533 objectTest, |
2434 new js.Binary(combiner, arrayTest, pop()))); | 2534 new js.Binary(combiner, arrayTest, pop())) |
| 2535 .withSourceInformation(sourceInformation)); |
2435 } | 2536 } |
2436 | 2537 |
2437 void visitIs(HIs node) { | 2538 void visitIs(HIs node) { |
2438 emitIs(node, "==="); | 2539 emitIs(node, "===", node.sourceInformation); |
2439 } | 2540 } |
2440 | 2541 |
2441 void visitIsViaInterceptor(HIsViaInterceptor node) { | 2542 void visitIsViaInterceptor(HIsViaInterceptor node) { |
2442 emitIsViaInterceptor(node, false); | 2543 emitIsViaInterceptor(node, node.sourceInformation, negative: false); |
2443 } | 2544 } |
2444 | 2545 |
2445 void emitIs(HIs node, String relation) { | 2546 void emitIs(HIs node, String relation, SourceInformation sourceInformation) { |
2446 DartType type = node.typeExpression; | 2547 DartType type = node.typeExpression; |
2447 registry.registerIsCheck(type); | 2548 registry.registerIsCheck(type); |
2448 HInstruction input = node.expression; | 2549 HInstruction input = node.expression; |
2449 | 2550 |
2450 // If this is changed to single == there are several places below that must | 2551 // If this is changed to single == there are several places below that must |
2451 // be changed to match. | 2552 // be changed to match. |
2452 assert(relation == '===' || relation == '!=='); | 2553 assert(relation == '===' || relation == '!=='); |
2453 bool negative = relation == '!=='; | 2554 bool negative = relation == '!=='; |
2454 | 2555 |
2455 if (node.isVariableCheck || node.isCompoundCheck) { | 2556 if (node.isVariableCheck || node.isCompoundCheck) { |
2456 use(node.checkCall); | 2557 use(node.checkCall); |
2457 if (negative) push(new js.Prefix('!', pop())); | 2558 if (negative) push(new js.Prefix('!', pop())); |
2458 } else { | 2559 } else { |
2459 assert(node.isRawCheck); | 2560 assert(node.isRawCheck); |
2460 HInstruction interceptor = node.interceptor; | 2561 HInstruction interceptor = node.interceptor; |
2461 ClassElement objectClass = compiler.objectClass; | 2562 ClassElement objectClass = compiler.objectClass; |
2462 Element element = type.element; | 2563 Element element = type.element; |
2463 if (element == compiler.nullClass) { | 2564 if (element == compiler.nullClass) { |
2464 if (negative) { | 2565 if (negative) { |
2465 checkNonNull(input); | 2566 checkNonNull(input); |
2466 } else { | 2567 } else { |
2467 checkNull(input); | 2568 checkNull(input); |
2468 } | 2569 } |
2469 } else if (identical(element, objectClass) || type.treatAsDynamic) { | 2570 } else if (identical(element, objectClass) || type.treatAsDynamic) { |
2470 // The constant folder also does this optimization, but we make | 2571 // The constant folder also does this optimization, but we make |
2471 // it safe by assuming it may have not run. | 2572 // it safe by assuming it may have not run. |
2472 push(newLiteralBool(!negative), node); | 2573 push(newLiteralBool(!negative, sourceInformation)); |
2473 } else if (element == compiler.stringClass) { | 2574 } else if (element == compiler.stringClass) { |
2474 checkString(input, relation); | 2575 checkString(input, relation, sourceInformation); |
2475 attachLocationToLast(node); | |
2476 } else if (element == compiler.doubleClass) { | 2576 } else if (element == compiler.doubleClass) { |
2477 checkDouble(input, relation); | 2577 checkDouble(input, relation, sourceInformation); |
2478 attachLocationToLast(node); | |
2479 } else if (element == compiler.numClass) { | 2578 } else if (element == compiler.numClass) { |
2480 checkNum(input, relation); | 2579 checkNum(input, relation, sourceInformation); |
2481 attachLocationToLast(node); | |
2482 } else if (element == compiler.boolClass) { | 2580 } else if (element == compiler.boolClass) { |
2483 checkBool(input, relation); | 2581 checkBool(input, relation, sourceInformation); |
2484 attachLocationToLast(node); | |
2485 } else if (element == compiler.intClass) { | 2582 } else if (element == compiler.intClass) { |
2486 // The is check in the code tells us that it might not be an | 2583 // The is check in the code tells us that it might not be an |
2487 // int. So we do a typeof first to avoid possible | 2584 // int. So we do a typeof first to avoid possible |
2488 // deoptimizations on the JS engine due to the Math.floor check. | 2585 // deoptimizations on the JS engine due to the Math.floor check. |
2489 checkNum(input, relation); | 2586 checkNum(input, relation, sourceInformation); |
2490 js.Expression numTest = pop(); | 2587 js.Expression numTest = pop(); |
2491 checkBigInt(input, relation); | 2588 checkBigInt(input, relation, sourceInformation); |
2492 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); | 2589 push(new js.Binary(negative ? '||' : '&&', numTest, pop()) |
| 2590 .withSourceInformation(sourceInformation)); |
2493 } else if (node.useInstanceOf) { | 2591 } else if (node.useInstanceOf) { |
2494 assert(interceptor == null); | 2592 assert(interceptor == null); |
2495 checkTypeViaInstanceof(input, type, negative); | 2593 checkTypeViaInstanceof(input, type, |
2496 attachLocationToLast(node); | 2594 sourceInformation, |
| 2595 negative: negative); |
2497 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { | 2596 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { |
2498 handleNumberOrStringSupertypeCheck( | 2597 handleNumberOrStringSupertypeCheck( |
2499 input, interceptor, type, negative: negative); | 2598 input, interceptor, type, |
2500 attachLocationToLast(node); | 2599 sourceInformation, |
| 2600 negative: negative); |
2501 } else if (Elements.isStringOnlySupertype(element, compiler)) { | 2601 } else if (Elements.isStringOnlySupertype(element, compiler)) { |
2502 handleStringSupertypeCheck( | 2602 handleStringSupertypeCheck( |
2503 input, interceptor, type, negative: negative); | 2603 input, interceptor, type, |
2504 attachLocationToLast(node); | 2604 sourceInformation, |
2505 } else if (identical(element, compiler.listClass) | 2605 negative: negative); |
2506 || Elements.isListSupertype(element, compiler)) { | 2606 } else if (identical(element, compiler.listClass) || |
| 2607 Elements.isListSupertype(element, compiler)) { |
2507 handleListOrSupertypeCheck( | 2608 handleListOrSupertypeCheck( |
2508 input, interceptor, type, negative: negative); | 2609 input, interceptor, type, |
2509 attachLocationToLast(node); | 2610 sourceInformation, |
| 2611 negative: negative); |
2510 } else if (type.isFunctionType) { | 2612 } else if (type.isFunctionType) { |
2511 checkType(input, interceptor, type, negative: negative); | 2613 checkType(input, interceptor, type, |
2512 attachLocationToLast(node); | 2614 sourceInformation, |
| 2615 negative: negative); |
2513 } else if ((input.canBePrimitive(compiler) | 2616 } else if ((input.canBePrimitive(compiler) |
2514 && !input.canBePrimitiveArray(compiler)) | 2617 && !input.canBePrimitiveArray(compiler)) |
2515 || input.canBeNull()) { | 2618 || input.canBeNull()) { |
2516 checkObject(input, relation); | 2619 checkObject(input, relation, node.sourceInformation); |
2517 js.Expression objectTest = pop(); | 2620 js.Expression objectTest = pop(); |
2518 checkType(input, interceptor, type, negative: negative); | 2621 checkType(input, interceptor, type, |
2519 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); | 2622 sourceInformation, |
| 2623 negative: negative); |
| 2624 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()) |
| 2625 .withSourceInformation(sourceInformation)); |
2520 } else { | 2626 } else { |
2521 checkType(input, interceptor, type, negative: negative); | 2627 checkType(input, interceptor, type, |
2522 attachLocationToLast(node); | 2628 sourceInformation, |
| 2629 negative: negative); |
2523 } | 2630 } |
2524 } | 2631 } |
2525 } | 2632 } |
2526 | 2633 |
2527 void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) { | 2634 void emitIsViaInterceptor(HIsViaInterceptor node, |
2528 checkTypeViaProperty(node.interceptor, node.typeExpression, negative); | 2635 SourceInformation sourceInformation, |
2529 attachLocationToLast(node); | 2636 {bool negative: false}) { |
| 2637 checkTypeViaProperty(node.interceptor, node.typeExpression, |
| 2638 sourceInformation, |
| 2639 negative: negative); |
2530 } | 2640 } |
2531 | 2641 |
2532 js.Expression generateReceiverOrArgumentTypeTest( | 2642 js.Expression generateReceiverOrArgumentTypeTest( |
2533 HInstruction input, TypeMask checkedType) { | 2643 HInstruction input, TypeMask checkedType) { |
2534 ClassWorld classWorld = compiler.world; | 2644 ClassWorld classWorld = compiler.world; |
2535 TypeMask inputType = input.instructionType; | 2645 TypeMask inputType = input.instructionType; |
2536 // Figure out if it is beneficial to turn this into a null check. | 2646 // Figure out if it is beneficial to turn this into a null check. |
2537 // V8 generally prefers 'typeof' checks, but for integers and | 2647 // V8 generally prefers 'typeof' checks, but for integers and |
2538 // indexable primitives we cannot compile this test into a single | 2648 // indexable primitives we cannot compile this test into a single |
2539 // typeof check so the null check is cheaper. | 2649 // typeof check so the null check is cheaper. |
2540 bool isIntCheck = checkedType.containsOnlyInt(classWorld); | 2650 bool isIntCheck = checkedType.containsOnlyInt(classWorld); |
2541 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); | 2651 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); |
2542 bool turnIntoNullCheck = !turnIntoNumCheck | 2652 bool turnIntoNullCheck = !turnIntoNumCheck |
2543 && (checkedType.nullable() == inputType) | 2653 && (checkedType.nullable() == inputType) |
2544 && (isIntCheck | 2654 && (isIntCheck |
2545 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); | 2655 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); |
2546 | 2656 |
2547 if (turnIntoNullCheck) { | 2657 if (turnIntoNullCheck) { |
2548 use(input); | 2658 use(input); |
2549 return new js.Binary("==", pop(), new js.LiteralNull()); | 2659 return new js.Binary("==", pop(), new js.LiteralNull()) |
| 2660 .withSourceInformation(input.sourceInformation); |
2550 } else if (isIntCheck && !turnIntoNumCheck) { | 2661 } else if (isIntCheck && !turnIntoNumCheck) { |
2551 // input is !int | 2662 // input is !int |
2552 checkBigInt(input, '!=='); | 2663 checkBigInt(input, '!==', input.sourceInformation); |
2553 return pop(); | 2664 return pop(); |
2554 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { | 2665 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { |
2555 // input is !num | 2666 // input is !num |
2556 checkNum(input, '!=='); | 2667 checkNum(input, '!==', input.sourceInformation); |
2557 return pop(); | 2668 return pop(); |
2558 } else if (checkedType.containsOnlyBool(classWorld)) { | 2669 } else if (checkedType.containsOnlyBool(classWorld)) { |
2559 // input is !bool | 2670 // input is !bool |
2560 checkBool(input, '!=='); | 2671 checkBool(input, '!==', input.sourceInformation); |
2561 return pop(); | 2672 return pop(); |
2562 } else if (checkedType.containsOnlyString(classWorld)) { | 2673 } else if (checkedType.containsOnlyString(classWorld)) { |
2563 // input is !string | 2674 // input is !string |
2564 checkString(input, '!=='); | 2675 checkString(input, '!==', input.sourceInformation); |
2565 return pop(); | 2676 return pop(); |
2566 } | 2677 } |
2567 compiler.internalError(input, 'Unexpected check.'); | 2678 compiler.internalError(input, 'Unexpected check.'); |
2568 return null; | 2679 return null; |
2569 } | 2680 } |
2570 | 2681 |
2571 void visitTypeConversion(HTypeConversion node) { | 2682 void visitTypeConversion(HTypeConversion node) { |
2572 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { | 2683 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
2573 ClassWorld classWorld = compiler.world; | 2684 ClassWorld classWorld = compiler.world; |
2574 // An int check if the input is not int or null, is not | 2685 // An int check if the input is not int or null, is not |
(...skipping 10 matching lines...) Expand all Loading... |
2585 generateThrowWithHelper('iae', node.checkedInput); | 2696 generateThrowWithHelper('iae', node.checkedInput); |
2586 } else if (node.isReceiverTypeCheck) { | 2697 } else if (node.isReceiverTypeCheck) { |
2587 use(node.checkedInput); | 2698 use(node.checkedInput); |
2588 String methodName = | 2699 String methodName = |
2589 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2700 backend.namer.invocationName(node.receiverTypeCheckSelector); |
2590 js.Expression call = js.propertyCall(pop(), methodName, []); | 2701 js.Expression call = js.propertyCall(pop(), methodName, []); |
2591 pushStatement(new js.Return(call)); | 2702 pushStatement(new js.Return(call)); |
2592 } | 2703 } |
2593 currentContainer = oldContainer; | 2704 currentContainer = oldContainer; |
2594 body = unwrapStatement(body); | 2705 body = unwrapStatement(body); |
2595 pushStatement(new js.If.noElse(test, body), node); | 2706 pushStatement(new js.If.noElse(test, body) |
| 2707 .withSourceInformation(node.sourceInformation)); |
2596 return; | 2708 return; |
2597 } | 2709 } |
2598 | 2710 |
2599 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2711 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
2600 DartType type = node.typeExpression; | 2712 DartType type = node.typeExpression; |
2601 assert(type.kind != TypeKind.TYPEDEF); | 2713 assert(type.kind != TypeKind.TYPEDEF); |
2602 if (type.isFunctionType) { | 2714 if (type.isFunctionType) { |
2603 // TODO(5022): We currently generate $isFunction checks for | 2715 // TODO(5022): We currently generate $isFunction checks for |
2604 // function types. | 2716 // function types. |
2605 registry.registerIsCheck(compiler.functionClass.rawType); | 2717 registry.registerIsCheck(compiler.functionClass.rawType); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2725 js.PropertyAccess accessHelper(String name) { | 2837 js.PropertyAccess accessHelper(String name) { |
2726 Element helper = backend.findHelper(name); | 2838 Element helper = backend.findHelper(name); |
2727 if (helper == null) { | 2839 if (helper == null) { |
2728 // For mocked-up tests. | 2840 // For mocked-up tests. |
2729 return js.js('(void 0).$name'); | 2841 return js.js('(void 0).$name'); |
2730 } | 2842 } |
2731 registry.registerStaticUse(helper); | 2843 registry.registerStaticUse(helper); |
2732 return backend.emitter.staticFunctionAccess(helper); | 2844 return backend.emitter.staticFunctionAccess(helper); |
2733 } | 2845 } |
2734 } | 2846 } |
OLD | NEW |