| 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 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler); | 6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler); |
| 7 String get name() => 'SSA code generator'; | 7 String get name() => 'SSA code generator'; |
| 8 | 8 |
| 9 | 9 |
| 10 String buildJavaScriptFunction(FunctionElement element, | 10 String buildJavaScriptFunction(FunctionElement element, |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 buffer.add(variableName); | 509 buffer.add(variableName); |
| 510 if (!isGeneratingDeclaration()) { | 510 if (!isGeneratingDeclaration()) { |
| 511 delayedVarDecl = delayedVarDecl.prepend(variableName); | 511 delayedVarDecl = delayedVarDecl.prepend(variableName); |
| 512 } | 512 } |
| 513 } else { | 513 } else { |
| 514 buffer.add("var "); | 514 buffer.add("var "); |
| 515 buffer.add(variableName); | 515 buffer.add(variableName); |
| 516 } | 516 } |
| 517 } | 517 } |
| 518 | 518 |
| 519 bool needsNewVariable(HInstruction instruction) { |
| 520 bool needsVar = !instruction.usedBy.isEmpty(); |
| 521 if (needsVar && instruction is HCheck) { |
| 522 HCheck check = instruction; |
| 523 HInstruction input = check.checkedInput; |
| 524 // We only need a new var if [input] is generated at use site |
| 525 // but is not a trivial code motion invariant instruction like |
| 526 // for parameters or this. |
| 527 // |
| 528 // For example: |
| 529 // Foo a = this; |
| 530 // print(a); |
| 531 // print(a); |
| 532 // |
| 533 // In checked mode no new variable is needed. |
| 534 // FooTypeCheck(this); |
| 535 // print(this); |
| 536 // print(this); |
| 537 // |
| 538 // But for this example: |
| 539 // Foo a = foo(); |
| 540 // print(a); |
| 541 // print(a); |
| 542 // |
| 543 // We need a new variable: |
| 544 // var a = FooTypeCheck(foo()); |
| 545 // print(a); |
| 546 // print(a); |
| 547 needsVar = isGenerateAtUseSite(input) && !input.isCodeMotionInvariant(); |
| 548 } |
| 549 return needsVar; |
| 550 } |
| 551 |
| 519 void define(HInstruction instruction) { | 552 void define(HInstruction instruction) { |
| 520 String name = temporary(instruction); | 553 if (needsNewVariable(instruction)) { |
| 521 declareVariable(name); | 554 String name = temporary(instruction); |
| 522 buffer.add(" = "); | 555 declareVariable(name); |
| 523 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 556 buffer.add(" = "); |
| 557 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 558 } else { |
| 559 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 560 } |
| 524 } | 561 } |
| 525 | 562 |
| 526 void use(HInstruction argument, int expectedPrecedenceForArgument) { | 563 void use(HInstruction argument, int expectedPrecedenceForArgument) { |
| 527 if (isGenerateAtUseSite(argument)) { | 564 if (argument is HCheck) { |
| 565 HCheck instruction = argument; |
| 566 HInstruction input = instruction.checkedInput; |
| 567 if (isGenerateAtUseSite(argument) && isGenerateAtUseSite(input)) { |
| 568 // If both instructions can be generated at use site, we can |
| 569 // just visit [argument]. |
| 570 // |
| 571 // For example: |
| 572 // Foo a = foo(); |
| 573 // print(a); |
| 574 // |
| 575 // In checked mode will turn into: |
| 576 // print(FooTypeCheck(foo())); |
| 577 visit(argument, expectedPrecedenceForArgument); |
| 578 } else if (isGenerateAtUseSite(input)) { |
| 579 // If [argument] cannot be generated at use site, but [input] |
| 580 // can, use the temporary of [argument]. A code motion |
| 581 // invariant instruction does not have a temporary, so we just |
| 582 // |
| 583 // For example: |
| 584 // Foo a = foo(); |
| 585 // print(a); |
| 586 // print(a); |
| 587 // |
| 588 // In checked mode will turn into: |
| 589 // var a = FooTypeCheck(foo()); |
| 590 // print(a); |
| 591 // print(a); |
| 592 // |
| 593 // Note that in case the input is code motion invariant, like |
| 594 // for parameters or this, we just need to visit it, since |
| 595 // there is no temporary for such instruction. |
| 596 if (input.isCodeMotionInvariant()) { |
| 597 visit(input, expectedPrecedenceForArgument); |
| 598 } else { |
| 599 buffer.add(temporary(argument)); |
| 600 } |
| 601 } else { |
| 602 // Otherwise we just use [input]. [argument] has already been |
| 603 // emitted, and we just need the temporary of [input]. |
| 604 // |
| 605 // For example: |
| 606 // var a = foo(); |
| 607 // print(a); |
| 608 // Foo b = a; |
| 609 // print(b); |
| 610 // |
| 611 // In checked mode will turn into: |
| 612 // var a = foo(); |
| 613 // print(a); |
| 614 // FooTypeCheck(a); |
| 615 // print(a); |
| 616 use(input, expectedPrecedenceForArgument); |
| 617 } |
| 618 } else if (isGenerateAtUseSite(argument)) { |
| 528 visit(argument, expectedPrecedenceForArgument); | 619 visit(argument, expectedPrecedenceForArgument); |
| 529 } else if (argument is HIntegerCheck) { | |
| 530 HIntegerCheck instruction = argument; | |
| 531 use(instruction.value, expectedPrecedenceForArgument); | |
| 532 } else if (argument is HBoundsCheck) { | |
| 533 HBoundsCheck instruction = argument; | |
| 534 use(instruction.index, expectedPrecedenceForArgument); | |
| 535 } else if (argument is HTypeGuard) { | |
| 536 HTypeGuard instruction = argument; | |
| 537 use(instruction.guarded, expectedPrecedenceForArgument); | |
| 538 } else { | 620 } else { |
| 539 buffer.add(temporary(argument)); | 621 buffer.add(temporary(argument)); |
| 540 } | 622 } |
| 541 } | 623 } |
| 542 | 624 |
| 543 visit(HInstruction node, int expectedPrecedenceForNode) { | 625 visit(HInstruction node, int expectedPrecedenceForNode) { |
| 544 int oldPrecedence = this.expectedPrecedence; | 626 int oldPrecedence = this.expectedPrecedence; |
| 545 this.expectedPrecedence = expectedPrecedenceForNode; | 627 this.expectedPrecedence = expectedPrecedenceForNode; |
| 546 node.accept(this); | 628 node.accept(this); |
| 547 this.expectedPrecedence = oldPrecedence; | 629 this.expectedPrecedence = oldPrecedence; |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1059 } | 1141 } |
| 1060 } | 1142 } |
| 1061 | 1143 |
| 1062 void iterateBasicBlock(HBasicBlock node) { | 1144 void iterateBasicBlock(HBasicBlock node) { |
| 1063 HInstruction instruction = node.first; | 1145 HInstruction instruction = node.first; |
| 1064 while (instruction != null) { | 1146 while (instruction != null) { |
| 1065 if (instruction === node.last) { | 1147 if (instruction === node.last) { |
| 1066 assignPhisOfAllSuccessors(node); | 1148 assignPhisOfAllSuccessors(node); |
| 1067 } | 1149 } |
| 1068 | 1150 |
| 1069 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 1151 if (isGenerateAtUseSite(instruction)) { |
| 1152 if (instruction is HIf) { |
| 1153 HIf hif = instruction; |
| 1154 // The "if" is implementing part of a logical expression. |
| 1155 // Skip directly forward to to its latest successor, since everything |
| 1156 // in-between must also be generateAtUseSite. |
| 1157 assert(hif.trueBranch.id < hif.falseBranch.id); |
| 1158 visitBasicBlock(hif.falseBranch); |
| 1159 } |
| 1160 } else if (instruction is HControlFlow) { |
| 1161 if (instruction is HLoopBranch && isGeneratingExpression()) { |
| 1162 addExpressionSeparator(); |
| 1163 } |
| 1070 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1164 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1071 return; | 1165 } else if (instruction is HTypeGuard) { |
| 1072 } else if (!isGenerateAtUseSite(instruction)) { | 1166 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1073 if (instruction is !HIf | 1167 } else { |
| 1074 && instruction is !HTypeGuard | 1168 if (isGeneratingExpression()) { |
| 1075 && instruction is !HLoopBranch | 1169 addExpressionSeparator(); |
| 1076 && !isGeneratingExpression()) { | 1170 } else { |
| 1077 addIndentation(); | 1171 addIndentation(); |
| 1078 } | 1172 } |
| 1079 if (isGeneratingExpression()) { | 1173 define(instruction); |
| 1080 addExpressionSeparator(); | 1174 if (!isGeneratingExpression()) buffer.add(';\n'); |
| 1081 } | |
| 1082 if (instruction.usedBy.isEmpty() | |
| 1083 || instruction is HTypeGuard | |
| 1084 || instruction is HCheck) { | |
| 1085 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | |
| 1086 } else { | |
| 1087 define(instruction); | |
| 1088 } | |
| 1089 // Control flow instructions, and some other instructions, | |
| 1090 // know how to handle ';'. | |
| 1091 if (instruction is !HControlFlow | |
| 1092 && instruction is !HTypeGuard | |
| 1093 && !isGeneratingExpression()) { | |
| 1094 buffer.add(';\n'); | |
| 1095 } | |
| 1096 } else if (instruction is HIf) { | |
| 1097 HIf hif = instruction; | |
| 1098 // The "if" is implementing part of a logical expression. | |
| 1099 // Skip directly forward to to its latest successor, since everything | |
| 1100 // in-between must also be generateAtUseSite. | |
| 1101 assert(hif.trueBranch.id < hif.falseBranch.id); | |
| 1102 visitBasicBlock(hif.falseBranch); | |
| 1103 return; | |
| 1104 } | 1175 } |
| 1105 instruction = instruction.next; | 1176 instruction = instruction.next; |
| 1106 } | 1177 } |
| 1107 } | 1178 } |
| 1108 | 1179 |
| 1109 visitInvokeBinary(HInvokeBinary node, String op) { | 1180 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1110 if (node.builtin) { | 1181 if (node.builtin) { |
| 1111 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; | 1182 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; |
| 1112 beginExpression(operatorPrecedences.precedence); | 1183 beginExpression(operatorPrecedences.precedence); |
| 1113 use(node.left, operatorPrecedences.left); | 1184 use(node.left, operatorPrecedences.left); |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1645 String operation = logicalOperations[node]; | 1716 String operation = logicalOperations[node]; |
| 1646 if (operation !== null) { | 1717 if (operation !== null) { |
| 1647 emitLogicalOperation(node, operation); | 1718 emitLogicalOperation(node, operation); |
| 1648 } else { | 1719 } else { |
| 1649 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); | 1720 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); |
| 1650 buffer.add('${temporary(canonicalPhi)}'); | 1721 buffer.add('${temporary(canonicalPhi)}'); |
| 1651 } | 1722 } |
| 1652 } | 1723 } |
| 1653 | 1724 |
| 1654 visitReturn(HReturn node) { | 1725 visitReturn(HReturn node) { |
| 1726 addIndentation(); |
| 1655 assert(node.inputs.length == 1); | 1727 assert(node.inputs.length == 1); |
| 1656 HInstruction input = node.inputs[0]; | 1728 HInstruction input = node.inputs[0]; |
| 1657 if (input.isConstantNull()) { | 1729 if (input.isConstantNull()) { |
| 1658 buffer.add('return;\n'); | 1730 buffer.add('return;\n'); |
| 1659 } else { | 1731 } else { |
| 1660 buffer.add('return '); | 1732 buffer.add('return '); |
| 1661 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1733 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1662 buffer.add(';\n'); | 1734 buffer.add(';\n'); |
| 1663 } | 1735 } |
| 1664 } | 1736 } |
| 1665 | 1737 |
| 1666 visitThis(HThis node) { | 1738 visitThis(HThis node) { |
| 1667 buffer.add('this'); | 1739 buffer.add('this'); |
| 1668 } | 1740 } |
| 1669 | 1741 |
| 1670 visitThrow(HThrow node) { | 1742 visitThrow(HThrow node) { |
| 1743 addIndentation(); |
| 1671 if (node.isRethrow) { | 1744 if (node.isRethrow) { |
| 1672 buffer.add('throw '); | 1745 buffer.add('throw '); |
| 1673 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1746 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1674 } else { | 1747 } else { |
| 1675 generateThrowWithHelper('captureStackTrace', node.inputs[0]); | 1748 generateThrowWithHelper('captureStackTrace', node.inputs[0]); |
| 1676 } | 1749 } |
| 1677 buffer.add(';\n'); | 1750 buffer.add(';\n'); |
| 1678 } | 1751 } |
| 1679 | 1752 |
| 1680 visitBoundsCheck(HBoundsCheck node) { | 1753 visitBoundsCheck(HBoundsCheck node) { |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2107 } else if (nativeCheck) { | 2180 } else if (nativeCheck) { |
| 2108 helper = const SourceString('callTypeCheck'); | 2181 helper = const SourceString('callTypeCheck'); |
| 2109 } else { | 2182 } else { |
| 2110 helper = const SourceString('propertyTypeCheck'); | 2183 helper = const SourceString('propertyTypeCheck'); |
| 2111 } | 2184 } |
| 2112 } | 2185 } |
| 2113 Element helperElement = compiler.findHelper(helper); | 2186 Element helperElement = compiler.findHelper(helper); |
| 2114 compiler.registerStaticUse(helperElement); | 2187 compiler.registerStaticUse(helperElement); |
| 2115 buffer.add(compiler.namer.isolateAccess(helperElement)); | 2188 buffer.add(compiler.namer.isolateAccess(helperElement)); |
| 2116 buffer.add('('); | 2189 buffer.add('('); |
| 2117 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 2190 use(node.checkedInput, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2118 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); | 2191 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); |
| 2119 buffer.add(')'); | 2192 buffer.add(')'); |
| 2120 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2193 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2121 } else { | 2194 } else { |
| 2122 use(node.inputs[0], expectedPrecedence); | 2195 visit(node.checkedInput, expectedPrecedence); |
| 2123 } | 2196 } |
| 2124 } | 2197 } |
| 2125 } | 2198 } |
| 2126 | 2199 |
| 2127 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2200 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2128 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2201 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) |
| 2129 : super(compiler, work, parameters, parameterNames); | 2202 : super(compiler, work, parameters, parameterNames); |
| 2130 | 2203 |
| 2131 void beginGraph(HGraph graph) {} | 2204 void beginGraph(HGraph graph) {} |
| 2132 void endGraph(HGraph graph) {} | 2205 void endGraph(HGraph graph) {} |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2521 startBailoutSwitch(); | 2594 startBailoutSwitch(); |
| 2522 } | 2595 } |
| 2523 } | 2596 } |
| 2524 | 2597 |
| 2525 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2598 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2526 if (labeledBlockInfo.body.start.hasGuards()) { | 2599 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2527 endBailoutSwitch(); | 2600 endBailoutSwitch(); |
| 2528 } | 2601 } |
| 2529 } | 2602 } |
| 2530 } | 2603 } |
| OLD | NEW |