| 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 Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 581 loopEntry.forEachPhi((HPhi phi) { | 581 loopEntry.forEachPhi((HPhi phi) { |
| 582 Element element = phi.sourceElement; | 582 Element element = phi.sourceElement; |
| 583 HInstruction postLoopDefinition = directLocals[element]; | 583 HInstruction postLoopDefinition = directLocals[element]; |
| 584 phi.addInput(postLoopDefinition); | 584 phi.addInput(postLoopDefinition); |
| 585 }); | 585 }); |
| 586 } | 586 } |
| 587 | 587 |
| 588 /** | 588 /** |
| 589 * Merge [otherLocals] into this locals handler, creating phi-nodes when | 589 * Merge [otherLocals] into this locals handler, creating phi-nodes when |
| 590 * there is a conflict. | 590 * there is a conflict. |
| 591 * If a phi node is necessary, it will use the otherLocals instruction as the | 591 * If a phi node is necessary, it will use this handler's instruction as the |
| 592 * first input, and this handler's instruction as the second. | 592 * first input, and the otherLocals instruction as the second. |
| 593 * NOTICE: This means that the predecessor corresponding to [otherLocals] | |
| 594 * should be the first predecessor of the current block, and the one | |
| 595 * corresponding to this locals handler should be the second. | |
| 596 */ | 593 */ |
| 597 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 594 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 598 // If an element is in one map but not the other we can safely | 595 // If an element is in one map but not the other we can safely |
| 599 // ignore it. It means that a variable was declared in the | 596 // ignore it. It means that a variable was declared in the |
| 600 // block. Since variable declarations are scoped the declared | 597 // block. Since variable declarations are scoped the declared |
| 601 // variable cannot be alive outside the block. Note: this is only | 598 // variable cannot be alive outside the block. Note: this is only |
| 602 // true for nodes where we do joins. | 599 // true for nodes where we do joins. |
| 603 Map<Element, HInstruction> joinedLocals = new Map<Element, HInstruction>(); | 600 Map<Element, HInstruction> joinedLocals = new Map<Element, HInstruction>(); |
| 604 otherLocals.directLocals.forEach((element, instruction) { | 601 otherLocals.directLocals.forEach((element, instruction) { |
| 605 // We know 'this' cannot be modified. | 602 // We know 'this' cannot be modified. |
| 606 if (element === closureData.thisElement) { | 603 if (element === closureData.thisElement) { |
| 607 assert(directLocals[element] == instruction); | 604 assert(directLocals[element] == instruction); |
| 608 joinedLocals[element] = instruction; | 605 joinedLocals[element] = instruction; |
| 609 } else { | 606 } else { |
| 610 HInstruction mine = directLocals[element]; | 607 HInstruction mine = directLocals[element]; |
| 611 if (mine === null) return; | 608 if (mine === null) return; |
| 612 if (instruction === mine) { | 609 if (instruction === mine) { |
| 613 joinedLocals[element] = instruction; | 610 joinedLocals[element] = instruction; |
| 614 } else { | 611 } else { |
| 615 HInstruction phi = | 612 HInstruction phi = |
| 616 new HPhi.manyInputs(element, <HInstruction>[instruction, mine]); | 613 new HPhi.manyInputs(element, <HInstruction>[mine, instruction]); |
| 617 joinBlock.addPhi(phi); | 614 joinBlock.addPhi(phi); |
| 618 joinedLocals[element] = phi; | 615 joinedLocals[element] = phi; |
| 619 } | 616 } |
| 620 } | 617 } |
| 621 }); | 618 }); |
| 622 directLocals = joinedLocals; | 619 directLocals = joinedLocals; |
| 623 } | 620 } |
| 624 | 621 |
| 625 /** | 622 /** |
| 626 * The current localsHandler is not used for its values, only for its | 623 * The current localsHandler is not used for its values, only for its |
| (...skipping 2757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3384 node.visitChildren(this); | 3381 node.visitChildren(this); |
| 3385 } | 3382 } |
| 3386 | 3383 |
| 3387 HInstruction concat(HInstruction left, HInstruction right) { | 3384 HInstruction concat(HInstruction left, HInstruction right) { |
| 3388 HInstruction instruction = new HStringConcat(left, right, diagnosticNode); | 3385 HInstruction instruction = new HStringConcat(left, right, diagnosticNode); |
| 3389 builder.add(instruction); | 3386 builder.add(instruction); |
| 3390 return instruction; | 3387 return instruction; |
| 3391 } | 3388 } |
| 3392 } | 3389 } |
| 3393 | 3390 |
| 3391 class SsaBranch { |
| 3392 final SsaBranchBuilder branchBuilder; |
| 3393 final HBasicBlock block; |
| 3394 LocalsHandler startLocals; |
| 3395 LocalsHandler exitLocals; |
| 3396 SubGraph graph; |
| 3397 |
| 3398 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); |
| 3399 } |
| 3400 |
| 3394 class SsaBranchBuilder { | 3401 class SsaBranchBuilder { |
| 3395 final SsaBuilder builder; | 3402 final SsaBuilder builder; |
| 3396 final Node diagnosticNode; | 3403 final Node diagnosticNode; |
| 3397 | 3404 |
| 3398 bool branchesHaveValues; | |
| 3399 HInstruction thenValue; | |
| 3400 HInstruction elseValue; | |
| 3401 // The locals-handler at the end of the condition block. | |
| 3402 LocalsHandler conditionLocals; | |
| 3403 LocalsHandler thenLocals; | |
| 3404 LocalsHandler elseLocals; | |
| 3405 SubGraph conditionGraph; | |
| 3406 SubGraph thenGraph; | |
| 3407 SubGraph elseGraph; | |
| 3408 | |
| 3409 SsaBranchBuilder(this.builder, [this.diagnosticNode]); | 3405 SsaBranchBuilder(this.builder, [this.diagnosticNode]); |
| 3410 | 3406 |
| 3411 Compiler get compiler() => builder.compiler; | 3407 Compiler get compiler() => builder.compiler; |
| 3412 | 3408 |
| 3413 void checkNotAborted() { | 3409 void checkNotAborted() { |
| 3414 if (builder.isAborted()) { | 3410 if (builder.isAborted()) { |
| 3415 compiler.unimplemented("aborted control flow", node: diagnosticNode); | 3411 compiler.unimplemented("aborted control flow", node: diagnosticNode); |
| 3416 } | 3412 } |
| 3417 } | 3413 } |
| 3418 | 3414 |
| 3419 SubGraph buildCondition(void doCondition()) { | 3415 void buildCondition(void visitCondition(), |
| 3420 HBasicBlock conditionStartBlock = builder.openNewBlock(); | 3416 SsaBranch conditionBranch, |
| 3421 doCondition(); | 3417 SsaBranch thenBranch, |
| 3418 SsaBranch elseBranch) { |
| 3419 startBranch(conditionBranch); |
| 3420 visitCondition(); |
| 3422 checkNotAborted(); | 3421 checkNotAborted(); |
| 3423 assert(builder.current === builder.lastOpenedBlock); | 3422 assert(builder.current === builder.lastOpenedBlock); |
| 3424 HInstruction condition = builder.popBoolified(); | 3423 HInstruction conditionValue = builder.popBoolified(); |
| 3425 HIf branch = new HIf(condition); | 3424 HIf branch = new HIf(conditionValue); |
| 3425 HBasicBlock conditionExitBlock = builder.current; |
| 3426 builder.close(branch); | 3426 builder.close(branch); |
| 3427 conditionBranch.exitLocals = builder.localsHandler; |
| 3428 conditionExitBlock.addSuccessor(thenBranch.block); |
| 3429 conditionExitBlock.addSuccessor(elseBranch.block); |
| 3430 bool conditionBranchLocalsCanBeReused = |
| 3431 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); |
| 3432 mergeLocals(conditionBranch, elseBranch, |
| 3433 mayReuseFromLocals: conditionBranchLocalsCanBeReused); |
| 3427 | 3434 |
| 3428 conditionGraph = | 3435 conditionBranch.graph = |
| 3429 new SubExpression(conditionStartBlock, builder.lastOpenedBlock); | 3436 new SubExpression(conditionBranch.block, conditionExitBlock); |
| 3430 conditionLocals = builder.localsHandler; | |
| 3431 return conditionGraph; | |
| 3432 } | 3437 } |
| 3433 | 3438 |
| 3434 SubGraph buildThen(void visitThen(), LocalsHandler locals) { | 3439 /** |
| 3435 builder.localsHandler = locals; | 3440 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] |
| 3436 HBasicBlock thenBlock = builder.addNewBlock(); | 3441 * return value implies that [mayReuseFromLocals] was set to [:true:]. |
| 3437 conditionGraph.end.addSuccessor(thenBlock); | 3442 */ |
| 3438 builder.open(thenBlock); | 3443 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, |
| 3439 visitThen(); | 3444 [bool mayReuseFromLocals]) { |
| 3440 if (branchesHaveValues) { | 3445 LocalsHandler fromLocals = fromBranch.exitLocals; |
| 3441 checkNotAborted(); | 3446 if (toBranch.startLocals == null) { |
| 3442 thenValue = builder.pop(); | 3447 if (mayReuseFromLocals) { |
| 3448 toBranch.startLocals = fromLocals; |
| 3449 return false; |
| 3450 } else { |
| 3451 toBranch.startLocals = new LocalsHandler.from(fromLocals); |
| 3452 return true; |
| 3453 } |
| 3454 } else { |
| 3455 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); |
| 3456 return true; |
| 3443 } | 3457 } |
| 3444 thenGraph = new SubGraph(thenBlock, builder.lastOpenedBlock); | |
| 3445 thenLocals = builder.localsHandler; | |
| 3446 return thenGraph; | |
| 3447 } | 3458 } |
| 3448 | 3459 |
| 3449 SubGraph buildElse(void visitElse(), LocalsHandler locals) { | 3460 void startBranch(SsaBranch branch) { |
| 3450 builder.localsHandler = locals; | 3461 builder.graph.addBlock(branch.block); |
| 3451 HBasicBlock elseBlock = builder.addNewBlock(); | 3462 builder.localsHandler = branch.startLocals; |
| 3452 conditionGraph.end.addSuccessor(elseBlock); | 3463 builder.open(branch.block); |
| 3453 builder.open(elseBlock); | |
| 3454 visitElse(); | |
| 3455 if (branchesHaveValues) { | |
| 3456 checkNotAborted(); | |
| 3457 elseValue = builder.pop(); | |
| 3458 } | |
| 3459 elseGraph = new SubGraph(elseBlock, builder.lastOpenedBlock); | |
| 3460 elseLocals = builder.localsHandler; | |
| 3461 return elseGraph; | |
| 3462 } | 3464 } |
| 3463 | 3465 |
| 3464 HBasicBlock join() { | 3466 HInstruction buildBranch(SsaBranch branch, |
| 3465 HBasicBlock joinBlock = null; | 3467 void visitBranch(), |
| 3466 HBasicBlock thenBlock = thenGraph.end; | 3468 SsaBranch joinBranch, |
| 3467 HBasicBlock elseBlock = elseGraph.end; | 3469 bool isExpression) { |
| 3468 // If the last instruction is already a control-flow instruction then the | 3470 startBranch(branch); |
| 3469 // block has been aborted. | 3471 visitBranch(); |
| 3470 if (thenBlock.last is HControlFlow) thenBlock = null; | 3472 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); |
| 3471 if (elseBlock.last is HControlFlow) elseBlock = null; | 3473 branch.exitLocals = builder.localsHandler; |
| 3472 | 3474 if (!builder.isAborted()) { |
| 3473 if (thenBlock !== null || elseBlock !== null) { | 3475 builder.goto(builder.current, joinBranch.block); |
| 3474 joinBlock = builder.addNewBlock(); | 3476 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); |
| 3475 if (thenBlock !== null) builder.goto(thenBlock, joinBlock); | |
| 3476 if (elseBlock !== null) builder.goto(elseBlock, joinBlock); | |
| 3477 // If the join block has two predecessors we have to merge the | |
| 3478 // locals. The current locals is what either the | |
| 3479 // condition or the else block left us with, so we merge that | |
| 3480 // with the set of locals we got after visiting the then | |
| 3481 // part of the if. | |
| 3482 builder.open(joinBlock); | |
| 3483 if (joinBlock.predecessors.length == 2) { | |
| 3484 builder.localsHandler.mergeWith(thenLocals, joinBlock); | |
| 3485 if (branchesHaveValues) { | |
| 3486 assert(thenValue !== null); | |
| 3487 assert(elseValue !== null); | |
| 3488 HPhi phi = new HPhi.manyInputs(null, | |
| 3489 <HInstruction>[thenValue, elseValue]); | |
| 3490 joinBlock.addPhi(phi); | |
| 3491 builder.stack.add(phi); | |
| 3492 } | |
| 3493 } else if (thenBlock !== null) { | |
| 3494 // The only predecessor is the then branch. | |
| 3495 builder.localsHandler = thenLocals; | |
| 3496 } else { | |
| 3497 assert(builder.localsHandler == elseLocals); | |
| 3498 } | |
| 3499 } | 3477 } |
| 3500 return builder.current; | 3478 if (isExpression) { |
| 3479 checkNotAborted(); |
| 3480 return builder.pop(); |
| 3481 } |
| 3482 return null; |
| 3501 } | 3483 } |
| 3502 | 3484 |
| 3503 handleIf(void visitCondition(), void visitThen(), void visitElse()) { | 3485 handleIf(void visitCondition(), void visitThen(), void visitElse()) { |
| 3486 if (visitElse == null) { |
| 3487 // Make sure to have an else part to avoid a critical edge. A |
| 3488 // critical edge is an edge that connects a block with multiple |
| 3489 // successors to a block with multiple predecessors. We avoid |
| 3490 // such edges because they prevent inserting copies during code |
| 3491 // generation of phi instructions. |
| 3492 visitElse = () {}; |
| 3493 } |
| 3494 |
| 3504 _handleDiamondBranch(visitCondition, visitThen, visitElse, false); | 3495 _handleDiamondBranch(visitCondition, visitThen, visitElse, false); |
| 3505 } | 3496 } |
| 3506 | 3497 |
| 3507 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { | 3498 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { |
| 3499 assert(visitElse != null); |
| 3508 _handleDiamondBranch(visitCondition, visitThen, visitElse, true); | 3500 _handleDiamondBranch(visitCondition, visitThen, visitElse, true); |
| 3509 } | 3501 } |
| 3510 | 3502 |
| 3511 void _handleDiamondBranch(void visitCondition(), | 3503 void _handleDiamondBranch(void visitCondition(), |
| 3512 void visitThen(), | 3504 void visitThen(), |
| 3513 void visitElse(), | 3505 void visitElse(), |
| 3514 bool isExpression) { | 3506 bool isExpression) { |
| 3515 branchesHaveValues = isExpression; | 3507 SsaBranch conditionBranch = new SsaBranch(this); |
| 3516 if (visitElse == null) { | 3508 SsaBranch thenBranch = new SsaBranch(this); |
| 3517 if (isExpression) { | 3509 SsaBranch elseBranch = new SsaBranch(this); |
| 3518 compiler.internalError("Diamond branch with values but without else.", | 3510 SsaBranch joinBranch = new SsaBranch(this); |
| 3519 node: diagnosticNode); | 3511 |
| 3520 } | 3512 conditionBranch.startLocals = builder.localsHandler; |
| 3521 // Make sure to have an else part to avoid a critical edge. A | 3513 builder.goto(builder.current, conditionBranch.block); |
| 3522 // critical edge is an edge that connects a block with multiple | 3514 |
| 3523 // successors to a block with multiple predecessors. We avoid | 3515 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch); |
| 3524 // such edges because they prevent inserting copies during code | 3516 HInstruction thenValue = |
| 3525 // generation of phi instructions. | 3517 buildBranch(thenBranch, visitThen, joinBranch, isExpression); |
| 3526 visitElse = () {}; | 3518 HInstruction elseValue = |
| 3519 buildBranch(elseBranch, visitElse, joinBranch, isExpression); |
| 3520 |
| 3521 if (isExpression) { |
| 3522 assert(thenValue != null && elseValue != null); |
| 3523 HPhi phi = |
| 3524 new HPhi.manyInputs(null, <HInstruction>[thenValue, elseValue]); |
| 3525 joinBranch.block.addPhi(phi); |
| 3526 builder.stack.add(phi); |
| 3527 } | 3527 } |
| 3528 | 3528 |
| 3529 buildCondition(visitCondition); | 3529 HBasicBlock thenBlock = thenBranch.block; |
| 3530 buildThen(visitThen, new LocalsHandler.from(conditionLocals)); | 3530 HBasicBlock elseBlock = elseBranch.block; |
| 3531 // Use the locals state after the condition. We are the last ones to use the | 3531 HBasicBlock joinBlock; |
| 3532 // conditionLocals. So we don't need to make a copy of it. | 3532 // If at least one branch did not abort, open the joinBranch. |
| 3533 buildElse(visitElse, conditionLocals); | 3533 if (!joinBranch.block.predecessors.isEmpty()) { |
| 3534 HBasicBlock joinBlock = join(); | 3534 startBranch(joinBranch); |
| 3535 joinBlock = joinBranch.block; |
| 3536 } |
| 3535 | 3537 |
| 3536 HIfBlockInformation info = | 3538 HIfBlockInformation info = |
| 3537 new HIfBlockInformation( | 3539 new HIfBlockInformation( |
| 3538 new HSubExpressionBlockInformation(conditionGraph), | 3540 new HSubExpressionBlockInformation(conditionBranch.graph), |
| 3539 new HSubGraphBlockInformation(thenGraph), | 3541 new HSubGraphBlockInformation(thenBranch.graph), |
| 3540 new HSubGraphBlockInformation(elseGraph)); | 3542 new HSubGraphBlockInformation(elseBranch.graph)); |
| 3541 | 3543 |
| 3542 HBasicBlock conditionStartBlock = conditionGraph.start; | 3544 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 3543 conditionGraph.start.setBlockFlow(info, joinBlock); | 3545 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 3546 SubGraph conditionGraph = conditionBranch.graph; |
| 3544 HIf branch = conditionGraph.end.last; | 3547 HIf branch = conditionGraph.end.last; |
| 3545 assert(branch is HIf); | 3548 assert(branch is HIf); |
| 3546 branch.blockInformation = conditionStartBlock.blockFlow; | 3549 branch.blockInformation = conditionStartBlock.blockFlow; |
| 3547 } | 3550 } |
| 3548 } | 3551 } |
| OLD | NEW |