| 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 = |
| 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 14 matching lines...) Expand all Loading... |
| 78 Builder createInnerBuilder() { | 76 Builder createInnerBuilder() { |
| 79 return new Builder(internalError, this); | 77 return new Builder(internalError, this); |
| 80 } | 78 } |
| 81 | 79 |
| 82 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 80 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
| 83 /// variables. | 81 /// variables. |
| 84 Variable phiTempVar; | 82 Variable phiTempVar; |
| 85 | 83 |
| 86 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { | 84 Variable addMutableVariable(cps_ir.MutableVariable irVariable) { |
| 87 assert(irVariable.host == currentElement); | 85 assert(irVariable.host == currentElement); |
| 88 assert(!local2mutable.containsKey(irVariable)); | 86 assert(!mutable2variable.containsKey(irVariable)); |
| 89 Variable variable = new Variable(currentElement, irVariable.hint); | 87 Variable variable = new Variable(currentElement, irVariable.hint); |
| 90 local2mutable[irVariable] = variable; | 88 mutable2variable[irVariable] = variable; |
| 91 return variable; | 89 return variable; |
| 92 } | 90 } |
| 93 | 91 |
| 94 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { | 92 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) { |
| 95 if (mutableVariable.host != currentElement) { | 93 if (mutableVariable.host != currentElement) { |
| 96 return parent.getMutableVariable(mutableVariable)..isCaptured = true; | 94 return parent.getMutableVariable(mutableVariable)..isCaptured = true; |
| 97 } | 95 } |
| 98 return local2mutable[mutableVariable]; | 96 return mutable2variable[mutableVariable]; |
| 99 } | 97 } |
| 100 | 98 |
| 101 VariableUse getMutableVariableUse( | 99 VariableUse getMutableVariableUse( |
| 102 cps_ir.Reference<cps_ir.MutableVariable> reference) { | 100 cps_ir.Reference<cps_ir.MutableVariable> reference) { |
| 103 Variable variable = getMutableVariable(reference.definition); | 101 Variable variable = getMutableVariable(reference.definition); |
| 104 return new VariableUse(variable); | 102 return new VariableUse(variable); |
| 105 } | 103 } |
| 106 | 104 |
| 107 /// Obtains the variable representing the given primitive. Returns null for | 105 /// Obtains the variable representing the given primitive. Returns null for |
| 108 /// primitives that have no reference and do not need a variable. | 106 /// primitives that have no reference and do not need a variable. |
| 109 Variable getVariable(cps_ir.Primitive primitive) { | 107 Variable getVariable(cps_ir.Primitive primitive) { |
| 110 if (primitive.registerIndex == null) { | 108 return primitive2variable.putIfAbsent(primitive, |
| 111 return null; // variable is unused | 109 () => new Variable(currentElement, primitive.hint)); |
| 112 } | |
| 113 List<Variable> variables = local2variables.putIfAbsent(primitive.hint, | |
| 114 () => <Variable>[]); | |
| 115 while (variables.length <= primitive.registerIndex) { | |
| 116 variables.add(new Variable(currentElement, primitive.hint)); | |
| 117 } | |
| 118 return variables[primitive.registerIndex]; | |
| 119 } | 110 } |
| 120 | 111 |
| 121 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 112 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
| 122 /// referred to by [reference]. | 113 /// referred to by [reference]. |
| 123 /// This increments the reference count for the given variable, so the | 114 /// This increments the reference count for the given variable, so the |
| 124 /// returned expression must be used in the tree. | 115 /// returned expression must be used in the tree. |
| 125 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { | 116 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { |
| 126 if (thisParameter != null && reference.definition == thisParameter) { | 117 if (thisParameter != null && reference.definition == thisParameter) { |
| 127 return new This(); | 118 return new This(); |
| 128 } | 119 } |
| 129 Variable variable = getVariable(reference.definition); | 120 return new VariableUse(getVariable(reference.definition)); |
| 130 if (variable == null) { | |
| 131 // Note: this may fail because you forgot to implement a visit-function | |
| 132 // in the RegisterAllocator. | |
| 133 internalError( | |
| 134 CURRENT_ELEMENT_SPANNABLE, | |
| 135 "Reference to ${reference.definition} has no register"); | |
| 136 } | |
| 137 return new VariableUse(variable); | |
| 138 } | 121 } |
| 139 | 122 |
| 140 ExecutableDefinition build(cps_ir.ExecutableDefinition node) { | 123 ExecutableDefinition build(cps_ir.ExecutableDefinition node) { |
| 124 // TODO(asgerf): Don't have build AND buildXXX as public API. |
| 141 if (node is cps_ir.FieldDefinition) { | 125 if (node is cps_ir.FieldDefinition) { |
| 142 return buildField(node); | 126 return buildField(node); |
| 143 } else if (node is cps_ir.ConstructorDefinition) { | 127 } else if (node is cps_ir.ConstructorDefinition) { |
| 144 return buildConstructor(node); | 128 return buildConstructor(node); |
| 145 } else { | 129 } else { |
| 146 assert(dart2js.invariant( | 130 assert(dart2js.invariant( |
| 147 CURRENT_ELEMENT_SPANNABLE, | 131 CURRENT_ELEMENT_SPANNABLE, |
| 148 node is cps_ir.FunctionDefinition, | 132 node is cps_ir.FunctionDefinition, |
| 149 message: 'expected FunctionDefinition or FieldDefinition, ' | 133 message: 'expected FunctionDefinition or FieldDefinition, ' |
| 150 ' found $node')); | 134 ' found $node')); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 207 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
| 224 return new List<Expression>.generate(args.length, | 208 return new List<Expression>.generate(args.length, |
| 225 (int index) => getVariableUse(args[index]), | 209 (int index) => getVariableUse(args[index]), |
| 226 growable: false); | 210 growable: false); |
| 227 } | 211 } |
| 228 | 212 |
| 229 Statement buildContinuationAssignment( | 213 Statement buildContinuationAssignment( |
| 230 cps_ir.Parameter parameter, | 214 cps_ir.Parameter parameter, |
| 231 Expression argument, | 215 Expression argument, |
| 232 Statement buildRest()) { | 216 Statement buildRest()) { |
| 233 Variable variable = getVariable(parameter); | |
| 234 Statement assignment; | 217 Statement assignment; |
| 235 if (variable == null) { | 218 if (parameter.hasAtLeastOneUse) { |
| 219 Variable variable = getVariable(parameter); |
| 220 assignment = new Assign(variable, argument, null); |
| 221 } else { |
| 236 assignment = new ExpressionStatement(argument, null); | 222 assignment = new ExpressionStatement(argument, null); |
| 237 } else { | |
| 238 assignment = new Assign(variable, argument, null); | |
| 239 } | 223 } |
| 240 assignment.next = buildRest(); | 224 assignment.next = buildRest(); |
| 241 return assignment; | 225 return assignment; |
| 242 } | 226 } |
| 243 | 227 |
| 244 /// Simultaneously assigns each argument to the corresponding parameter, | 228 /// Simultaneously assigns each argument to the corresponding parameter, |
| 245 /// then continues at the statement created by [buildRest]. | 229 /// then continues at the statement created by [buildRest]. |
| 246 Statement buildPhiAssignments( | 230 Statement buildPhiAssignments( |
| 247 List<cps_ir.Parameter> parameters, | 231 List<cps_ir.Parameter> parameters, |
| 248 List<Expression> arguments, | 232 List<Expression> arguments, |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); | 639 return new ReadTypeVariable(node.variable, getVariableUse(node.target)); |
| 656 } | 640 } |
| 657 | 641 |
| 658 @override | 642 @override |
| 659 Node visitTypeExpression(cps_ir.TypeExpression node) { | 643 Node visitTypeExpression(cps_ir.TypeExpression node) { |
| 660 return new TypeExpression( | 644 return new TypeExpression( |
| 661 node.dartType, | 645 node.dartType, |
| 662 node.arguments.map(getVariableUse).toList()); | 646 node.arguments.map(getVariableUse).toList()); |
| 663 } | 647 } |
| 664 } | 648 } |
| 649 |
| OLD | NEW |