| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 /** | 94 /** |
| 95 * Keeps track of locals (including parameters and phis) when building. The | 95 * Keeps track of locals (including parameters and phis) when building. The |
| 96 * 'this' reference is treated as parameter and hence handled by this class, | 96 * 'this' reference is treated as parameter and hence handled by this class, |
| 97 * too. | 97 * too. |
| 98 */ | 98 */ |
| 99 class LocalsHandler { | 99 class LocalsHandler { |
| 100 /** | 100 /** |
| 101 * The values of locals that can be directly accessed (without redirections | 101 * The values of locals that can be directly accessed (without redirections |
| 102 * to boxes or closure-fields). | 102 * to boxes or closure-fields). |
| 103 * | 103 * |
| 104 * [directLocals] is iterated, so it is a [LinkedHashMap] to make the | 104 * [directLocals] is iterated, so it is "insertion ordered" to make the |
| 105 * iteration order a function only of insertions and not a function of | 105 * iteration order a function only of insertions and not a function of |
| 106 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements | 106 * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements |
| 107 * don't have source locations for [Elements.compareByPosition]. | 107 * don't have source locations for [Elements.compareByPosition]. |
| 108 */ | 108 */ |
| 109 LinkedHashMap<Element, HInstruction> directLocals; | 109 Map<Element, HInstruction> directLocals; |
| 110 Map<Element, Element> redirectionMapping; | 110 Map<Element, Element> redirectionMapping; |
| 111 SsaBuilder builder; | 111 SsaBuilder builder; |
| 112 ClosureClassMap closureData; | 112 ClosureClassMap closureData; |
| 113 | 113 |
| 114 LocalsHandler(this.builder) | 114 LocalsHandler(this.builder) |
| 115 : directLocals = new LinkedHashMap<Element, HInstruction>(), | 115 : directLocals = new Map<Element, HInstruction>(), |
| 116 redirectionMapping = new Map<Element, Element>(); | 116 redirectionMapping = new Map<Element, Element>(); |
| 117 | 117 |
| 118 get typesTask => builder.compiler.typesTask; | 118 get typesTask => builder.compiler.typesTask; |
| 119 | 119 |
| 120 /** | 120 /** |
| 121 * Creates a new [LocalsHandler] based on [other]. We only need to | 121 * Creates a new [LocalsHandler] based on [other]. We only need to |
| 122 * copy the [directLocals], since the other fields can be shared | 122 * copy the [directLocals], since the other fields can be shared |
| 123 * throughout the AST visit. | 123 * throughout the AST visit. |
| 124 */ | 124 */ |
| 125 LocalsHandler.from(LocalsHandler other) | 125 LocalsHandler.from(LocalsHandler other) |
| 126 : directLocals = | 126 : directLocals = new Map<Element, HInstruction>.from(other.directLocals), |
| 127 new LinkedHashMap<Element, HInstruction>.from(other.directLocals), | |
| 128 redirectionMapping = other.redirectionMapping, | 127 redirectionMapping = other.redirectionMapping, |
| 129 builder = other.builder, | 128 builder = other.builder, |
| 130 closureData = other.closureData; | 129 closureData = other.closureData; |
| 131 | 130 |
| 132 /** | 131 /** |
| 133 * Redirects accesses from element [from] to element [to]. The [to] element | 132 * Redirects accesses from element [from] to element [to]. The [to] element |
| 134 * must be a boxed variable or a variable that is stored in a closure-field. | 133 * must be a boxed variable or a variable that is stored in a closure-field. |
| 135 */ | 134 */ |
| 136 void redirectElement(Element from, Element to) { | 135 void redirectElement(Element from, Element to) { |
| 137 assert(redirectionMapping[from] == null); | 136 assert(redirectionMapping[from] == null); |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 } | 496 } |
| 498 } | 497 } |
| 499 | 498 |
| 500 /** | 499 /** |
| 501 * Create phis at the loop entry for local variables (ready for the values | 500 * Create phis at the loop entry for local variables (ready for the values |
| 502 * from the back edge). Populate the phis with the current values. | 501 * from the back edge). Populate the phis with the current values. |
| 503 */ | 502 */ |
| 504 void beginLoopHeader(HBasicBlock loopEntry) { | 503 void beginLoopHeader(HBasicBlock loopEntry) { |
| 505 // Create a copy because we modify the map while iterating over it. | 504 // Create a copy because we modify the map while iterating over it. |
| 506 Map<Element, HInstruction> savedDirectLocals = | 505 Map<Element, HInstruction> savedDirectLocals = |
| 507 new LinkedHashMap<Element, HInstruction>.from(directLocals); | 506 new Map<Element, HInstruction>.from(directLocals); |
| 508 | 507 |
| 509 // Create phis for all elements in the definitions environment. | 508 // Create phis for all elements in the definitions environment. |
| 510 savedDirectLocals.forEach((Element element, HInstruction instruction) { | 509 savedDirectLocals.forEach((Element element, HInstruction instruction) { |
| 511 if (isAccessedDirectly(element)) { | 510 if (isAccessedDirectly(element)) { |
| 512 // We know 'this' cannot be modified. | 511 // We know 'this' cannot be modified. |
| 513 if (!identical(element, closureData.thisElement)) { | 512 if (!identical(element, closureData.thisElement)) { |
| 514 HPhi phi = new HPhi.singleInput(element, instruction); | 513 HPhi phi = new HPhi.singleInput(element, instruction); |
| 515 loopEntry.addPhi(phi); | 514 loopEntry.addPhi(phi); |
| 516 directLocals[element] = phi; | 515 directLocals[element] = phi; |
| 517 } else { | 516 } else { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 * If a phi node is necessary, it will use this handler's instruction as the | 564 * If a phi node is necessary, it will use this handler's instruction as the |
| 566 * first input, and the otherLocals instruction as the second. | 565 * first input, and the otherLocals instruction as the second. |
| 567 */ | 566 */ |
| 568 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 567 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 569 // If an element is in one map but not the other we can safely | 568 // If an element is in one map but not the other we can safely |
| 570 // ignore it. It means that a variable was declared in the | 569 // ignore it. It means that a variable was declared in the |
| 571 // block. Since variable declarations are scoped the declared | 570 // block. Since variable declarations are scoped the declared |
| 572 // variable cannot be alive outside the block. Note: this is only | 571 // variable cannot be alive outside the block. Note: this is only |
| 573 // true for nodes where we do joins. | 572 // true for nodes where we do joins. |
| 574 Map<Element, HInstruction> joinedLocals = | 573 Map<Element, HInstruction> joinedLocals = |
| 575 new LinkedHashMap<Element, HInstruction>(); | 574 new Map<Element, HInstruction>(); |
| 576 otherLocals.directLocals.forEach((element, instruction) { | 575 otherLocals.directLocals.forEach((element, instruction) { |
| 577 // We know 'this' cannot be modified. | 576 // We know 'this' cannot be modified. |
| 578 if (identical(element, closureData.thisElement)) { | 577 if (identical(element, closureData.thisElement)) { |
| 579 assert(directLocals[element] == instruction); | 578 assert(directLocals[element] == instruction); |
| 580 joinedLocals[element] = instruction; | 579 joinedLocals[element] = instruction; |
| 581 } else { | 580 } else { |
| 582 HInstruction mine = directLocals[element]; | 581 HInstruction mine = directLocals[element]; |
| 583 if (mine == null) return; | 582 if (mine == null) return; |
| 584 if (identical(instruction, mine)) { | 583 if (identical(instruction, mine)) { |
| 585 joinedLocals[element] = instruction; | 584 joinedLocals[element] = instruction; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 599 * localsHandlers into a new one using phis. The new localsHandler is | 598 * localsHandlers into a new one using phis. The new localsHandler is |
| 600 * returned. Unless it is also in the list, the current localsHandler is not | 599 * returned. Unless it is also in the list, the current localsHandler is not |
| 601 * used for its values, only for its declared variables. This is a way to | 600 * used for its values, only for its declared variables. This is a way to |
| 602 * exclude local values from the result when they are no longer in scope. | 601 * exclude local values from the result when they are no longer in scope. |
| 603 */ | 602 */ |
| 604 LocalsHandler mergeMultiple(List<LocalsHandler> localsHandlers, | 603 LocalsHandler mergeMultiple(List<LocalsHandler> localsHandlers, |
| 605 HBasicBlock joinBlock) { | 604 HBasicBlock joinBlock) { |
| 606 assert(localsHandlers.length > 0); | 605 assert(localsHandlers.length > 0); |
| 607 if (localsHandlers.length == 1) return localsHandlers[0]; | 606 if (localsHandlers.length == 1) return localsHandlers[0]; |
| 608 Map<Element, HInstruction> joinedLocals = | 607 Map<Element, HInstruction> joinedLocals = |
| 609 new LinkedHashMap<Element,HInstruction>(); | 608 new Map<Element,HInstruction>(); |
| 610 HInstruction thisValue = null; | 609 HInstruction thisValue = null; |
| 611 directLocals.forEach((Element element, HInstruction instruction) { | 610 directLocals.forEach((Element element, HInstruction instruction) { |
| 612 if (element != closureData.thisElement) { | 611 if (element != closureData.thisElement) { |
| 613 HPhi phi = new HPhi.noInputs(element); | 612 HPhi phi = new HPhi.noInputs(element); |
| 614 joinedLocals[element] = phi; | 613 joinedLocals[element] = phi; |
| 615 joinBlock.addPhi(phi); | 614 joinBlock.addPhi(phi); |
| 616 } else { | 615 } else { |
| 617 // We know that "this" never changes, if it's there. | 616 // We know that "this" never changes, if it's there. |
| 618 // Save it for later. While merging, there is no phi for "this", | 617 // Save it for later. While merging, there is no phi for "this", |
| 619 // so we don't have to special case it in the merge loop. | 618 // so we don't have to special case it in the merge loop. |
| 620 thisValue = instruction; | 619 thisValue = instruction; |
| 621 } | 620 } |
| 622 }); | 621 }); |
| 623 for (LocalsHandler handler in localsHandlers) { | 622 for (LocalsHandler handler in localsHandlers) { |
| 624 handler.directLocals.forEach((Element element, HInstruction instruction) { | 623 handler.directLocals.forEach((Element element, HInstruction instruction) { |
| 625 HPhi phi = joinedLocals[element]; | 624 HPhi phi = joinedLocals[element]; |
| 626 if (phi != null) { | 625 if (phi != null) { |
| 627 phi.addInput(instruction); | 626 phi.addInput(instruction); |
| 628 } | 627 } |
| 629 }); | 628 }); |
| 630 } | 629 } |
| 631 if (thisValue != null) { | 630 if (thisValue != null) { |
| 632 // If there was a "this" for the scope, add it to the new locals. | 631 // If there was a "this" for the scope, add it to the new locals. |
| 633 joinedLocals[closureData.thisElement] = thisValue; | 632 joinedLocals[closureData.thisElement] = thisValue; |
| 634 } | 633 } |
| 635 | 634 |
| 636 // Remove locals that are not in all handlers. | 635 // Remove locals that are not in all handlers. |
| 637 directLocals = new LinkedHashMap<Element, HInstruction>(); | 636 directLocals = new Map<Element, HInstruction>(); |
| 638 joinedLocals.forEach((element, instruction) { | 637 joinedLocals.forEach((element, instruction) { |
| 639 if (instruction is HPhi | 638 if (instruction is HPhi |
| 640 && instruction.inputs.length != localsHandlers.length) { | 639 && instruction.inputs.length != localsHandlers.length) { |
| 641 joinBlock.removePhi(instruction); | 640 joinBlock.removePhi(instruction); |
| 642 } else { | 641 } else { |
| 643 directLocals[element] = instruction; | 642 directLocals[element] = instruction; |
| 644 } | 643 } |
| 645 }); | 644 }); |
| 646 return this; | 645 return this; |
| 647 } | 646 } |
| (...skipping 4971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5619 new HSubGraphBlockInformation(elseBranch.graph)); | 5618 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5620 | 5619 |
| 5621 HBasicBlock conditionStartBlock = conditionBranch.block; | 5620 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5622 conditionStartBlock.setBlockFlow(info, joinBlock); | 5621 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5623 SubGraph conditionGraph = conditionBranch.graph; | 5622 SubGraph conditionGraph = conditionBranch.graph; |
| 5624 HIf branch = conditionGraph.end.last; | 5623 HIf branch = conditionGraph.end.last; |
| 5625 assert(branch is HIf); | 5624 assert(branch is HIf); |
| 5626 branch.blockInformation = conditionStartBlock.blockFlow; | 5625 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5627 } | 5626 } |
| 5628 } | 5627 } |
| OLD | NEW |