| 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 |