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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 <Element,List<Variable>>{}; | 50 <Element,List<Variable>>{}; |
51 | 51 |
52 /// Like [element2variables], except for closure variables. Closure variables | 52 /// Like [element2variables], except for closure variables. Closure variables |
53 /// are not subject to SSA, so at most one variable is used per local. | 53 /// are not subject to SSA, so at most one variable is used per local. |
54 final Map<Local, Variable> local2closure = <Local, Variable>{}; | 54 final Map<Local, Variable> local2closure = <Local, Variable>{}; |
55 | 55 |
56 // Continuations with more than one use are replaced with Tree labels. This | 56 // Continuations with more than one use are replaced with Tree labels. This |
57 // is the mapping from continuations to labels. | 57 // is the mapping from continuations to labels. |
58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
59 | 59 |
60 FunctionDefinition function; | 60 ExecutableElement currentElement; |
61 cps_ir.Continuation returnContinuation; | 61 cps_ir.Continuation returnContinuation; |
62 | 62 |
63 Builder parent; | 63 Builder parent; |
64 | 64 |
65 Builder(this.compiler); | 65 Builder(this.compiler); |
66 | 66 |
67 Builder.inner(Builder parent) | 67 Builder.inner(Builder parent) |
68 : this.parent = parent, | 68 : this.parent = parent, |
69 compiler = parent.compiler; | 69 compiler = parent.compiler; |
70 | 70 |
71 /// Variable used in [buildPhiAssignments] as a temporary when swapping | 71 /// Variable used in [buildPhiAssignments] as a temporary when swapping |
72 /// variables. | 72 /// variables. |
73 Variable phiTempVar; | 73 Variable phiTempVar; |
74 | 74 |
75 Variable getClosureVariable(Local local) { | 75 Variable getClosureVariable(Local local) { |
76 if (local.executableContext != function.element) { | 76 if (local.executableContext != currentElement) { |
77 return parent.getClosureVariable(local); | 77 return parent.getClosureVariable(local); |
78 } | 78 } |
79 Variable variable = local2closure[local]; | 79 Variable variable = local2closure[local]; |
80 if (variable == null) { | 80 if (variable == null) { |
81 variable = new Variable(function, local); | 81 variable = new Variable(currentElement, local); |
82 local2closure[local] = variable; | 82 local2closure[local] = variable; |
83 } | 83 } |
84 return variable; | 84 return variable; |
85 } | 85 } |
86 | 86 |
87 /// Obtains the variable representing the given primitive. Returns null for | 87 /// Obtains the variable representing the given primitive. Returns null for |
88 /// primitives that have no reference and do not need a variable. | 88 /// primitives that have no reference and do not need a variable. |
89 Variable getVariable(cps_ir.Primitive primitive) { | 89 Variable getVariable(cps_ir.Primitive primitive) { |
90 if (primitive.registerIndex == null) { | 90 if (primitive.registerIndex == null) { |
91 return null; // variable is unused | 91 return null; // variable is unused |
92 } | 92 } |
93 List<Variable> variables = element2variables[primitive.hint]; | 93 List<Variable> variables = element2variables[primitive.hint]; |
94 if (variables == null) { | 94 if (variables == null) { |
95 variables = <Variable>[]; | 95 variables = <Variable>[]; |
96 element2variables[primitive.hint] = variables; | 96 element2variables[primitive.hint] = variables; |
97 } | 97 } |
98 while (variables.length <= primitive.registerIndex) { | 98 while (variables.length <= primitive.registerIndex) { |
99 variables.add(new Variable(function, primitive.hint)); | 99 variables.add(new Variable(currentElement, primitive.hint)); |
100 } | 100 } |
101 return variables[primitive.registerIndex]; | 101 return variables[primitive.registerIndex]; |
102 } | 102 } |
103 | 103 |
104 /// Obtains a reference to the tree Variable corresponding to the IR primitive | 104 /// Obtains a reference to the tree Variable corresponding to the IR primitive |
105 /// referred to by [reference]. | 105 /// referred to by [reference]. |
106 /// This increments the reference count for the given variable, so the | 106 /// This increments the reference count for the given variable, so the |
107 /// returned expression must be used in the tree. | 107 /// returned expression must be used in the tree. |
108 Expression getVariableReference(cps_ir.Reference reference) { | 108 Expression getVariableReference(cps_ir.Reference reference) { |
109 Variable variable = getVariable(reference.definition); | 109 Variable variable = getVariable(reference.definition); |
110 if (variable == null) { | 110 if (variable == null) { |
111 compiler.internalError( | 111 compiler.internalError( |
112 compiler.currentElement, | 112 compiler.currentElement, |
113 "Reference to ${reference.definition} has no register"); | 113 "Reference to ${reference.definition} has no register"); |
114 } | 114 } |
115 ++variable.readCount; | 115 ++variable.readCount; |
116 return variable; | 116 return variable; |
117 } | 117 } |
118 | 118 |
119 FunctionDefinition build(cps_ir.FunctionDefinition node) { | 119 ExecutableDefinition build(cps_ir.ExecutableDefinition node) { |
120 visit(node); | 120 if (node is cps_ir.FieldDefinition) { |
121 return function; | 121 return buildField(node); |
| 122 } else if (node is cps_ir.FunctionDefinition) { |
| 123 return buildFunction(node); |
| 124 } |
| 125 assert(false); |
| 126 } |
| 127 |
| 128 FieldDefinition buildField(cps_ir.FieldDefinition node) { |
| 129 currentElement = node.element; |
| 130 returnContinuation = node.returnContinuation; |
| 131 |
| 132 phiTempVar = new Variable(node.element, null); |
| 133 |
| 134 return new FieldDefinition(node.element, visit(node.body)); |
| 135 } |
| 136 |
| 137 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
| 138 currentElement = node.element; |
| 139 List<Variable> parameters = <Variable>[]; |
| 140 for (cps_ir.Parameter p in node.parameters) { |
| 141 Variable parameter = getVariable(p); |
| 142 assert(parameter != null); |
| 143 ++parameter.writeCount; // Being a parameter counts as a write. |
| 144 parameters.add(parameter); |
| 145 } |
| 146 returnContinuation = node.returnContinuation; |
| 147 |
| 148 Statement body; |
| 149 if (!node.isAbstract) { |
| 150 phiTempVar = new Variable(node.element, null); |
| 151 body = visit(node.body); |
| 152 } |
| 153 |
| 154 return new FunctionDefinition(node.element, parameters, |
| 155 body, node.localConstants, node.defaultParameterValues); |
122 } | 156 } |
123 | 157 |
124 List<Expression> translateArguments(List<cps_ir.Reference> args) { | 158 List<Expression> translateArguments(List<cps_ir.Reference> args) { |
125 return new List<Expression>.generate(args.length, | 159 return new List<Expression>.generate(args.length, |
126 (int index) => getVariableReference(args[index])); | 160 (int index) => getVariableReference(args[index])); |
127 } | 161 } |
128 | 162 |
129 List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { | 163 List<Variable> translatePhiArguments(List<cps_ir.Reference> args) { |
130 return new List<Variable>.generate(args.length, | 164 return new List<Variable>.generate(args.length, |
131 (int index) => getVariableReference(args[index])); | 165 (int index) => getVariableReference(args[index])); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 if (first == null) { | 259 if (first == null) { |
226 first = buildRest(); | 260 first = buildRest(); |
227 } else { | 261 } else { |
228 current.next = buildRest(); | 262 current.next = buildRest(); |
229 } | 263 } |
230 return first; | 264 return first; |
231 } | 265 } |
232 | 266 |
233 visitNode(cps_ir.Node node) => throw "Unhandled node: $node"; | 267 visitNode(cps_ir.Node node) => throw "Unhandled node: $node"; |
234 | 268 |
235 Expression visitFunctionDefinition(cps_ir.FunctionDefinition node) { | |
236 List<Variable> parameters = <Variable>[]; | |
237 function = new FunctionDefinition(node.element, parameters, | |
238 null, node.localConstants, node.defaultParameterValues); | |
239 returnContinuation = node.returnContinuation; | |
240 for (cps_ir.Parameter p in node.parameters) { | |
241 Variable parameter = getVariable(p); | |
242 assert(parameter != null); | |
243 ++parameter.writeCount; // Being a parameter counts as a write. | |
244 parameters.add(parameter); | |
245 } | |
246 if (!node.isAbstract) { | |
247 phiTempVar = new Variable(function, null); | |
248 function.body = visit(node.body); | |
249 } | |
250 return null; | |
251 } | |
252 | |
253 Statement visitLetPrim(cps_ir.LetPrim node) { | 269 Statement visitLetPrim(cps_ir.LetPrim node) { |
254 Variable variable = getVariable(node.primitive); | 270 Variable variable = getVariable(node.primitive); |
255 | 271 |
256 // Don't translate unused primitives. | 272 // Don't translate unused primitives. |
257 if (variable == null) return visit(node.body); | 273 if (variable == null) return visit(node.body); |
258 | 274 |
259 Node definition = visit(node.primitive); | 275 Node definition = visit(node.primitive); |
260 | 276 |
261 // visitPrimitive returns a Statement without successor if it cannot occur | 277 // visitPrimitive returns a Statement without successor if it cannot occur |
262 // in expression context (currently only the case for FunctionDeclarations). | 278 // in expression context (currently only the case for FunctionDeclarations). |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 node.type, | 449 node.type, |
434 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { | 450 new List<LiteralMapEntry>.generate(node.entries.length, (int index) { |
435 return new LiteralMapEntry( | 451 return new LiteralMapEntry( |
436 getVariableReference(node.entries[index].key), | 452 getVariableReference(node.entries[index].key), |
437 getVariableReference(node.entries[index].value)); | 453 getVariableReference(node.entries[index].value)); |
438 }) | 454 }) |
439 ); | 455 ); |
440 } | 456 } |
441 | 457 |
442 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { | 458 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { |
443 return new Builder.inner(this).build(function); | 459 return new Builder.inner(this).buildFunction(function); |
444 } | 460 } |
445 | 461 |
446 Node visitCreateFunction(cps_ir.CreateFunction node) { | 462 Node visitCreateFunction(cps_ir.CreateFunction node) { |
447 FunctionDefinition def = makeSubFunction(node.definition); | 463 FunctionDefinition def = makeSubFunction(node.definition); |
448 FunctionType type = node.definition.element.type; | 464 FunctionType type = node.definition.element.type; |
449 bool hasReturnType = !type.returnType.treatAsDynamic; | 465 bool hasReturnType = !type.returnType.treatAsDynamic; |
450 if (hasReturnType) { | 466 if (hasReturnType) { |
451 // This function cannot occur in expression context. | 467 // This function cannot occur in expression context. |
452 // The successor will be filled in by visitLetPrim. | 468 // The successor will be filled in by visitLetPrim. |
453 return new FunctionDeclaration(getVariable(node), def, null); | 469 return new FunctionDeclaration(getVariable(node), def, null); |
(...skipping 26 matching lines...) Expand all Loading... |
480 | 496 |
481 Expression visitIdentical(cps_ir.Identical node) { | 497 Expression visitIdentical(cps_ir.Identical node) { |
482 return new InvokeStatic( | 498 return new InvokeStatic( |
483 compiler.identicalFunction, | 499 compiler.identicalFunction, |
484 identicalSelector, | 500 identicalSelector, |
485 <Expression>[getVariableReference(node.left), | 501 <Expression>[getVariableReference(node.left), |
486 getVariableReference(node.right)]); | 502 getVariableReference(node.right)]); |
487 } | 503 } |
488 } | 504 } |
489 | 505 |
OLD | NEW |