Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library tree_ir_builder; | 5 library tree_ir_builder; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree | 39 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree |
| 40 * control-flow recognition. | 40 * control-flow recognition. |
| 41 * | 41 * |
| 42 * Otherwise, the output of Builder looks very much like the input. In | 42 * Otherwise, the output of Builder looks very much like the input. In |
| 43 * particular, intermediate values and blocks used for local control flow are | 43 * particular, intermediate values and blocks used for local control flow are |
| 44 * still all named. | 44 * still all named. |
| 45 */ | 45 */ |
| 46 class Builder implements cps_ir.Visitor<Node> { | 46 class Builder implements cps_ir.Visitor<Node> { |
| 47 final dart2js.InternalErrorFunction internalError; | 47 final dart2js.InternalErrorFunction internalError; |
| 48 | 48 |
| 49 /// Maps variable/parameter elements to the Tree variables that represent it. | 49 final Map<cps_ir.Primitive, Variable> primitive2variable = |
|
Kevin Millikin (Google)
2015/03/20 11:12:03
I don't really like this naming convention. At th
asgerf
2015/03/31 12:14:19
I don't think of it as the type of the key. We map
| |
| 50 final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{}; | 50 <cps_ir.Primitive, Variable>{}; |
| 51 | 51 final Map<cps_ir.MutableVariable, Variable> mutable2variable = |
| 52 /// Like [local2variables], except for mutable variables. | |
| 53 final Map<cps_ir.MutableVariable, Variable> local2mutable = | |
| 54 <cps_ir.MutableVariable, Variable>{}; | 52 <cps_ir.MutableVariable, Variable>{}; |
| 55 | 53 |
| 56 // Continuations with more than one use are replaced with Tree labels. This | 54 // Continuations with more than one use are replaced with Tree labels. This |
| 57 // is the mapping from continuations to labels. | 55 // is the mapping from continuations to labels. |
| 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 56 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
| 59 | 57 |
| 60 /// A stack of singly-used labels that can be safely inlined at their use | 58 /// A stack of singly-used labels that can be safely inlined at their use |
| 61 /// site. | 59 /// site. |
| 62 /// | 60 /// |
| 63 /// Code for continuations with exactly one use is inlined at the use site. | 61 /// Code for continuations with exactly one use is inlined at the use site. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 76 Builder createInnerBuilder() { | 74 Builder createInnerBuilder() { |
| 77 return new Builder(internalError, this); | 75 return new Builder(internalError, this); |
| 78 } | 76 } |
| 79 | 77 |
| 80 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 78 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
| 81 /// variables. | 79 /// variables. |
| 82 Variable phiTempVar; | 80 Variable phiTempVar; |
| 83 | 81 |
| 84 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { | 82 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { |
| 85 assert(irVariable.host == currentElement); | 83 assert(irVariable.host == currentElement); |
| 86 assert(!local2mutable.containsKey(irVariable)); | 84 assert(!mutable2variable.containsKey(irVariable)); |
| 87 Variable variable = new Variable(currentElement, irVariable.hint); | 85 Variable variable = new Variable(currentElement, irVariable.hint); |
| 88 local2mutable[irVariable] = variable; | 86 mutable2variable[irVariable] = variable; |
| 89 return variable; | 87 return variable; |
| 90 } | 88 } |
| 91 | 89 |
| 92 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { | 90 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { |
| 93 if (mutableVariable.host != currentElement) { | 91 if (mutableVariable.host != currentElement) { |
| 94 return parent.getMutableVariable(mutableVariable)..isCaptured = true; | 92 return parent.getMutableVariable(mutableVariable)..isCaptured = true; |
| 95 } | 93 } |
| 96 return local2mutable[mutableVariable]; | 94 return mutable2variable[mutableVariable]; |
| 97 } | 95 } |
| 98 | 96 |
| 99 VariableUse getMutableVariableUse( | 97 VariableUse getMutableVariableUse( |
| 100 cps_ir.Reference<cps_ir.MutableVariable> reference) { | 98 cps_ir.Reference<cps_ir.MutableVariable> reference) { |
| 101 Variable variable = getMutableVariable(reference.definition); | 99 Variable variable = getMutableVariable(reference.definition); |
| 102 return new VariableUse(variable); | 100 return new VariableUse(variable); |
| 103 } | 101 } |
| 104 | 102 |
| 105 /// Obtains the variable representing the given primitive. Returns null for | 103 /// Obtains the variable representing the given primitive. Returns null for |
| 106 /// primitives that have no reference and do not need a variable. | 104 /// primitives that have no reference and do not need a variable. |
| 107 Variable getVariable(cps_ir.Primitive primitive) { | 105 Variable getVariable(cps_ir.Primitive primitive) { |
| 108 if (primitive.registerIndex == null) { | 106 return primitive2variable.putIfAbsent(primitive, |
| 109 return null; // variable is unused | 107 () => new Variable(currentElement, primitive.hint)); |
| 110 } | |
| 111 List<Variable> variables = local2variables.putIfAbsent(primitive.hint, | |
| 112 () => <Variable>[]); | |
| 113 while (variables.length <= primitive.registerIndex) { | |
| 114 variables.add(new Variable(currentElement, primitive.hint)); | |
| 115 } | |
| 116 return variables[primitive.registerIndex]; | |
| 117 } | 108 } |
| 118 | 109 |
| 119 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 110 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
| 120 /// referred to by [reference]. | 111 /// referred to by [reference]. |
| 121 /// This increments the reference count for the given variable, so the | 112 /// This increments the reference count for the given variable, so the |
| 122 /// returned expression must be used in the tree. | 113 /// returned expression must be used in the tree. |
| 123 VariableUse getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { | 114 VariableUse getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { |
| 124 Variable variable = getVariable(reference.definition); | 115 return new VariableUse(getVariable(reference.definition)); |
| 125 if (variable == null) { | |
| 126 // Note: this may fail because you forgot to implement a visit-function | |
| 127 // in the RegisterAllocator. | |
| 128 internalError( | |
| 129 CURRENT_ELEMENT_SPANNABLE, | |
| 130 "Reference to ${reference.definition} has no register"); | |
| 131 } | |
| 132 return new VariableUse(variable); | |
| 133 } | 116 } |
| 134 | 117 |
| 135 ExecutableDefinition build(cps_ir.ExecutableDefinition node) { | 118 ExecutableDefinition build(cps_ir.ExecutableDefinition node) { |
| 119 // TODO(asgerf): Don't have build AND buildXXX as public API. | |
| 136 if (node is cps_ir.FieldDefinition) { | 120 if (node is cps_ir.FieldDefinition) { |
| 137 return buildField(node); | 121 return buildField(node); |
| 138 } else if (node is cps_ir.ConstructorDefinition) { | 122 } else if (node is cps_ir.ConstructorDefinition) { |
| 139 return buildConstructor(node); | 123 return buildConstructor(node); |
| 140 } else { | 124 } else { |
| 141 assert(dart2js.invariant( | 125 assert(dart2js.invariant( |
| 142 CURRENT_ELEMENT_SPANNABLE, | 126 CURRENT_ELEMENT_SPANNABLE, |
| 143 node is cps_ir.FunctionDefinition, | 127 node is cps_ir.FunctionDefinition, |
| 144 message: 'expected FunctionDefinition or FieldDefinition, ' | 128 message: 'expected FunctionDefinition or FieldDefinition, ' |
| 145 ' found $node')); | 129 ' found $node')); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { | 206 List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { |
| 223 return new List<Variable>.generate(args.length, | 207 return new List<Variable>.generate(args.length, |
| 224 (int index) => getVariable(args[index].definition), | 208 (int index) => getVariable(args[index].definition), |
| 225 growable: false); | 209 growable: false); |
| 226 } | 210 } |
| 227 | 211 |
| 228 Statement buildContinuationAssignment( | 212 Statement buildContinuationAssignment( |
| 229 cps_ir.Parameter parameter, | 213 cps_ir.Parameter parameter, |
| 230 Expression argument, | 214 Expression argument, |
| 231 Statement buildRest()) { | 215 Statement buildRest()) { |
| 232 Variable variable = getVariable(parameter); | |
| 233 Statement assignment; | 216 Statement assignment; |
| 234 if (variable == null) { | 217 if (parameter.hasAtLeastOneUse) { |
| 218 Variable variable = getVariable(parameter); | |
| 219 assignment = new Assign(variable, argument, null); | |
| 220 } else { | |
| 235 assignment = new ExpressionStatement(argument, null); | 221 assignment = new ExpressionStatement(argument, null); |
| 236 } else { | |
| 237 assignment = new Assign(variable, argument, null); | |
| 238 } | 222 } |
| 239 assignment.next = buildRest(); | 223 assignment.next = buildRest(); |
| 240 return assignment; | 224 return assignment; |
| 241 } | 225 } |
| 242 | 226 |
| 243 /// Simultaneously assigns each argument to the corresponding parameter, | 227 /// Simultaneously assigns each argument to the corresponding parameter, |
| 244 /// then continues at the statement created by [buildRest]. | 228 /// then continues at the statement created by [buildRest]. |
| 245 Statement buildPhiAssignments( | 229 Statement buildPhiAssignments( |
| 246 List<cps_ir.Parameter> parameters, | 230 List<cps_ir.Parameter> parameters, |
| 247 List<Variable> arguments, | 231 List<Variable> arguments, |
| (...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 640 } | 624 } |
| 641 | 625 |
| 642 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { | 626 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { |
| 643 return new ReifyRuntimeType(getVariableUse(node.value)); | 627 return new ReifyRuntimeType(getVariableUse(node.value)); |
| 644 } | 628 } |
| 645 | 629 |
| 646 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { | 630 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { |
| 647 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); | 631 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); |
| 648 } | 632 } |
| 649 } | 633 } |
| 634 | |
| OLD | NEW |