| 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 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 visit(argument); | 204 visit(argument); |
| 205 } else { | 205 } else { |
| 206 buffer.add(temporary(argument)); | 206 buffer.add(temporary(argument)); |
| 207 } | 207 } |
| 208 } | 208 } |
| 209 | 209 |
| 210 visit(HInstruction node) { | 210 visit(HInstruction node) { |
| 211 return node.accept(this); | 211 return node.accept(this); |
| 212 } | 212 } |
| 213 | 213 |
| 214 void handleLabeledBlock(HBasicBlock node) { |
| 215 HLabeledBlockInformation labeledBlockInfo = node.labeledBlockInformation; |
| 216 if (labeledBlockInfo.start === node) { |
| 217 addIndentation(); |
| 218 for (SourceString label in labeledBlockInfo.labels) { |
| 219 addLabel(label); |
| 220 buffer.add(":"); |
| 221 } |
| 222 buffer.add("{\n"); |
| 223 indent++; |
| 224 } else { |
| 225 assert(labeledBlockInfo.end === node); |
| 226 assert((){ |
| 227 // Check that this block is (transitively) dominated by the start block. |
| 228 HBasicBlock block = node; |
| 229 while (block.dominator !== null) { |
| 230 block = block.dominator; |
| 231 if (block === labeledBlockInfo.start) return true; |
| 232 } |
| 233 return false; |
| 234 }); |
| 235 indent--; |
| 236 addIndentation(); |
| 237 buffer.add("}\n"); |
| 238 } |
| 239 } |
| 240 |
| 214 visitBasicBlock(HBasicBlock node) { | 241 visitBasicBlock(HBasicBlock node) { |
| 215 currentBlock = node; | 242 currentBlock = node; |
| 216 | 243 |
| 217 // While loop will be closed by the conditional loop-branch. | 244 if (node.hasLabeledBlockInformation()) { |
| 218 // TODO(floitsch): HACK HACK HACK. | 245 handleLabeledBlock(node); |
| 219 if (currentBlock.isLoopHeader()) beginLoop(node); | 246 } else if (currentBlock.isLoopHeader()) { |
| 247 // While loop will be closed by the conditional loop-branch. |
| 248 // TODO(floitsch): HACK HACK HACK. |
| 249 beginLoop(node); |
| 250 } |
| 220 | 251 |
| 221 HInstruction instruction = node.first; | 252 HInstruction instruction = node.first; |
| 222 while (instruction != null) { | 253 while (instruction != null) { |
| 223 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 254 if (instruction is HGoto || instruction is HExit || instruction is HTry) { |
| 224 visit(instruction); | 255 visit(instruction); |
| 225 return; | 256 return; |
| 226 } else if (!instruction.generateAtUseSite()) { | 257 } else if (!instruction.generateAtUseSite()) { |
| 227 if (instruction is !HIf && instruction is !HBailoutTarget) { | 258 if (instruction is !HIf && instruction is !HBailoutTarget) { |
| 228 addIndentation(); | 259 addIndentation(); |
| 229 } | 260 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 // is responsible for visiting the successor. | 374 // is responsible for visiting the successor. |
| 344 if (dominated.isEmpty()) return; | 375 if (dominated.isEmpty()) return; |
| 345 if (dominated.length > 2) unreachable(); | 376 if (dominated.length > 2) unreachable(); |
| 346 if (dominated.length == 2 && currentBlock !== currentGraph.entry) { | 377 if (dominated.length == 2 && currentBlock !== currentGraph.entry) { |
| 347 unreachable(); | 378 unreachable(); |
| 348 } | 379 } |
| 349 assert(dominated[0] == currentBlock.successors[0]); | 380 assert(dominated[0] == currentBlock.successors[0]); |
| 350 visitBasicBlock(dominated[0]); | 381 visitBasicBlock(dominated[0]); |
| 351 } | 382 } |
| 352 | 383 |
| 384 // Used to write the name of labels. |
| 385 // The default implementation uses the unmodified Dart label name. |
| 386 // Specializations might change this. |
| 387 void addLabel(SourceString label) { |
| 388 buffer.add(label.toString()); |
| 389 } |
| 390 |
| 391 visitBreak(HBreak node) { |
| 392 assert(currentBlock.successors.length == 1); |
| 393 // No block finishing with a 'break' can have more than |
| 394 // one dominated block (since it has only one successor). |
| 395 // If the successor is dominated by another block, then the other block |
| 396 // is responsible for visiting the successor. |
| 397 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 398 assert(dominated.isEmpty()); |
| 399 // Otherwise we would have bailed out in the builder. |
| 400 addIndentation(); |
| 401 buffer.add("break"); |
| 402 if (node.label !== null) { |
| 403 buffer.add(" "); |
| 404 addLabel(node.label); |
| 405 } |
| 406 buffer.add(";\n"); |
| 407 } |
| 408 |
| 353 visitTry(HTry node) { | 409 visitTry(HTry node) { |
| 354 addIndentation(); | 410 addIndentation(); |
| 355 buffer.add('try {\n'); | 411 buffer.add('try {\n'); |
| 356 indent++; | 412 indent++; |
| 357 List<HBasicBlock> successors = node.block.successors; | 413 List<HBasicBlock> successors = node.block.successors; |
| 358 visitBasicBlock(successors[0]); | 414 visitBasicBlock(successors[0]); |
| 359 indent--; | 415 indent--; |
| 360 | 416 |
| 361 if (node.finallyBlock != successors[1]) { | 417 if (node.finallyBlock != successors[1]) { |
| 362 // Printing the catch part. | 418 // Printing the catch part. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 375 buffer.add('} finally {\n'); | 431 buffer.add('} finally {\n'); |
| 376 indent++; | 432 indent++; |
| 377 visitBasicBlock(node.finallyBlock); | 433 visitBasicBlock(node.finallyBlock); |
| 378 } | 434 } |
| 379 indent--; | 435 indent--; |
| 380 addIndentation(); | 436 addIndentation(); |
| 381 buffer.add('}\n'); | 437 buffer.add('}\n'); |
| 382 } | 438 } |
| 383 | 439 |
| 384 visitIf(HIf node) { | 440 visitIf(HIf node) { |
| 441 List<HBasicBlock> dominated = node.block.dominatedBlocks; |
| 385 startIf(node); | 442 startIf(node); |
| 386 assert(!node.generateAtUseSite()); | 443 assert(!node.generateAtUseSite()); |
| 387 startThen(node); | 444 startThen(node); |
| 445 assert(node.thenBlock === dominated[0]); |
| 388 visitBasicBlock(node.thenBlock); | 446 visitBasicBlock(node.thenBlock); |
| 447 int preVisitedBlocks = 1; |
| 389 endThen(node); | 448 endThen(node); |
| 390 if (node.hasElse) { | 449 if (node.hasElse) { |
| 391 startElse(node); | 450 startElse(node); |
| 451 assert(node.elseBlock === dominated[1]); |
| 392 visitBasicBlock(node.elseBlock); | 452 visitBasicBlock(node.elseBlock); |
| 453 preVisitedBlocks = 2; |
| 393 endElse(node); | 454 endElse(node); |
| 394 } | 455 } |
| 395 endIf(node); | 456 endIf(node); |
| 396 | 457 |
| 397 // Normally the HIf dominates the join-block. In this case there is one | 458 // Visit all the dominated blocks that are not part of the then or else |
| 398 // dominated block that we need to visit: | 459 // branches. Depending on how the then/else branches terminate |
| 399 // If both the then and else blocks return/throw, then the join-block is | 460 // (e.g., return/throw/break) there can be any number of these. |
| 400 // either the exit-block, or there is none. | |
| 401 // We can also have the case where the HIf has no else, but the then-branch | |
| 402 // terminates. If the code after the 'if' terminates, then the | |
| 403 // if could become the dominator of the exit-block, thus having | |
| 404 // three dominated blocks: the then, the code after the if, and the exit | |
| 405 // block. | |
| 406 | |
| 407 List<HBasicBlock> dominated = node.block.dominatedBlocks; | |
| 408 int dominatedCount = dominated.length; | 461 int dominatedCount = dominated.length; |
| 409 if (node.hasElse && (dominatedCount == 3 || dominatedCount == 4)) { | 462 for (int i = preVisitedBlocks; i < dominatedCount; i++) { |
| 410 // Normal case. The third dominated block is either the join-block or | 463 HBasicBlock dominatedBlock = dominated[i]; |
| 411 // the exit-block (if both branches terminate). | 464 assert(dominatedBlock.dominator === node.block); |
| 412 // If the if dominates 4 blocks, then at least one branch does a | 465 visitBasicBlock(dominatedBlock); |
| 413 // conditional return, and the 4th block is the exit-block. | |
| 414 assert(dominatedCount != 4 || dominated.last().isExitBlock()); | |
| 415 visitBasicBlock(dominated[2]); | |
| 416 } else if (node.hasElse) { | |
| 417 // Both branches terminate, but this HIf is not the dominator of the exit | |
| 418 // block. | |
| 419 assert(dominatedCount == 2); | |
| 420 } else if (!node.hasElse && dominatedCount == 2) { | |
| 421 // Normal case. Even if the then-branch terminated there is still | |
| 422 // a join-block. | |
| 423 assert(!dominated.last().isExitBlock()); | |
| 424 visitBasicBlock(dominated[1]); | |
| 425 } else { | |
| 426 // The then-branch terminates, and the code following the if terminates | |
| 427 // too. The if happens to dominate the exit-block. | |
| 428 assert(!node.hasElse); | |
| 429 assert(dominatedCount == 3); | |
| 430 assert(dominated.last().isExitBlock()); | |
| 431 visitBasicBlock(dominated[1]); | |
| 432 visitBasicBlock(dominated[2]); | |
| 433 } | 466 } |
| 434 } | 467 } |
| 435 | 468 |
| 436 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 469 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 437 use(node.receiver); | 470 use(node.receiver); |
| 438 buffer.add('.'); | 471 buffer.add('.'); |
| 439 // Avoid adding the generative constructor name to the list of | 472 // Avoid adding the generative constructor name to the list of |
| 440 // seen selectors. | 473 // seen selectors. |
| 441 if (node.inputs[0] is HForeignNew) { | 474 if (node.inputs[0] is HForeignNew) { |
| 442 // Remove 'this' from the number of arguments. | 475 // Remove 'this' from the number of arguments. |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 visitLoopBranch(HLoopBranch node) { | 605 visitLoopBranch(HLoopBranch node) { |
| 573 HBasicBlock branchBlock = currentBlock; | 606 HBasicBlock branchBlock = currentBlock; |
| 574 handleLoopCondition(node); | 607 handleLoopCondition(node); |
| 575 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; | 608 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 576 // For a do while loop, the body has already been visited. | 609 // For a do while loop, the body has already been visited. |
| 577 if (!node.isDoWhile()) { | 610 if (!node.isDoWhile()) { |
| 578 visitBasicBlock(dominated[0]); | 611 visitBasicBlock(dominated[0]); |
| 579 } | 612 } |
| 580 endLoop(node.block); | 613 endLoop(node.block); |
| 581 visitBasicBlock(branchBlock.successors[1]); | 614 visitBasicBlock(branchBlock.successors[1]); |
| 582 // TODO(floitsch): with labeled breaks we can have more dominated blocks. | 615 // With labeled breaks we can have more dominated blocks. |
| 583 assert(dominated.length <= 3); | 616 if (dominated.length >= 3) { |
| 584 if (dominated.length == 3) { | 617 for (int i = 2; i < dominated.length; i++) { |
| 585 // This happens when the body contains a 'return', and the exit-block is | 618 visitBasicBlock(dominated[i]); |
| 586 // not dominated by a dominator of the while loop. | 619 } |
| 587 assert(dominated[2].isExitBlock()); | |
| 588 visitBasicBlock(dominated[2]); | |
| 589 } | 620 } |
| 590 } | 621 } |
| 591 | 622 |
| 592 visitNot(HNot node) { | 623 visitNot(HNot node) { |
| 593 assert(node.inputs.length == 1); | 624 assert(node.inputs.length == 1); |
| 594 buffer.add('(!'); | 625 buffer.add('(!'); |
| 595 use(node.inputs[0]); | 626 use(node.inputs[0]); |
| 596 buffer.add(')'); | 627 buffer.add(')'); |
| 597 } | 628 } |
| 598 | 629 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 checkArray(input, '!=='); | 920 checkArray(input, '!=='); |
| 890 buffer.add(') '); | 921 buffer.add(') '); |
| 891 bailout(node, 'Not a string or array'); | 922 bailout(node, 'Not a string or array'); |
| 892 } else { | 923 } else { |
| 893 unreachable(); | 924 unreachable(); |
| 894 } | 925 } |
| 895 } | 926 } |
| 896 | 927 |
| 897 void beginLoop(HBasicBlock block) { | 928 void beginLoop(HBasicBlock block) { |
| 898 addIndentation(); | 929 addIndentation(); |
| 930 for (SourceString label in block.loopInformation.labels) { |
| 931 buffer.add("${label.stringValue}:"); |
| 932 } |
| 899 buffer.add('while (true) {\n'); | 933 buffer.add('while (true) {\n'); |
| 900 indent++; | 934 indent++; |
| 901 } | 935 } |
| 902 | 936 |
| 903 void endLoop(HBasicBlock block) { | 937 void endLoop(HBasicBlock block) { |
| 904 indent--; | 938 indent--; |
| 905 addIndentation(); | 939 addIndentation(); |
| 906 buffer.add('}\n'); // Close 'while' loop. | 940 buffer.add('}\n'); // Close 'while' loop. |
| 907 } | 941 } |
| 908 | 942 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 indent++; | 1084 indent++; |
| 1051 } | 1085 } |
| 1052 | 1086 |
| 1053 void endBailoutSwitch() { | 1087 void endBailoutSwitch() { |
| 1054 indent--; // Close 'case'. | 1088 indent--; // Close 'case'. |
| 1055 indent--; | 1089 indent--; |
| 1056 addIndentation(); | 1090 addIndentation(); |
| 1057 buffer.add('}\n'); // Close 'switch'. | 1091 buffer.add('}\n'); // Close 'switch'. |
| 1058 } | 1092 } |
| 1059 | 1093 |
| 1094 // Adds a "$" in front of names of labels from the original source. |
| 1095 // This avoids conflicts with labels introduced by bailouts, which |
| 1096 // starts with a non-"$" character. |
| 1097 void addLabel(SourceString label) { |
| 1098 buffer.add("\$$label"); |
| 1099 } |
| 1100 |
| 1060 void beginLoop(HBasicBlock block) { | 1101 void beginLoop(HBasicBlock block) { |
| 1061 // TODO(ngeoffray): Don't put labels on loops that don't bailout. | 1102 // TODO(ngeoffray): Don't put labels on loops that don't bailout. |
| 1062 String newLabel = pushLabel(); | 1103 String newLabel = pushLabel(); |
| 1063 if (block.hasBailouts()) { | 1104 if (block.hasBailouts()) { |
| 1064 startBailoutCase(block.bailouts, const <HBailoutTarget>[]); | 1105 startBailoutCase(block.bailouts, const <HBailoutTarget>[]); |
| 1065 } | 1106 } |
| 1066 | 1107 |
| 1067 addIndentation(); | 1108 addIndentation(); |
| 1109 for (SourceString label in block.loopInformation.labels) { |
| 1110 addLabel(label); |
| 1111 buffer.add(":"); |
| 1112 } |
| 1068 buffer.add('$newLabel: while (true) {\n'); | 1113 buffer.add('$newLabel: while (true) {\n'); |
| 1069 indent++; | 1114 indent++; |
| 1070 | 1115 |
| 1071 if (block.hasBailouts()) { | 1116 if (block.hasBailouts()) { |
| 1072 startBailoutSwitch(); | 1117 startBailoutSwitch(); |
| 1073 } | 1118 } |
| 1074 } | 1119 } |
| 1075 | 1120 |
| 1076 void endLoop(HBasicBlock block) { | 1121 void endLoop(HBasicBlock block) { |
| 1077 popLabel(); | 1122 popLabel(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1145 startBailoutSwitch(); | 1190 startBailoutSwitch(); |
| 1146 } | 1191 } |
| 1147 } | 1192 } |
| 1148 | 1193 |
| 1149 void endElse(HIf node) { | 1194 void endElse(HIf node) { |
| 1150 if (node.elseBlock.hasBailouts()) { | 1195 if (node.elseBlock.hasBailouts()) { |
| 1151 endBailoutSwitch(); | 1196 endBailoutSwitch(); |
| 1152 } | 1197 } |
| 1153 } | 1198 } |
| 1154 } | 1199 } |
| OLD | NEW |