| 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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 } | 219 } |
| 220 } | 220 } |
| 221 | 221 |
| 222 visit(HInstruction node, int expectedPrecedence) { | 222 visit(HInstruction node, int expectedPrecedence) { |
| 223 int oldPrecedence = this.expectedPrecedence; | 223 int oldPrecedence = this.expectedPrecedence; |
| 224 this.expectedPrecedence = expectedPrecedence; | 224 this.expectedPrecedence = expectedPrecedence; |
| 225 node.accept(this); | 225 node.accept(this); |
| 226 this.expectedPrecedence = oldPrecedence; | 226 this.expectedPrecedence = oldPrecedence; |
| 227 } | 227 } |
| 228 | 228 |
| 229 void handleLabeledBlock(HBasicBlock node) { |
| 230 HLabeledBlockInformation labeledBlockInfo = node.labeledBlockInformation; |
| 231 if (labeledBlockInfo.start === node) { |
| 232 addIndentation(); |
| 233 for (SourceString label in labeledBlockInfo.labels) { |
| 234 addLabel(label); |
| 235 buffer.add(":"); |
| 236 } |
| 237 buffer.add("{\n"); |
| 238 indent++; |
| 239 } else { |
| 240 assert(labeledBlockInfo.end === node); |
| 241 assert((){ |
| 242 // Check that this block is (transitively) dominated by the start block. |
| 243 HBasicBlock block = node; |
| 244 while (block.dominator !== null) { |
| 245 block = block.dominator; |
| 246 if (block === labeledBlockInfo.start) return true; |
| 247 } |
| 248 return false; |
| 249 }); |
| 250 indent--; |
| 251 addIndentation(); |
| 252 buffer.add("}\n"); |
| 253 } |
| 254 } |
| 255 |
| 229 visitBasicBlock(HBasicBlock node) { | 256 visitBasicBlock(HBasicBlock node) { |
| 230 currentBlock = node; | 257 currentBlock = node; |
| 231 | 258 |
| 232 // While loop will be closed by the conditional loop-branch. | 259 if (node.hasLabeledBlockInformation()) { |
| 233 // TODO(floitsch): HACK HACK HACK. | 260 handleLabeledBlock(node); |
| 234 if (currentBlock.isLoopHeader()) beginLoop(node); | 261 } else if (currentBlock.isLoopHeader()) { |
| 262 // While loop will be closed by the conditional loop-branch. |
| 263 // TODO(floitsch): HACK HACK HACK. |
| 264 beginLoop(node); |
| 265 } |
| 235 | 266 |
| 236 HInstruction instruction = node.first; | 267 HInstruction instruction = node.first; |
| 237 while (instruction != null) { | 268 while (instruction != null) { |
| 238 if (instruction is HGoto || instruction is HExit || instruction is HTry) { | 269 if (instruction is HGoto || instruction is HExit || instruction is HTry) { |
| 239 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 270 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 240 return; | 271 return; |
| 241 } else if (!instruction.generateAtUseSite()) { | 272 } else if (!instruction.generateAtUseSite()) { |
| 242 if (instruction is !HIf && instruction is !HBailoutTarget) { | 273 if (instruction is !HIf && instruction is !HBailoutTarget) { |
| 243 addIndentation(); | 274 addIndentation(); |
| 244 } | 275 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 // is responsible for visiting the successor. | 396 // is responsible for visiting the successor. |
| 366 if (dominated.isEmpty()) return; | 397 if (dominated.isEmpty()) return; |
| 367 if (dominated.length > 2) unreachable(); | 398 if (dominated.length > 2) unreachable(); |
| 368 if (dominated.length == 2 && currentBlock !== currentGraph.entry) { | 399 if (dominated.length == 2 && currentBlock !== currentGraph.entry) { |
| 369 unreachable(); | 400 unreachable(); |
| 370 } | 401 } |
| 371 assert(dominated[0] == currentBlock.successors[0]); | 402 assert(dominated[0] == currentBlock.successors[0]); |
| 372 visitBasicBlock(dominated[0]); | 403 visitBasicBlock(dominated[0]); |
| 373 } | 404 } |
| 374 | 405 |
| 406 // Used to write the name of labels. |
| 407 // The default implementation uses the unmodified Dart label name. |
| 408 // Specializations might change this. |
| 409 void addLabel(SourceString label) { |
| 410 buffer.add(label.toString()); |
| 411 } |
| 412 |
| 413 visitBreak(HBreak node) { |
| 414 assert(currentBlock.successors.length == 1); |
| 415 // No block finishing with a 'break' can have more than |
| 416 // one dominated block (since it has only one successor). |
| 417 // If the successor is dominated by another block, then the other block |
| 418 // is responsible for visiting the successor. |
| 419 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 420 assert(dominated.isEmpty()); |
| 421 // Otherwise we would have bailed out in the builder. |
| 422 addIndentation(); |
| 423 buffer.add("break"); |
| 424 if (node.label !== null) { |
| 425 buffer.add(" "); |
| 426 addLabel(node.label); |
| 427 } |
| 428 buffer.add(";\n"); |
| 429 } |
| 430 |
| 375 visitTry(HTry node) { | 431 visitTry(HTry node) { |
| 376 addIndentation(); | 432 addIndentation(); |
| 377 buffer.add('try {\n'); | 433 buffer.add('try {\n'); |
| 378 indent++; | 434 indent++; |
| 379 List<HBasicBlock> successors = node.block.successors; | 435 List<HBasicBlock> successors = node.block.successors; |
| 380 visitBasicBlock(successors[0]); | 436 visitBasicBlock(successors[0]); |
| 381 indent--; | 437 indent--; |
| 382 | 438 |
| 383 if (node.finallyBlock != successors[1]) { | 439 if (node.finallyBlock != successors[1]) { |
| 384 // Printing the catch part. | 440 // Printing the catch part. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 399 visitBasicBlock(node.finallyBlock); | 455 visitBasicBlock(node.finallyBlock); |
| 400 indent--; | 456 indent--; |
| 401 } | 457 } |
| 402 addIndentation(); | 458 addIndentation(); |
| 403 buffer.add('}\n'); | 459 buffer.add('}\n'); |
| 404 | 460 |
| 405 visitBasicBlock(node.joinBlock); | 461 visitBasicBlock(node.joinBlock); |
| 406 } | 462 } |
| 407 | 463 |
| 408 visitIf(HIf node) { | 464 visitIf(HIf node) { |
| 465 List<HBasicBlock> dominated = node.block.dominatedBlocks; |
| 409 startIf(node); | 466 startIf(node); |
| 410 assert(!node.generateAtUseSite()); | 467 assert(!node.generateAtUseSite()); |
| 411 startThen(node); | 468 startThen(node); |
| 469 assert(node.thenBlock === dominated[0]); |
| 412 visitBasicBlock(node.thenBlock); | 470 visitBasicBlock(node.thenBlock); |
| 471 int preVisitedBlocks = 1; |
| 413 endThen(node); | 472 endThen(node); |
| 414 if (node.hasElse) { | 473 if (node.hasElse) { |
| 415 startElse(node); | 474 startElse(node); |
| 475 assert(node.elseBlock === dominated[1]); |
| 416 visitBasicBlock(node.elseBlock); | 476 visitBasicBlock(node.elseBlock); |
| 477 preVisitedBlocks = 2; |
| 417 endElse(node); | 478 endElse(node); |
| 418 } | 479 } |
| 419 endIf(node); | 480 endIf(node); |
| 420 | 481 |
| 421 // Normally the HIf dominates the join-block. In this case there is one | 482 // Visit all the dominated blocks that are not part of the then or else |
| 422 // dominated block that we need to visit: | 483 // branches. Depending on how the then/else branches terminate |
| 423 // If both the then and else blocks return/throw, then the join-block is | 484 // (e.g., return/throw/break) there can be any number of these. |
| 424 // either the exit-block, or there is none. | |
| 425 // We can also have the case where the HIf has no else, but the then-branch | |
| 426 // terminates. If the code after the 'if' terminates, then the | |
| 427 // if could become the dominator of the exit-block, thus having | |
| 428 // three dominated blocks: the then, the code after the if, and the exit | |
| 429 // block. | |
| 430 | |
| 431 List<HBasicBlock> dominated = node.block.dominatedBlocks; | |
| 432 int dominatedCount = dominated.length; | 485 int dominatedCount = dominated.length; |
| 433 if (node.hasElse && (dominatedCount == 3 || dominatedCount == 4)) { | 486 for (int i = preVisitedBlocks; i < dominatedCount; i++) { |
| 434 // Normal case. The third dominated block is either the join-block or | 487 HBasicBlock dominatedBlock = dominated[i]; |
| 435 // the exit-block (if both branches terminate). | 488 assert(dominatedBlock.dominator === node.block); |
| 436 // If the if dominates 4 blocks, then at least one branch does a | 489 visitBasicBlock(dominatedBlock); |
| 437 // conditional return, and the 4th block is the exit-block. | |
| 438 assert(dominatedCount != 4 || dominated.last().isExitBlock()); | |
| 439 visitBasicBlock(dominated[2]); | |
| 440 } else if (node.hasElse) { | |
| 441 // Both branches terminate, but this HIf is not the dominator of the exit | |
| 442 // block. | |
| 443 assert(dominatedCount == 2); | |
| 444 } else if (!node.hasElse && dominatedCount == 2) { | |
| 445 // Normal case. Even if the then-branch terminated there is still | |
| 446 // a join-block. | |
| 447 assert(!dominated.last().isExitBlock()); | |
| 448 visitBasicBlock(dominated[1]); | |
| 449 } else { | |
| 450 // The then-branch terminates, and the code following the if terminates | |
| 451 // too. The if happens to dominate the exit-block. | |
| 452 assert(!node.hasElse); | |
| 453 assert(dominatedCount == 3); | |
| 454 assert(dominated.last().isExitBlock()); | |
| 455 visitBasicBlock(dominated[1]); | |
| 456 visitBasicBlock(dominated[2]); | |
| 457 } | 490 } |
| 458 } | 491 } |
| 459 | 492 |
| 460 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 493 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 461 beginExpression(JSPrecedence.CALL_PRECEDENCE); | 494 beginExpression(JSPrecedence.CALL_PRECEDENCE); |
| 462 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 495 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 463 buffer.add('.'); | 496 buffer.add('.'); |
| 464 // Avoid adding the generative constructor name to the list of | 497 // Avoid adding the generative constructor name to the list of |
| 465 // seen selectors. | 498 // seen selectors. |
| 466 if (node.inputs[0] is HForeignNew) { | 499 if (node.inputs[0] is HForeignNew) { |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 visitLoopBranch(HLoopBranch node) { | 667 visitLoopBranch(HLoopBranch node) { |
| 635 HBasicBlock branchBlock = currentBlock; | 668 HBasicBlock branchBlock = currentBlock; |
| 636 handleLoopCondition(node); | 669 handleLoopCondition(node); |
| 637 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; | 670 List<HBasicBlock> dominated = currentBlock.dominatedBlocks; |
| 638 // For a do while loop, the body has already been visited. | 671 // For a do while loop, the body has already been visited. |
| 639 if (!node.isDoWhile()) { | 672 if (!node.isDoWhile()) { |
| 640 visitBasicBlock(dominated[0]); | 673 visitBasicBlock(dominated[0]); |
| 641 } | 674 } |
| 642 endLoop(node.block); | 675 endLoop(node.block); |
| 643 visitBasicBlock(branchBlock.successors[1]); | 676 visitBasicBlock(branchBlock.successors[1]); |
| 644 // TODO(floitsch): with labeled breaks we can have more dominated blocks. | 677 // With labeled breaks we can have more dominated blocks. |
| 645 assert(dominated.length <= 3); | 678 if (dominated.length >= 3) { |
| 646 if (dominated.length == 3) { | 679 for (int i = 2; i < dominated.length; i++) { |
| 647 // This happens when the body contains a 'return', and the exit-block is | 680 visitBasicBlock(dominated[i]); |
| 648 // not dominated by a dominator of the while loop. | 681 } |
| 649 assert(dominated[2].isExitBlock()); | |
| 650 visitBasicBlock(dominated[2]); | |
| 651 } | 682 } |
| 652 } | 683 } |
| 653 | 684 |
| 654 visitNot(HNot node) { | 685 visitNot(HNot node) { |
| 655 assert(node.inputs.length == 1); | 686 assert(node.inputs.length == 1); |
| 656 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 687 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 657 buffer.add('!'); | 688 buffer.add('!'); |
| 658 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); | 689 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE); |
| 659 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | 690 endExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 660 } | 691 } |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 checkArray(input, '!=='); | 1037 checkArray(input, '!=='); |
| 1007 buffer.add(')) '); | 1038 buffer.add(')) '); |
| 1008 bailout(node, 'Not a string or array'); | 1039 bailout(node, 'Not a string or array'); |
| 1009 } else { | 1040 } else { |
| 1010 unreachable(); | 1041 unreachable(); |
| 1011 } | 1042 } |
| 1012 } | 1043 } |
| 1013 | 1044 |
| 1014 void beginLoop(HBasicBlock block) { | 1045 void beginLoop(HBasicBlock block) { |
| 1015 addIndentation(); | 1046 addIndentation(); |
| 1047 for (SourceString label in block.loopInformation.labels) { |
| 1048 buffer.add("${label.stringValue}:"); |
| 1049 } |
| 1016 buffer.add('while (true) {\n'); | 1050 buffer.add('while (true) {\n'); |
| 1017 indent++; | 1051 indent++; |
| 1018 } | 1052 } |
| 1019 | 1053 |
| 1020 void endLoop(HBasicBlock block) { | 1054 void endLoop(HBasicBlock block) { |
| 1021 indent--; | 1055 indent--; |
| 1022 addIndentation(); | 1056 addIndentation(); |
| 1023 buffer.add('}\n'); // Close 'while' loop. | 1057 buffer.add('}\n'); // Close 'while' loop. |
| 1024 } | 1058 } |
| 1025 | 1059 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1167 indent++; | 1201 indent++; |
| 1168 } | 1202 } |
| 1169 | 1203 |
| 1170 void endBailoutSwitch() { | 1204 void endBailoutSwitch() { |
| 1171 indent--; // Close 'case'. | 1205 indent--; // Close 'case'. |
| 1172 indent--; | 1206 indent--; |
| 1173 addIndentation(); | 1207 addIndentation(); |
| 1174 buffer.add('}\n'); // Close 'switch'. | 1208 buffer.add('}\n'); // Close 'switch'. |
| 1175 } | 1209 } |
| 1176 | 1210 |
| 1211 // Adds a "$" in front of names of labels from the original source. |
| 1212 // This avoids conflicts with labels introduced by bailouts, which |
| 1213 // starts with a non-"$" character. |
| 1214 void addLabel(SourceString label) { |
| 1215 buffer.add("\$$label"); |
| 1216 } |
| 1217 |
| 1177 void beginLoop(HBasicBlock block) { | 1218 void beginLoop(HBasicBlock block) { |
| 1178 // TODO(ngeoffray): Don't put labels on loops that don't bailout. | 1219 // TODO(ngeoffray): Don't put labels on loops that don't bailout. |
| 1179 String newLabel = pushLabel(); | 1220 String newLabel = pushLabel(); |
| 1180 if (block.hasBailouts()) { | 1221 if (block.hasBailouts()) { |
| 1181 startBailoutCase(block.bailouts, const <HBailoutTarget>[]); | 1222 startBailoutCase(block.bailouts, const <HBailoutTarget>[]); |
| 1182 } | 1223 } |
| 1183 | 1224 |
| 1184 addIndentation(); | 1225 addIndentation(); |
| 1226 for (SourceString label in block.loopInformation.labels) { |
| 1227 addLabel(label); |
| 1228 buffer.add(":"); |
| 1229 } |
| 1185 buffer.add('$newLabel: while (true) {\n'); | 1230 buffer.add('$newLabel: while (true) {\n'); |
| 1186 indent++; | 1231 indent++; |
| 1187 | 1232 |
| 1188 if (block.hasBailouts()) { | 1233 if (block.hasBailouts()) { |
| 1189 startBailoutSwitch(); | 1234 startBailoutSwitch(); |
| 1190 } | 1235 } |
| 1191 } | 1236 } |
| 1192 | 1237 |
| 1193 void endLoop(HBasicBlock block) { | 1238 void endLoop(HBasicBlock block) { |
| 1194 popLabel(); | 1239 popLabel(); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1264 startBailoutSwitch(); | 1309 startBailoutSwitch(); |
| 1265 } | 1310 } |
| 1266 } | 1311 } |
| 1267 | 1312 |
| 1268 void endElse(HIf node) { | 1313 void endElse(HIf node) { |
| 1269 if (node.elseBlock.hasBailouts()) { | 1314 if (node.elseBlock.hasBailouts()) { |
| 1270 endBailoutSwitch(); | 1315 endBailoutSwitch(); |
| 1271 } | 1316 } |
| 1272 } | 1317 } |
| 1273 } | 1318 } |
| OLD | NEW |