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 String generate(WorkItem work, HGraph graph) { | 9 String generate(WorkItem work, HGraph graph) { |
| 10 return measure(() { | 10 return measure(() { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 } | 73 } |
| 74 }); | 74 }); |
| 75 compiler.enqueue(new WorkItem.bailoutVersion( | 75 compiler.enqueue(new WorkItem.bailoutVersion( |
| 76 work.element, work.resolutionTree, bailouts)); | 76 work.element, work.resolutionTree, bailouts)); |
| 77 } | 77 } |
| 78 } | 78 } |
| 79 | 79 |
| 80 typedef void ElementAction(Element element); | 80 typedef void ElementAction(Element element); |
| 81 | 81 |
| 82 class SsaCodeGenerator implements HVisitor { | 82 class SsaCodeGenerator implements HVisitor { |
| 83 /** | |
| 84 * Current state for generating simple (non-local-control) code. | |
| 85 * It is generated as either statements (indented and ';'-terminated), | |
| 86 * expressions (comma separated) or declarations (also comma separated, | |
| 87 * but expected to be preceeded by a 'var' so it declares its variables); | |
| 88 */ | |
| 89 static final int STATE_STATEMENT = 0; | |
| 90 static final int STATE_FIRST_EXPRESSION = 1; | |
| 91 static final int STATE_FIRST_DECLARATION = 2; | |
|
floitsch
2012/03/28 04:03:48
FIRST_DECLARATION and STATE_DECLARATION are unused
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Yes. They are preparing for including the initiali
| |
| 92 static final int STATE_EXPRESSION = 3; | |
| 93 static final int STATE_DECLARATION = 4; | |
| 94 | |
| 83 final Compiler compiler; | 95 final Compiler compiler; |
| 84 final WorkItem work; | 96 final WorkItem work; |
| 85 final StringBuffer buffer; | 97 final StringBuffer buffer; |
| 86 final StringBuffer parameters; | 98 final StringBuffer parameters; |
| 87 | 99 |
| 88 final Map<Element, String> parameterNames; | 100 final Map<Element, String> parameterNames; |
| 89 final Map<int, String> names; | 101 final Map<int, String> names; |
| 90 final Map<String, int> prefixes; | 102 final Map<String, int> prefixes; |
| 91 final Set<HInstruction> generateAtUseSite; | 103 final Set<HInstruction> generateAtUseSite; |
| 92 final Map<HPhi, String> logicalOperations; | 104 final Map<HPhi, String> logicalOperations; |
| 93 final Map<Element, ElementAction> breakAction; | 105 final Map<Element, ElementAction> breakAction; |
| 94 final Map<Element, ElementAction> continueAction; | 106 final Map<Element, ElementAction> continueAction; |
| 95 | 107 |
| 96 Element equalsNullElement; | 108 Element equalsNullElement; |
| 97 int indent = 0; | 109 int indent = 0; |
| 98 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; | 110 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; |
| 99 HGraph currentGraph; | 111 HGraph currentGraph; |
| 112 /** | |
| 113 * Whether the code-generation should try to generate an expression | |
| 114 * instead of a sequence of statements. | |
| 115 */ | |
| 116 int generationState = STATE_STATEMENT; | |
| 117 /** | |
| 118 * While generating expressions, we can't insert variable declarations. | |
| 119 * Instead we declare them at the end of the function | |
| 120 */ | |
| 121 Link<String> delayedVarDecl = const EmptyLink<String>(); | |
| 100 HBasicBlock currentBlock; | 122 HBasicBlock currentBlock; |
| 101 | 123 |
| 102 // Records a block-information that is being handled specially. | 124 // Records a block-information that is being handled specially. |
| 103 // Used to break bad recursion. | 125 // Used to break bad recursion. |
| 104 HLabeledBlockInformation currentBlockInformation; | 126 HBlockInformation currentBlockInformation; |
| 105 // The subgraph is used to delimit traversal for some constructions, e.g., | 127 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 106 // if branches. | 128 // if branches. |
| 107 SubGraph subGraph; | 129 SubGraph subGraph; |
| 108 | 130 |
| 109 LibraryElement get currentLibrary() => work.element.getLibrary(); | 131 LibraryElement get currentLibrary() => work.element.getLibrary(); |
| 110 | 132 |
| 111 bool isGenerateAtUseSite(HInstruction instruction) { | 133 bool isGenerateAtUseSite(HInstruction instruction) { |
| 112 return generateAtUseSite.contains(instruction); | 134 return generateAtUseSite.contains(instruction); |
| 113 } | 135 } |
| 114 | 136 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 logicalOperations).visitGraph(graph); | 189 logicalOperations).visitGraph(graph); |
| 168 } | 190 } |
| 169 | 191 |
| 170 visitGraph(HGraph graph) { | 192 visitGraph(HGraph graph) { |
| 171 preGenerateMethod(graph); | 193 preGenerateMethod(graph); |
| 172 currentGraph = graph; | 194 currentGraph = graph; |
| 173 indent++; // We are already inside a function. | 195 indent++; // We are already inside a function. |
| 174 subGraph = new SubGraph(graph.entry, graph.exit); | 196 subGraph = new SubGraph(graph.entry, graph.exit); |
| 175 beginGraph(graph); | 197 beginGraph(graph); |
| 176 visitBasicBlock(graph.entry); | 198 visitBasicBlock(graph.entry); |
| 199 if (!delayedVarDecl.isEmpty()) { | |
| 200 addIndentation(); | |
| 201 buffer.add("var "); | |
| 202 while (true) { | |
| 203 buffer.add(delayedVarDecl.head); | |
| 204 delayedVarDecl = delayedVarDecl.tail; | |
| 205 if (delayedVarDecl.isEmpty()) break; | |
| 206 buffer.add(", "); | |
| 207 } | |
| 208 buffer.add(";\n"); | |
| 209 } | |
| 177 endGraph(graph); | 210 endGraph(graph); |
| 178 } | 211 } |
| 179 | 212 |
| 180 void visitSubGraph(SubGraph newSubGraph) { | 213 void visitSubGraph(SubGraph newSubGraph) { |
| 181 SubGraph oldSubGraph = subGraph; | 214 SubGraph oldSubGraph = subGraph; |
| 182 subGraph = newSubGraph; | 215 subGraph = newSubGraph; |
| 183 visitBasicBlock(subGraph.start); | 216 visitBasicBlock(subGraph.start); |
| 184 subGraph = oldSubGraph; | 217 subGraph = oldSubGraph; |
| 185 } | 218 } |
| 186 | 219 |
| 220 bool isExpression(SubGraph limits) { | |
| 221 HBasicBlock basicBlock = limits.start; | |
| 222 do { | |
| 223 HInstruction current = basicBlock.first; | |
| 224 while (current != basicBlock.last) { | |
| 225 // E.g, BailoutTarget. | |
|
ngeoffray
2012/03/28 15:28:04
BailoutTarget does not exist anymore.
| |
| 226 if (current.isControlFlow()) { | |
| 227 print("[isExpression FAIL: $current]"); | |
|
floitsch
2012/03/28 04:03:48
debug code?
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Ah, yes. Will remove them all.
| |
| 228 return false; | |
| 229 } | |
| 230 current = current.next; | |
| 231 } | |
| 232 if (current is HGoto) { | |
| 233 basicBlock = basicBlock.successors[0]; | |
| 234 } else if (current is HConditionalBranch) { | |
| 235 if (generateAtUseSite.contains(current)) { | |
| 236 // Short-circuit logical operator trickery. | |
| 237 // Check the second half, which will continue into the join. | |
|
floitsch
2012/03/28 04:03:48
Isn't the second half successors[1]?
Can't we just
Lasse Reichstein Nielsen
2012/03/29 13:09:38
No, successors[1] is the join node, the first half
floitsch
2012/03/29 21:44:10
Right... missed that. Please add as comment.
Lasse Reichstein Nielsen
2012/03/30 09:37:17
Done.
| |
| 238 basicBlock = basicBlock.successors[0]; | |
| 239 } else { | |
| 240 // We allow an expression to end on an HIf (a condition expression). | |
| 241 if (basicBlock !== limits.end) print("[isExpression IF_FAIL: $current] "); | |
|
floitsch
2012/03/28 04:03:48
debug code?
| |
| 242 return basicBlock === limits.end; | |
| 243 } | |
| 244 } else { | |
| 245 print("[isExpression CC-FAIL: $current"); | |
|
floitsch
2012/03/28 04:03:48
debug code?
| |
| 246 // Expression-incompatible control flow. | |
| 247 return false; | |
| 248 } | |
| 249 } while (limits.contains(basicBlock)); | |
| 250 return true; | |
| 251 } | |
| 252 | |
| 253 bool isCondition(SubGraph limits) { | |
| 254 return isExpression(limits) && (limits.end.last is HConditionalBranch); | |
| 255 } | |
| 256 | |
| 257 void visitExpressionGraph(SubGraph subGraph) { | |
| 258 int oldState = generationState; | |
| 259 generationState = STATE_FIRST_EXPRESSION; | |
| 260 visitSubGraph(subGraph); | |
| 261 generationState = oldState; | |
| 262 } | |
| 263 | |
| 264 void visitConditionGraph(SubGraph subGraph) { | |
| 265 visitExpressionGraph(subGraph); | |
| 266 } | |
| 267 | |
| 187 String temporary(HInstruction instruction) { | 268 String temporary(HInstruction instruction) { |
| 188 int id = instruction.id; | 269 int id = instruction.id; |
| 189 String name = names[id]; | 270 String name = names[id]; |
| 190 if (name !== null) return name; | 271 if (name !== null) return name; |
| 191 | 272 |
| 192 if (instruction is HPhi) { | 273 if (instruction is HPhi) { |
| 193 HPhi phi = instruction; | 274 HPhi phi = instruction; |
| 194 Element element = phi.element; | 275 Element element = phi.element; |
| 195 if (element != null && element.kind == ElementKind.PARAMETER) { | 276 if (element != null && element.kind == ElementKind.PARAMETER) { |
| 196 name = parameterNames[element]; | 277 name = parameterNames[element]; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 void visitArguments(List<HInstruction> inputs) { | 314 void visitArguments(List<HInstruction> inputs) { |
| 234 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); | 315 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); |
| 235 buffer.add('('); | 316 buffer.add('('); |
| 236 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { | 317 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { |
| 237 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); | 318 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); |
| 238 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 319 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 239 } | 320 } |
| 240 buffer.add(')'); | 321 buffer.add(')'); |
| 241 } | 322 } |
| 242 | 323 |
| 324 | |
| 325 | |
| 326 /** | |
| 327 * Whether we are currently generating expressions instead of statements. | |
| 328 * This includes declarations, which are generated as expressions. | |
| 329 */ | |
| 330 bool isGeneratingExpression() { | |
| 331 return generationState != STATE_STATEMENT; | |
| 332 } | |
| 333 | |
| 334 /** | |
| 335 * Whether we are generating a declaration. | |
| 336 */ | |
| 337 bool isGeneratingDeclaration() { | |
| 338 assert(generationState != STATE_STATEMENT); | |
| 339 return (generationState & 0x01) == 0; | |
|
floitsch
2012/03/28 04:03:48
magic constant.
I don't see generationState as a b
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Yep. Fixed.
| |
| 340 } | |
| 341 | |
| 342 /** | |
| 343 * Called before writing an expression. | |
| 344 * Ensures that expressions are comma spearated. | |
| 345 */ | |
| 346 void addExpressionSeparator() { | |
| 347 if (generationState <= STATE_FIRST_DECLARATION) { | |
|
floitsch
2012/03/28 04:03:48
if (generationState == STATE_FIRST_EXPRESSION) gen
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
| |
| 348 // From STATE_FIRST_EXPRESSION to STATE_EXPRESSION or from | |
| 349 // STATE_FIRST_DECLARATION to STATE_DECLARATION. | |
| 350 generationState += 2; | |
| 351 } else { | |
| 352 buffer.add(", "); | |
| 353 } | |
| 354 } | |
| 355 | |
| 243 void define(HInstruction instruction) { | 356 void define(HInstruction instruction) { |
| 244 buffer.add('var ${temporary(instruction)} = '); | 357 String temporaryVar = temporary(instruction); |
| 245 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 358 if (isGeneratingExpression()) { |
| 359 // As expression. | |
| 360 if (!isGeneratingDeclaration()) { | |
| 361 delayedVarDecl = delayedVarDecl.prepend(temporaryVar); | |
| 362 } | |
| 363 addExpressionSeparator(); | |
| 364 buffer.add('$temporaryVar = '); | |
| 365 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 366 } else { | |
| 367 // As statement. | |
| 368 buffer.add('var $temporaryVar = '); | |
| 369 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 370 } | |
| 246 } | 371 } |
| 247 | 372 |
| 248 void use(HInstruction argument, int expectedPrecedence) { | 373 void use(HInstruction argument, int expectedPrecedence) { |
| 249 if (isGenerateAtUseSite(argument)) { | 374 if (isGenerateAtUseSite(argument)) { |
| 250 visit(argument, expectedPrecedence); | 375 visit(argument, expectedPrecedence); |
| 251 } else if (argument is HIntegerCheck) { | 376 } else if (argument is HIntegerCheck) { |
| 252 HIntegerCheck instruction = argument; | 377 HIntegerCheck instruction = argument; |
| 253 use(instruction.value, expectedPrecedence); | 378 use(instruction.value, expectedPrecedence); |
| 254 } else if (argument is HBoundsCheck) { | 379 } else if (argument is HBoundsCheck) { |
| 255 HBoundsCheck instruction = argument; | 380 HBoundsCheck instruction = argument; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 void emitLogicalOperation(HPhi node, String operation) { | 481 void emitLogicalOperation(HPhi node, String operation) { |
| 357 JSBinaryOperatorPrecedence operatorPrecedence = | 482 JSBinaryOperatorPrecedence operatorPrecedence = |
| 358 JSPrecedence.binary[operation]; | 483 JSPrecedence.binary[operation]; |
| 359 beginExpression(operatorPrecedence.precedence); | 484 beginExpression(operatorPrecedence.precedence); |
| 360 use(node.inputs[0], operatorPrecedence.left); | 485 use(node.inputs[0], operatorPrecedence.left); |
| 361 buffer.add(" $operation "); | 486 buffer.add(" $operation "); |
| 362 use(node.inputs[1], operatorPrecedence.right); | 487 use(node.inputs[1], operatorPrecedence.right); |
| 363 endExpression(operatorPrecedence.precedence); | 488 endExpression(operatorPrecedence.precedence); |
| 364 } | 489 } |
| 365 | 490 |
| 366 visitBasicBlock(HBasicBlock node) { | 491 bool handleLoop(HBasicBlock node) { |
| 492 assert(node.isLoopHeader()); | |
| 493 HLoopInformation info = node.loopInformation; | |
| 494 SubExpression condition = info.condition; | |
| 495 print("LOOP: [${["WHILE","FOR","DO-WHILE","FOR-IN"][info.type]}]"); | |
|
floitsch
2012/03/28 04:03:48
debug code?
| |
| 496 if (isCondition(condition)) { | |
| 497 print("--[Condition is Expression!]"); | |
| 498 switch (info.type) { | |
| 499 case HLoopInformation.WHILE_LOOP: | |
| 500 case HLoopInformation.FOR_IN_LOOP: { | |
| 501 addIndentation(); | |
| 502 for (LabelElement label in info.labels) { | |
| 503 writeLabel(label); | |
| 504 buffer.add(":"); | |
| 505 } | |
| 506 buffer.add("while ("); | |
| 507 visitConditionGraph(condition); | |
| 508 buffer.add(") {\n"); | |
| 509 indent++; | |
| 510 visitSubGraph(info.body); | |
| 511 if (info.updates !== null) { | |
| 512 // Even in while loops the updates block may be needed to | |
| 513 // handle phi nodes of its successors. | |
| 514 visitSubGraph(info.updates); | |
| 515 } | |
| 516 indent--; | |
| 517 addIndentation(); | |
| 518 buffer.add("}\n"); | |
| 519 break; | |
| 520 } | |
| 521 case HLoopInformation.FOR_LOOP: { | |
| 522 // TODO(lrn): Find a way to put initialization into the for. | |
| 523 // It's currently handled before we reach the [HLoopInformation]. | |
| 524 addIndentation(); | |
| 525 for (LabelElement label in info.labels) { | |
| 526 if (label.isTarget) { | |
| 527 writeLabel(label); | |
| 528 buffer.add(":"); | |
| 529 } | |
| 530 } | |
| 531 buffer.add("for(;"); | |
| 532 visitConditionGraph(info.condition); | |
| 533 buffer.add(";"); | |
| 534 if (isExpression(info.updates)) { | |
| 535 visitExpressionGraph(info.updates); | |
| 536 buffer.add(") {\n"); | |
| 537 indent++; | |
| 538 visitSubGraph(info.body); | |
| 539 indent--; | |
| 540 addIndentation(); | |
| 541 buffer.add("}\n"); | |
| 542 } else { | |
| 543 buffer.add(") {\n"); | |
| 544 indent++; | |
| 545 if (info.target !== null && info.target.isContinueTarget) { | |
| 546 addIndentation(); | |
| 547 for (LabelElement label in info.labels) { | |
| 548 if (label.isContinueTarget) { | |
| 549 writeContinueLabel(label); | |
| 550 buffer.add(":"); | |
| 551 continueActions[label] = continueAsBreak; | |
|
floitsch
2012/03/28 04:03:48
continueAction.
Add test.
| |
| 552 } | |
| 553 } | |
| 554 addImplicitContinueLabel(); | |
| 555 buffer.add(":{\n"); | |
| 556 continueAction[info.target] = implicitContinueAsBreak; | |
| 557 indent++; | |
|
floitsch
2012/03/28 04:03:48
move indent++ closer to "{" ?
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Refactored away.
| |
| 558 } | |
| 559 visitSubGraph(info.body); | |
|
floitsch
2012/03/28 04:03:48
I would keep the 'if' open and duplicate the 'visi
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
| |
| 560 if (info.target !== null && info.target.isContinueTarget) { | |
| 561 indent--; | |
| 562 buffer.add("}\n"); | |
| 563 continueAction.remove(info.target); | |
| 564 for (LabelElement label in info.labels) { | |
| 565 if (label.isContinueTarget) { | |
| 566 continueAction.remove(label); | |
| 567 } | |
| 568 } | |
| 569 } | |
| 570 visitSubGraph(info.updates); | |
| 571 indent--; | |
| 572 buffer.add("}\n"); | |
| 573 } | |
| 574 break; | |
| 575 } | |
| 576 case HLoopInformation.DO_WHILE_LOOP: | |
| 577 default: | |
| 578 return false; | |
|
floitsch
2012/03/28 04:03:48
I don't like these "return false/true" where it is
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
| |
| 579 } | |
| 580 return true; | |
| 581 } | |
| 582 return false; | |
| 583 } | |
| 584 | |
| 585 void visitBasicBlock(HBasicBlock node) { | |
| 367 // Abort traversal if we are leaving the currently active sub-graph. | 586 // Abort traversal if we are leaving the currently active sub-graph. |
| 368 if (!subGraph.contains(node)) return; | 587 if (!subGraph.contains(node)) return; |
| 369 | 588 |
| 370 // If this node has special behavior attached, handle it. | 589 // If this node has special behavior attached, handle it. |
| 371 // If we reach here again while handling the attached information, | 590 // If we reach here again while handling the attached information, |
| 372 // e.g., because we call visitSubGraph on a subgraph starting here, | 591 // e.g., because we call visitSubGraph on a subgraph starting here, |
| 373 // don't handle it again. | 592 // don't handle it again. |
| 374 if (node.hasLabeledBlockInformation() && | 593 if (node.hasLabeledBlockInformation() && |
| 375 node.labeledBlockInformation !== currentBlockInformation) { | 594 node.labeledBlockInformation !== currentBlockInformation) { |
| 376 HLabeledBlockInformation oldBlockInformation = currentBlockInformation; | 595 HBlockInformation oldBlockInformation = currentBlockInformation; |
| 377 currentBlockInformation = node.labeledBlockInformation; | 596 currentBlockInformation = node.labeledBlockInformation; |
| 378 handleLabeledBlock(currentBlockInformation); | 597 handleLabeledBlock(currentBlockInformation); |
| 379 currentBlockInformation = oldBlockInformation; | 598 currentBlockInformation = oldBlockInformation; |
| 380 return; | 599 return; |
| 381 } | 600 } |
| 382 | 601 |
| 383 currentBlock = node; | 602 if (node.isLoopHeader() && |
| 384 | 603 node.loopInformation !== currentBlockInformation) { |
| 385 if (node.isLoopHeader()) { | 604 HBlockInformation oldBlockInformation = currentBlockInformation; |
| 386 // While loop will be closed by the conditional loop-branch. | 605 currentBlockInformation = node.loopInformation; |
| 387 // TODO(floitsch): HACK HACK HACK. | 606 if (handleLoop(node)) { |
|
floitsch
2012/03/28 04:03:48
WOOT!!! ;)
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Don't be too happy, the code is still there as a f
|
floitsch
2012/03/28 04:03:48
not a strong preference but I would prefer:
bool s
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
|
| 607 currentBlockInformation = oldBlockInformation; | |
| 608 visitBasicBlock(node.loopInformation.joinBlock); | |
| 609 return; | |
| 610 } | |
| 611 currentBlockInformation = oldBlockInformation; | |
| 388 beginLoop(node); | 612 beginLoop(node); |
| 389 } | 613 } |
| 390 | 614 |
| 615 iterateBasicBlock(node); | |
| 616 } | |
| 617 | |
| 618 void iterateBasicBlock(HBasicBlock node) { | |
| 619 currentBlock = node; | |
| 620 bool firstExpression = true; | |
|
floitsch
2012/03/28 04:03:48
unused variable.
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
| |
| 391 HInstruction instruction = node.first; | 621 HInstruction instruction = node.first; |
| 392 while (instruction != null) { | 622 while (instruction != null) { |
| 393 if (instruction === node.last) { | 623 if (instruction === node.last) { |
| 394 for (HBasicBlock successor in node.successors) { | 624 for (HBasicBlock successor in node.successors) { |
| 395 int index = successor.predecessors.indexOf(node); | 625 int index = successor.predecessors.indexOf(node); |
| 396 successor.forEachPhi((HPhi phi) { | 626 successor.forEachPhi((HPhi phi) { |
| 397 bool isLogicalOperation = logicalOperations.containsKey(phi); | 627 bool isLogicalOperation = logicalOperations.containsKey(phi); |
| 398 // In case the phi is being generated by another | 628 // In case the phi is being generated by another |
| 399 // instruction. | 629 // instruction. |
| 400 if (isLogicalOperation && isGenerateAtUseSite(phi)) return; | 630 if (isLogicalOperation && isGenerateAtUseSite(phi)) return; |
| 401 addIndentation(); | 631 if (isGeneratingExpression()) { |
| 402 if (!temporaryExists(phi)) buffer.add('var '); | 632 addExpressionSeparator(); |
| 403 buffer.add('${temporary(phi)} = '); | 633 String temporaryVar; |
| 634 if (!temporaryExists(phi) && !isGeneratingDeclaration()) { | |
| 635 temporaryVar = temporary(phi); | |
| 636 delayedVarDecl = delayedVarDecl.prepend(temporaryVar); | |
| 637 } else { | |
| 638 temporaryVar = temporary(phi); | |
| 639 } | |
| 640 buffer.add(temporaryVar); | |
| 641 buffer.add(" = "); | |
| 642 } else { | |
| 643 addIndentation(); | |
| 644 if (!temporaryExists(phi)) buffer.add('var '); | |
| 645 buffer.add('${temporary(phi)} = '); | |
| 646 } | |
| 404 if (isLogicalOperation) { | 647 if (isLogicalOperation) { |
| 405 emitLogicalOperation(phi, logicalOperations[phi]); | 648 emitLogicalOperation(phi, logicalOperations[phi]); |
| 406 } else { | 649 } else { |
| 407 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 650 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 408 } | 651 } |
| 409 buffer.add(';\n'); | 652 if (!isGeneratingExpression()) { |
| 653 buffer.add(';\n'); | |
| 654 } | |
| 410 }); | 655 }); |
| 411 } | 656 } |
| 412 } | 657 } |
| 413 | 658 |
| 414 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 659 if (instruction is HGoto || instruction is HExit || instruction is HTry) { |
| 415 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 660 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 416 return; | 661 return; |
| 417 } else if (!isGenerateAtUseSite(instruction)) { | 662 } else if (!isGenerateAtUseSite(instruction)) { |
| 418 if (instruction is !HIf && instruction is !HBailoutTarget) { | 663 if (instruction is !HIf && instruction is !HBailoutTarget && |
| 664 !isGeneratingExpression()) { | |
| 419 addIndentation(); | 665 addIndentation(); |
| 420 } | 666 } |
| 421 if (instruction.usedBy.isEmpty() | 667 if (instruction.usedBy.isEmpty() |
| 422 || instruction is HTypeGuard | 668 || instruction is HTypeGuard |
| 423 || instruction is HCheck) { | 669 || instruction is HCheck) { |
| 670 if (isGeneratingExpression()) { | |
| 671 addExpressionSeparator(); | |
| 672 } | |
| 424 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 673 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 425 } else { | 674 } else { |
| 426 define(instruction); | 675 define(instruction); |
| 427 } | 676 } |
| 428 // Control flow instructions know how to handle ';'. | 677 // Control flow instructions know how to handle ';'. |
| 429 if (instruction is !HControlFlow && instruction is !HBailoutTarget) { | 678 if (instruction is! HControlFlow && instruction is! HBailoutTarget && |
| 679 !isGeneratingExpression()) { | |
| 430 buffer.add(';\n'); | 680 buffer.add(';\n'); |
| 431 } | 681 } |
| 432 } else if (instruction is HIf) { | 682 } else if (instruction is HIf) { |
| 433 HIf hif = instruction; | 683 HIf hif = instruction; |
| 434 // The "if" is implementing part of a logical expression. | 684 // The "if" is implementing part of a logical expression. |
| 435 // Skip directly forward to to its latest successor, since everything | 685 // Skip directly forward to to its latest successor, since everything |
| 436 // in-between must also be generateAtUseSite. | 686 // in-between must also be generateAtUseSite. |
| 437 assert(hif.trueBranch.id < hif.falseBranch.id); | 687 assert(hif.trueBranch.id < hif.falseBranch.id); |
| 438 visitBasicBlock(hif.falseBranch); | 688 visitBasicBlock(hif.falseBranch); |
| 439 return; | 689 return; |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 visitBasicBlock(node.finallyBlock); | 889 visitBasicBlock(node.finallyBlock); |
| 640 indent--; | 890 indent--; |
| 641 } | 891 } |
| 642 addIndentation(); | 892 addIndentation(); |
| 643 buffer.add('}\n'); | 893 buffer.add('}\n'); |
| 644 | 894 |
| 645 visitBasicBlock(node.joinBlock); | 895 visitBasicBlock(node.joinBlock); |
| 646 } | 896 } |
| 647 | 897 |
| 648 visitIf(HIf node) { | 898 visitIf(HIf node) { |
| 899 if (isGeneratingExpression()) { | |
|
floitsch
2012/03/28 04:03:48
can you give an example when this is happening?
Lasse Reichstein Nielsen
2012/03/29 13:09:38
When we are expression-generating the condition of
floitsch
2012/03/29 21:44:10
But then it should be a loop-condition and end wit
Lasse Reichstein Nielsen
2012/03/30 09:37:17
True. A HIf is only part of an expression if it's
| |
| 900 assert(node.block == subGraph.end); | |
| 901 // We are generating an expression for a condition. | |
| 902 addExpressionSeparator(); | |
| 903 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | |
| 904 return; | |
| 905 } | |
| 649 List<HBasicBlock> dominated = node.block.dominatedBlocks; | 906 List<HBasicBlock> dominated = node.block.dominatedBlocks; |
| 650 HIfBlockInformation info = node.blockInformation; | 907 HIfBlockInformation info = node.blockInformation; |
| 651 startIf(node); | 908 startIf(node); |
| 652 assert(!isGenerateAtUseSite(node)); | 909 assert(!isGenerateAtUseSite(node)); |
| 653 startThen(node); | 910 startThen(node); |
| 654 assert(node.thenBlock === dominated[0]); | 911 assert(node.thenBlock === dominated[0]); |
| 655 visitSubGraph(info.thenGraph); | 912 visitSubGraph(info.thenGraph); |
| 656 int preVisitedBlocks = 1; | 913 int preVisitedBlocks = 1; |
| 657 endThen(node); | 914 endThen(node); |
| 658 if (node.hasElse) { | 915 if (node.hasElse) { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 780 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1037 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 781 buffer.add('.'); | 1038 buffer.add('.'); |
| 782 buffer.add(name); | 1039 buffer.add(name); |
| 783 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); | 1040 beginExpression(JSPrecedence.MEMBER_PRECEDENCE); |
| 784 } else { | 1041 } else { |
| 785 buffer.add(name); | 1042 buffer.add(name); |
| 786 } | 1043 } |
| 787 } | 1044 } |
| 788 | 1045 |
| 789 visitFieldSet(HFieldSet node) { | 1046 visitFieldSet(HFieldSet node) { |
| 1047 bool delayDeclaration = false; | |
|
ngeoffray
2012/03/28 15:28:04
Please add a comment on why FieldSet needs to part
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Even better, instead of deferring it to a later cl
| |
| 790 if (node.receiver !== null) { | 1048 if (node.receiver !== null) { |
| 791 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1049 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 792 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1050 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 793 buffer.add('.'); | 1051 buffer.add('.'); |
| 794 } else { | 1052 } else { |
| 795 // TODO(ngeoffray): Remove the 'var' once we don't globally box | 1053 // TODO(ngeoffray): Remove the 'var' once we don't globally box |
| 796 // variables used in a try/catch. | 1054 // variables used in a try/catch. |
| 797 buffer.add('var '); | 1055 if (isGeneratingExpression()) { |
| 1056 delayDeclaration = !isGeneratingDeclaration(); | |
| 1057 } else { | |
| 1058 buffer.add('var '); | |
| 1059 } | |
| 798 } | 1060 } |
| 799 String name = JsNames.getValid(node.element.name.slowToString()); | 1061 String name = JsNames.getValid(node.element.name.slowToString()); |
| 800 buffer.add(name); | 1062 buffer.add(name); |
| 1063 if (delayDeclaration) delayedVarDecl = delayedVarDecl.prepend(name); | |
| 801 buffer.add(' = '); | 1064 buffer.add(' = '); |
| 802 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1065 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 803 if (node.receiver !== null) { | 1066 if (node.receiver !== null) { |
| 804 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1067 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 805 } | 1068 } |
| 806 } | 1069 } |
| 807 | 1070 |
| 808 visitForeign(HForeign node) { | 1071 visitForeign(HForeign node) { |
| 809 String code = node.code.slowToString(); | 1072 String code = node.code.slowToString(); |
| 810 List<HInstruction> inputs = node.inputs; | 1073 List<HInstruction> inputs = node.inputs; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 node.constant.writeJsCode(buffer, handler); | 1117 node.constant.writeJsCode(buffer, handler); |
| 855 } | 1118 } |
| 856 } else { | 1119 } else { |
| 857 buffer.add(compiler.namer.CURRENT_ISOLATE); | 1120 buffer.add(compiler.namer.CURRENT_ISOLATE); |
| 858 buffer.add("."); | 1121 buffer.add("."); |
| 859 buffer.add(name); | 1122 buffer.add(name); |
| 860 } | 1123 } |
| 861 } | 1124 } |
| 862 | 1125 |
| 863 visitLoopBranch(HLoopBranch node) { | 1126 visitLoopBranch(HLoopBranch node) { |
| 1127 if (subGraph !== null && node.block == subGraph.end) { | |
|
ngeoffray
2012/03/28 15:28:04
How can that happen? Please add a comment.
Lasse Reichstein Nielsen
2012/03/29 13:09:38
Done.
| |
| 1128 if (isGeneratingExpression()) { | |
|
floitsch
2012/03/28 04:03:48
when can we enter here, but not generate an expres
Lasse Reichstein Nielsen
2012/03/29 13:09:38
We can't yet.
Eventually I'll want to handle loops
floitsch
2012/03/29 21:44:10
If we can't reach this unless it's an expression,
Lasse Reichstein Nielsen
2012/03/30 09:37:17
Done.
| |
| 1129 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE); | |
| 1130 } | |
| 1131 return; | |
| 1132 } | |
| 864 HBasicBlock branchBlock = currentBlock; | 1133 HBasicBlock branchBlock = currentBlock; |
| 865 handleLoopCondition(node); | 1134 handleLoopCondition(node); |
| 866 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; | 1135 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 867 // For a do while loop, the body has already been visited. | 1136 // For a do while loop, the body has already been visited. |
| 868 if (!node.isDoWhile()) { | 1137 if (!node.isDoWhile()) { |
| 869 visitBasicBlock(dominated[0]); | 1138 visitBasicBlock(dominated[0]); |
| 870 } | 1139 } |
| 871 endLoop(node.block); | 1140 endLoop(node.block); |
| 872 visitBasicBlock(branchBlock.successors[1]); | 1141 visitBasicBlock(branchBlock.successors[1]); |
| 873 // With labeled breaks we can have more dominated blocks. | 1142 // With labeled breaks we can have more dominated blocks. |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1430 | 1699 |
| 1431 void endGraph(HGraph graph) { | 1700 void endGraph(HGraph graph) { |
| 1432 if (!graph.entry.hasBailouts()) return; | 1701 if (!graph.entry.hasBailouts()) return; |
| 1433 indent--; // Close original case. | 1702 indent--; // Close original case. |
| 1434 indent--; | 1703 indent--; |
| 1435 addIndentation(); | 1704 addIndentation(); |
| 1436 buffer.add('}\n'); // Close 'switch'. | 1705 buffer.add('}\n'); // Close 'switch'. |
| 1437 setup.add(' }\n'); | 1706 setup.add(' }\n'); |
| 1438 } | 1707 } |
| 1439 | 1708 |
| 1709 bool handleLoop(HBasicBlock node) => false; | |
| 1710 | |
| 1440 void visitTypeGuard(HTypeGuard guard) { | 1711 void visitTypeGuard(HTypeGuard guard) { |
| 1441 compiler.internalError('Type guard in an unoptimized method'); | 1712 compiler.internalError('Type guard in an unoptimized method'); |
| 1442 } | 1713 } |
| 1443 | 1714 |
| 1444 void visitBailoutTarget(HBailoutTarget node) { | 1715 void visitBailoutTarget(HBailoutTarget node) { |
| 1445 indent--; | 1716 indent--; |
| 1446 addIndentation(); | 1717 addIndentation(); |
| 1447 buffer.add('case ${node.state}:\n'); | 1718 buffer.add('case ${node.state}:\n'); |
| 1448 indent++; | 1719 indent++; |
| 1449 addIndentation(); | 1720 addIndentation(); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1585 startBailoutSwitch(); | 1856 startBailoutSwitch(); |
| 1586 } | 1857 } |
| 1587 } | 1858 } |
| 1588 | 1859 |
| 1589 void endElse(HIf node) { | 1860 void endElse(HIf node) { |
| 1590 if (node.elseBlock.hasBailouts()) { | 1861 if (node.elseBlock.hasBailouts()) { |
| 1591 endBailoutSwitch(); | 1862 endBailoutSwitch(); |
| 1592 } | 1863 } |
| 1593 } | 1864 } |
| 1594 } | 1865 } |
| OLD | NEW |