Chromium Code Reviews| 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 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 void define(HInstruction instruction) { | 519 void define(HInstruction instruction) { |
| 520 String name = temporary(instruction); | 520 bool needsVar = !instruction.usedBy.isEmpty(); |
| 521 declareVariable(name); | 521 if (needsVar) { |
| 522 buffer.add(" = "); | 522 if (instruction.returnsInput()) { |
|
Lasse Reichstein Nielsen
2012/05/08 12:39:08
Use single if with '&&'.
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 523 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 523 HInstruction input = instruction.input; |
| 524 // We only need a new var if [input] is generated at use site | |
| 525 // but is not a trivial code motion invariant instruction (eg | |
|
floitsch
2012/05/08 13:21:42
"like for". There is enough space.
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 526 // parameters or this). | |
| 527 // | |
| 528 // For example: | |
| 529 // Foo a = this; | |
| 530 // print(a); | |
| 531 // print(a); | |
| 532 // | |
| 533 // In checked mode does not need a new variable: | |
|
floitsch
2012/05/08 13:21:42
In checked mode no new variable is needed:
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 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(); | |
|
floitsch
2012/05/08 13:21:42
If I understand correctly it is crucial that 'defi
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 548 } | |
| 549 } | |
| 550 if (needsVar) { | |
| 551 String name = temporary(instruction); | |
| 552 declareVariable(name); | |
| 553 buffer.add(" = "); | |
| 554 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 555 } else { | |
| 556 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | |
| 557 } | |
| 524 } | 558 } |
| 525 | 559 |
| 526 void use(HInstruction argument, int expectedPrecedenceForArgument) { | 560 void use(HInstruction argument, int expectedPrecedenceForArgument) { |
| 527 if (isGenerateAtUseSite(argument)) { | 561 if (argument.returnsInput()) { |
| 562 HInstruction input = argument.input; | |
| 563 if (isGenerateAtUseSite(argument) && isGenerateAtUseSite(input)) { | |
| 564 // If both instructions can be generated at use site, we can | |
| 565 // just visit [argument]. | |
| 566 // | |
| 567 // For example: | |
| 568 // Foo a = foo(); | |
| 569 // print(a); | |
| 570 // | |
| 571 // In checked mode will turn into: | |
| 572 // print(FooTypeCheck(foo())); | |
| 573 visit(argument, expectedPrecedenceForArgument); | |
| 574 } else if (isGenerateAtUseSite(input) && !input.isCodeMotionInvariant()) { | |
|
Lasse Reichstein Nielsen
2012/05/08 12:39:08
Please explain the use of isCodeMotionInvariant.
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 575 // If [argument] cannot be generated at use site, but [input] | |
| 576 // can, use the temporary of [argument]. | |
| 577 // | |
| 578 // For example: | |
| 579 // Foo a = foo(); | |
| 580 // print(a); | |
| 581 // print(a); | |
| 582 // | |
| 583 // In checked mode will turn into: | |
| 584 // var a = FooTypeCheck(foo()); | |
| 585 // print(a); | |
| 586 // print(a); | |
| 587 buffer.add(temporary(argument)); | |
| 588 } else { | |
| 589 // Otherwise we just use [input]. | |
|
Lasse Reichstein Nielsen
2012/05/08 12:39:08
Please give example of output here too.
What happe
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 590 use(input, expectedPrecedenceForArgument); | |
| 591 } | |
| 592 } else if (isGenerateAtUseSite(argument)) { | |
| 528 visit(argument, expectedPrecedenceForArgument); | 593 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 { | 594 } else { |
| 539 buffer.add(temporary(argument)); | 595 buffer.add(temporary(argument)); |
| 540 } | 596 } |
| 541 } | 597 } |
| 542 | 598 |
| 543 visit(HInstruction node, int expectedPrecedenceForNode) { | 599 visit(HInstruction node, int expectedPrecedenceForNode) { |
| 544 int oldPrecedence = this.expectedPrecedence; | 600 int oldPrecedence = this.expectedPrecedence; |
| 545 this.expectedPrecedence = expectedPrecedenceForNode; | 601 this.expectedPrecedence = expectedPrecedenceForNode; |
| 546 node.accept(this); | 602 node.accept(this); |
| 547 this.expectedPrecedence = oldPrecedence; | 603 this.expectedPrecedence = oldPrecedence; |
| (...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1056 } | 1112 } |
| 1057 } | 1113 } |
| 1058 | 1114 |
| 1059 void iterateBasicBlock(HBasicBlock node) { | 1115 void iterateBasicBlock(HBasicBlock node) { |
| 1060 HInstruction instruction = node.first; | 1116 HInstruction instruction = node.first; |
| 1061 while (instruction != null) { | 1117 while (instruction != null) { |
| 1062 if (instruction === node.last) { | 1118 if (instruction === node.last) { |
| 1063 assignPhisOfAllSuccessors(node); | 1119 assignPhisOfAllSuccessors(node); |
| 1064 } | 1120 } |
| 1065 | 1121 |
| 1066 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 1122 if (isGenerateAtUseSite(instruction)) { |
| 1067 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1123 if (instruction is HIf) { |
| 1068 return; | 1124 HIf hif = instruction; |
| 1069 } else if (!isGenerateAtUseSite(instruction)) { | 1125 // The "if" is implementing part of a logical expression. |
| 1070 if (instruction is !HIf | 1126 // Skip directly forward to to its latest successor, since everything |
| 1071 && instruction is !HTypeGuard | 1127 // in-between must also be generateAtUseSite. |
| 1072 && instruction is !HLoopBranch | 1128 assert(hif.trueBranch.id < hif.falseBranch.id); |
| 1073 && !isGeneratingExpression()) { | 1129 visitBasicBlock(hif.falseBranch); |
| 1074 addIndentation(); | |
| 1075 } | 1130 } |
| 1076 if (isGeneratingExpression()) { | 1131 } else if (instruction is HControlFlow) { |
| 1132 if (instruction is HLoopBranch && isGeneratingExpression()) { | |
| 1077 addExpressionSeparator(); | 1133 addExpressionSeparator(); |
| 1078 } | 1134 } |
| 1079 if (instruction.usedBy.isEmpty() | 1135 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1080 || instruction is HTypeGuard | 1136 } else if (instruction is HTypeGuard) { |
| 1081 || instruction is HCheck) { | 1137 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 1082 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 1138 } else { |
| 1083 } else { | 1139 isGeneratingExpression() ? addExpressionSeparator() : addIndentation(); |
|
Lasse Reichstein Nielsen
2012/05/08 12:39:08
Use if. Please don't (try) to be clever with the c
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 1084 define(instruction); | 1140 define(instruction); |
| 1085 } | 1141 if (!isGeneratingExpression()) buffer.add(';\n'); |
| 1086 // Control flow instructions, and some other instructions, | |
| 1087 // know how to handle ';'. | |
| 1088 if (instruction is !HControlFlow | |
| 1089 && instruction is !HTypeGuard | |
| 1090 && !isGeneratingExpression()) { | |
| 1091 buffer.add(';\n'); | |
| 1092 } | |
| 1093 } else if (instruction is HIf) { | |
| 1094 HIf hif = instruction; | |
| 1095 // The "if" is implementing part of a logical expression. | |
| 1096 // Skip directly forward to to its latest successor, since everything | |
| 1097 // in-between must also be generateAtUseSite. | |
| 1098 assert(hif.trueBranch.id < hif.falseBranch.id); | |
| 1099 visitBasicBlock(hif.falseBranch); | |
| 1100 return; | |
| 1101 } | 1142 } |
| 1102 instruction = instruction.next; | 1143 instruction = instruction.next; |
| 1103 } | 1144 } |
| 1104 } | 1145 } |
| 1105 | 1146 |
| 1106 visitInvokeBinary(HInvokeBinary node, String op) { | 1147 visitInvokeBinary(HInvokeBinary node, String op) { |
| 1107 if (node.builtin) { | 1148 if (node.builtin) { |
| 1108 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; | 1149 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op]; |
| 1109 beginExpression(operatorPrecedences.precedence); | 1150 beginExpression(operatorPrecedences.precedence); |
| 1110 use(node.left, operatorPrecedences.left); | 1151 use(node.left, operatorPrecedences.left); |
| (...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1611 String operation = logicalOperations[node]; | 1652 String operation = logicalOperations[node]; |
| 1612 if (operation !== null) { | 1653 if (operation !== null) { |
| 1613 emitLogicalOperation(node, operation); | 1654 emitLogicalOperation(node, operation); |
| 1614 } else { | 1655 } else { |
| 1615 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); | 1656 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); |
| 1616 buffer.add('${temporary(canonicalPhi)}'); | 1657 buffer.add('${temporary(canonicalPhi)}'); |
| 1617 } | 1658 } |
| 1618 } | 1659 } |
| 1619 | 1660 |
| 1620 visitReturn(HReturn node) { | 1661 visitReturn(HReturn node) { |
| 1662 addIndentation(); | |
| 1621 assert(node.inputs.length == 1); | 1663 assert(node.inputs.length == 1); |
| 1622 HInstruction input = node.inputs[0]; | 1664 HInstruction input = node.inputs[0]; |
| 1623 if (input.isConstantNull()) { | 1665 if (input.isConstantNull()) { |
| 1624 buffer.add('return;\n'); | 1666 buffer.add('return;\n'); |
| 1625 } else { | 1667 } else { |
| 1626 buffer.add('return '); | 1668 buffer.add('return '); |
| 1627 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1669 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1628 buffer.add(';\n'); | 1670 buffer.add(';\n'); |
| 1629 } | 1671 } |
| 1630 } | 1672 } |
| 1631 | 1673 |
| 1632 visitThis(HThis node) { | 1674 visitThis(HThis node) { |
| 1633 buffer.add('this'); | 1675 buffer.add('this'); |
| 1634 } | 1676 } |
| 1635 | 1677 |
| 1636 visitThrow(HThrow node) { | 1678 visitThrow(HThrow node) { |
| 1679 addIndentation(); | |
| 1637 if (node.isRethrow) { | 1680 if (node.isRethrow) { |
| 1638 buffer.add('throw '); | 1681 buffer.add('throw '); |
| 1639 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 1682 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1640 } else { | 1683 } else { |
| 1641 generateThrowWithHelper('captureStackTrace', node.inputs[0]); | 1684 generateThrowWithHelper('captureStackTrace', node.inputs[0]); |
| 1642 } | 1685 } |
| 1643 buffer.add(';\n'); | 1686 buffer.add(';\n'); |
| 1644 } | 1687 } |
| 1645 | 1688 |
| 1646 visitBoundsCheck(HBoundsCheck node) { | 1689 visitBoundsCheck(HBoundsCheck node) { |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2026 buffer.add(".${name.slowToString()} === '${arguments.head}'"); | 2069 buffer.add(".${name.slowToString()} === '${arguments.head}'"); |
| 2027 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); | 2070 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE); |
| 2028 }); | 2071 }); |
| 2029 } | 2072 } |
| 2030 if (node.nullOk) { | 2073 if (node.nullOk) { |
| 2031 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); | 2074 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE); |
| 2032 } | 2075 } |
| 2033 } | 2076 } |
| 2034 | 2077 |
| 2035 void visitTypeConversion(HTypeConversion node) { | 2078 void visitTypeConversion(HTypeConversion node) { |
| 2079 HInstruction input = node.inputs[0]; | |
|
Lasse Reichstein Nielsen
2012/05/08 12:39:08
node.input?
Why extract input here, when it's only
ngeoffray
2012/05/08 16:09:12
Done.
| |
| 2036 if (node.checked) { | 2080 if (node.checked) { |
| 2037 Element element = node.type.computeType(compiler).element; | 2081 Element element = node.type.computeType(compiler).element; |
| 2038 compiler.registerIsCheck(element); | 2082 compiler.registerIsCheck(element); |
| 2039 SourceString helper; | 2083 SourceString helper; |
| 2040 String additionalArgument; | 2084 String additionalArgument; |
| 2041 bool nativeCheck = | 2085 bool nativeCheck = |
| 2042 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); | 2086 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element); |
| 2043 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 2087 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2044 | 2088 |
| 2045 if (element == compiler.stringClass) { | 2089 if (element == compiler.stringClass) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 2073 } else if (nativeCheck) { | 2117 } else if (nativeCheck) { |
| 2074 helper = const SourceString('callTypeCheck'); | 2118 helper = const SourceString('callTypeCheck'); |
| 2075 } else { | 2119 } else { |
| 2076 helper = const SourceString('propertyTypeCheck'); | 2120 helper = const SourceString('propertyTypeCheck'); |
| 2077 } | 2121 } |
| 2078 } | 2122 } |
| 2079 Element helperElement = compiler.findHelper(helper); | 2123 Element helperElement = compiler.findHelper(helper); |
| 2080 compiler.registerStaticUse(helperElement); | 2124 compiler.registerStaticUse(helperElement); |
| 2081 buffer.add(compiler.namer.isolateAccess(helperElement)); | 2125 buffer.add(compiler.namer.isolateAccess(helperElement)); |
| 2082 buffer.add('('); | 2126 buffer.add('('); |
| 2083 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | 2127 use(input, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 2084 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); | 2128 if (additionalArgument !== null) buffer.add(", '$additionalArgument'"); |
| 2085 buffer.add(')'); | 2129 buffer.add(')'); |
| 2086 endExpression(JSPrecedence.CALL_PRECEDENCE); | 2130 endExpression(JSPrecedence.CALL_PRECEDENCE); |
| 2087 } else { | 2131 } else { |
| 2088 use(node.inputs[0], expectedPrecedence); | 2132 visit(input, expectedPrecedence); |
| 2089 } | 2133 } |
| 2090 } | 2134 } |
| 2091 } | 2135 } |
| 2092 | 2136 |
| 2093 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2137 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2094 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) | 2138 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames) |
| 2095 : super(compiler, work, parameters, parameterNames); | 2139 : super(compiler, work, parameters, parameterNames); |
| 2096 | 2140 |
| 2097 void beginGraph(HGraph graph) {} | 2141 void beginGraph(HGraph graph) {} |
| 2098 void endGraph(HGraph graph) {} | 2142 void endGraph(HGraph graph) {} |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2487 startBailoutSwitch(); | 2531 startBailoutSwitch(); |
| 2488 } | 2532 } |
| 2489 } | 2533 } |
| 2490 | 2534 |
| 2491 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2535 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2492 if (labeledBlockInfo.body.start.hasGuards()) { | 2536 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2493 endBailoutSwitch(); | 2537 endBailoutSwitch(); |
| 2494 } | 2538 } |
| 2495 } | 2539 } |
| 2496 } | 2540 } |
| OLD | NEW |