Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import 'ir_nodes.dart' as ir; | 7 import 'ir_nodes.dart' as ir; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../dart2jslib.dart'; | 9 import '../dart2jslib.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 // list of references. When the delimited subexpression is plugged into the | 184 // list of references. When the delimited subexpression is plugged into the |
| 185 // surrounding context, the free occurrences can be captured or become free | 185 // surrounding context, the free occurrences can be captured or become free |
| 186 // occurrences in the next outer delimited subexpression. | 186 // occurrences in the next outer delimited subexpression. |
| 187 // | 187 // |
| 188 // Each nested visitor maintains a list that maps indexes of variables | 188 // Each nested visitor maintains a list that maps indexes of variables |
| 189 // assigned in the delimited subexpression to their reaching definition --- | 189 // assigned in the delimited subexpression to their reaching definition --- |
| 190 // that is, the definition in effect at the hole in 'current'. These are | 190 // that is, the definition in effect at the hole in 'current'. These are |
| 191 // used to determine if a join-point continuation needs to be passed | 191 // used to determine if a join-point continuation needs to be passed |
| 192 // arguments, and what the arguments are. | 192 // arguments, and what the arguments are. |
| 193 final Map<Element, int> variableIndex; | 193 final Map<Element, int> variableIndex; |
| 194 final List<Element> index2variable; | |
| 194 final List<ir.Parameter> freeVars; | 195 final List<ir.Parameter> freeVars; |
| 195 final List<ir.Primitive> assignedVars; | 196 final List<ir.Primitive> assignedVars; |
| 196 | 197 |
| 197 /// Construct a top-level visitor. | 198 /// Construct a top-level visitor. |
| 198 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) | 199 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) |
| 199 : returnContinuation = new ir.Continuation.retrn(), | 200 : returnContinuation = new ir.Continuation.retrn(), |
| 200 parameters = <ir.Parameter>[], | 201 parameters = <ir.Parameter>[], |
| 201 variableIndex = <Element, int>{}, | 202 variableIndex = <Element, int>{}, |
| 202 freeVars = null, | 203 freeVars = null, |
| 203 assignedVars = <ir.Primitive>[], | 204 assignedVars = <ir.Primitive>[], |
| 205 index2variable = <Element>[], | |
| 204 super(elements, compiler); | 206 super(elements, compiler); |
| 205 | 207 |
| 206 /// Construct a delimited visitor. | 208 /// Construct a delimited visitor. |
| 207 IrBuilder.delimited(IrBuilder parent) | 209 IrBuilder.delimited(IrBuilder parent) |
| 208 : sourceFile = parent.sourceFile, | 210 : sourceFile = parent.sourceFile, |
| 209 returnContinuation = parent.returnContinuation, | 211 returnContinuation = parent.returnContinuation, |
| 210 parameters = parent.parameters, | 212 parameters = parent.parameters, |
| 211 variableIndex = parent.variableIndex, | 213 variableIndex = parent.variableIndex, |
| 212 freeVars = new List<ir.Parameter>.generate( | 214 freeVars = new List<ir.Parameter>.generate( |
| 213 parent.assignedVars.length, (_) => new ir.Parameter(null), | 215 parent.assignedVars.length, (_) => new ir.Parameter(null), |
| 214 growable: false), | 216 growable: false), |
| 215 assignedVars = new List<ir.Primitive>.generate( | 217 assignedVars = new List<ir.Primitive>.generate( |
| 216 parent.assignedVars.length, (_) => null), | 218 parent.assignedVars.length, (_) => null), |
| 219 index2variable = new List<Element>.from(parent.index2variable), | |
| 217 super(parent.elements, parent.compiler); | 220 super(parent.elements, parent.compiler); |
| 218 | 221 |
| 219 /** | 222 /** |
| 220 * Builds the [ir.FunctionDefinition] for a function element. In case the | 223 * Builds the [ir.FunctionDefinition] for a function element. In case the |
| 221 * function uses features that cannot be expressed in the IR, this function | 224 * function uses features that cannot be expressed in the IR, this function |
| 222 * returns `null`. | 225 * returns `null`. |
| 223 */ | 226 */ |
| 224 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 227 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
| 225 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 228 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
| 226 } | 229 } |
| 227 | 230 |
| 228 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 231 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { |
| 229 assert(invariant(element, element.isImplementation)); | 232 assert(invariant(element, element.isImplementation)); |
| 230 ast.FunctionExpression function = element.node; | 233 ast.FunctionExpression function = element.node; |
| 231 assert(function != null); | 234 assert(function != null); |
| 232 assert(!function.modifiers.isExternal); | 235 assert(!function.modifiers.isExternal); |
| 233 assert(elements[function] != null); | 236 assert(elements[function] != null); |
| 234 | 237 |
| 235 root = current = null; | 238 root = current = null; |
| 236 | 239 |
| 237 FunctionSignature signature = element.functionSignature; | 240 FunctionSignature signature = element.functionSignature; |
| 238 signature.orderedForEachParameter((parameterElement) { | 241 signature.orderedForEachParameter((parameterElement) { |
| 239 ir.Parameter parameter = new ir.Parameter(parameterElement); | 242 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 240 parameters.add(parameter); | 243 parameters.add(parameter); |
| 241 variableIndex[parameterElement] = assignedVars.length; | 244 variableIndex[parameterElement] = assignedVars.length; |
| 242 assignedVars.add(parameter); | 245 assignedVars.add(parameter); |
| 246 index2variable.add(parameterElement); | |
| 243 }); | 247 }); |
| 244 | 248 |
| 245 visit(function.body); | 249 visit(function.body); |
| 246 ensureReturn(function); | 250 ensureReturn(function); |
| 247 return new ir.FunctionDefinition(returnContinuation, parameters, root); | 251 return new ir.FunctionDefinition(returnContinuation, parameters, root); |
| 248 } | 252 } |
| 249 | 253 |
| 250 ConstantSystem get constantSystem => compiler.backend.constantSystem; | 254 ConstantSystem get constantSystem => compiler.backend.constantSystem; |
| 251 | 255 |
| 252 bool get isOpen => root == null || current != null; | 256 bool get isOpen => root == null || current != null; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 // The last assignments, if any, reaching the end of the two subterms. | 342 // The last assignments, if any, reaching the end of the two subterms. |
| 339 ir.Primitive leftAssignment = leftBuilder.assignedVars[i]; | 343 ir.Primitive leftAssignment = leftBuilder.assignedVars[i]; |
| 340 ir.Primitive rightAssignment = rightBuilder.assignedVars[i]; | 344 ir.Primitive rightAssignment = rightBuilder.assignedVars[i]; |
| 341 | 345 |
| 342 if (leftAssignment != null || rightAssignment != null) { | 346 if (leftAssignment != null || rightAssignment != null) { |
| 343 // The corresponsing argument is the reaching definition if any, or a | 347 // The corresponsing argument is the reaching definition if any, or a |
| 344 // free occurrence. In the case that control does not reach both the | 348 // free occurrence. In the case that control does not reach both the |
| 345 // left and right subterms we will still have a join continuation with | 349 // left and right subterms we will still have a join continuation with |
| 346 // possibly arguments passed to it. Such singly-used continuations | 350 // possibly arguments passed to it. Such singly-used continuations |
| 347 // are eliminated by the shrinking conversions. | 351 // are eliminated by the shrinking conversions. |
| 348 parameters.add(new ir.Parameter(null)); | 352 parameters.add(new ir.Parameter(index2variable[i])); |
| 349 ir.Primitive reachingDefinition = | 353 ir.Primitive reachingDefinition = |
| 350 assignedVars[i] == null ? freeVars[i] : assignedVars[i]; | 354 assignedVars[i] == null ? freeVars[i] : assignedVars[i]; |
| 351 leftArguments.add( | 355 leftArguments.add( |
| 352 leftAssignment == null ? reachingDefinition : leftAssignment); | 356 leftAssignment == null ? reachingDefinition : leftAssignment); |
| 353 rightArguments.add( | 357 rightArguments.add( |
| 354 rightAssignment == null ? reachingDefinition : rightAssignment); | 358 rightAssignment == null ? reachingDefinition : rightAssignment); |
| 355 } | 359 } |
| 356 } | 360 } |
| 357 return parameters; | 361 return parameters; |
| 358 } | 362 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 388 for (int i = 0; i < assignedVars.length; ++i) { | 392 for (int i = 0; i < assignedVars.length; ++i) { |
| 389 // Was there an assignment in the body? | 393 // Was there an assignment in the body? |
| 390 ir.Definition reachingAssignment = bodyBuilder.assignedVars[i]; | 394 ir.Definition reachingAssignment = bodyBuilder.assignedVars[i]; |
| 391 // If not, was there an assignment in the condition? | 395 // If not, was there an assignment in the condition? |
| 392 if (reachingAssignment == null) { | 396 if (reachingAssignment == null) { |
| 393 reachingAssignment = condBuilder.assignedVars[i]; | 397 reachingAssignment = condBuilder.assignedVars[i]; |
| 394 } | 398 } |
| 395 // If not, no value needs to be passed to the join point. | 399 // If not, no value needs to be passed to the join point. |
| 396 if (reachingAssignment == null) continue; | 400 if (reachingAssignment == null) continue; |
| 397 | 401 |
| 398 parameters.add(new ir.Parameter(null)); | 402 parameters.add(new ir.Parameter(index2variable[i])); |
| 399 ir.Definition entryAssignment = assignedVars[i]; | 403 ir.Definition entryAssignment = assignedVars[i]; |
| 400 entryArguments.add( | 404 entryArguments.add( |
| 401 entryAssignment == null ? freeVars[i] : entryAssignment); | 405 entryAssignment == null ? freeVars[i] : entryAssignment); |
| 402 loopArguments.add(reachingAssignment); | 406 loopArguments.add(reachingAssignment); |
| 403 } | 407 } |
| 404 return parameters; | 408 return parameters; |
| 405 } | 409 } |
| 406 | 410 |
| 407 /// Capture free variables in the arms of a branch. | 411 /// Capture free variables in the arms of a branch. |
| 408 /// | 412 /// |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 621 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 625 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 622 assert(isOpen); | 626 assert(isOpen); |
| 623 for (ast.Node definition in node.definitions.nodes) { | 627 for (ast.Node definition in node.definitions.nodes) { |
| 624 Element element = elements[definition]; | 628 Element element = elements[definition]; |
| 625 // Definitions are either SendSets if there is an initializer, or | 629 // Definitions are either SendSets if there is an initializer, or |
| 626 // Identifiers if there is no initializer. | 630 // Identifiers if there is no initializer. |
| 627 if (definition is ast.SendSet) { | 631 if (definition is ast.SendSet) { |
| 628 assert(!definition.arguments.isEmpty); | 632 assert(!definition.arguments.isEmpty); |
| 629 assert(definition.arguments.tail.isEmpty); | 633 assert(definition.arguments.tail.isEmpty); |
| 630 ir.Primitive initialValue = visit(definition.arguments.head); | 634 ir.Primitive initialValue = visit(definition.arguments.head); |
| 635 // If a temporary was introduced for the initializer expression, | |
|
Kevin Millikin (Google)
2014/06/10 11:33:01
Hmm, the comment says "If" but the code is uncondi
asgerf
2014/06/10 12:22:24
The 'if' I mention is inside the method (if elemen
| |
| 636 // do not use a separate variable for it. | |
| 637 useElementForVariable(initialValue, element); | |
| 631 variableIndex[element] = assignedVars.length; | 638 variableIndex[element] = assignedVars.length; |
| 632 assignedVars.add(initialValue); | 639 assignedVars.add(initialValue); |
| 640 index2variable.add(element); | |
| 633 } else { | 641 } else { |
| 634 assert(definition is ast.Identifier); | 642 assert(definition is ast.Identifier); |
| 635 // The initial value is null. | 643 // The initial value is null. |
| 636 // TODO(kmillikin): Consider pooling constants. | 644 // TODO(kmillikin): Consider pooling constants. |
| 637 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 645 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 646 useElementForVariable(constant, element); | |
| 638 add(new ir.LetPrim(constant)); | 647 add(new ir.LetPrim(constant)); |
| 639 variableIndex[element] = assignedVars.length; | 648 variableIndex[element] = assignedVars.length; |
| 640 assignedVars.add(constant); | 649 assignedVars.add(constant); |
| 650 index2variable.add(element); | |
| 641 } | 651 } |
| 642 } | 652 } |
| 643 return null; | 653 return null; |
| 644 } | 654 } |
| 645 | 655 |
| 646 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 656 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 647 // where (C', x) = Build(e, C) | 657 // where (C', x) = Build(e, C) |
| 648 // | 658 // |
| 649 // Return without a subexpression is translated as if it were return null. | 659 // Return without a subexpression is translated as if it were return null. |
| 650 ir.Primitive visitReturn(ast.Return node) { | 660 ir.Primitive visitReturn(ast.Return node) { |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1081 | 1091 |
| 1082 ir.Primitive visitSendSet(ast.SendSet node) { | 1092 ir.Primitive visitSendSet(ast.SendSet node) { |
| 1083 assert(isOpen); | 1093 assert(isOpen); |
| 1084 Element element = elements[node]; | 1094 Element element = elements[node]; |
| 1085 if (node.assignmentOperator.source != '=') return giveup(); | 1095 if (node.assignmentOperator.source != '=') return giveup(); |
| 1086 if (Elements.isLocal(element)) { | 1096 if (Elements.isLocal(element)) { |
| 1087 // Exactly one argument expected for a simple assignment. | 1097 // Exactly one argument expected for a simple assignment. |
| 1088 assert(!node.arguments.isEmpty); | 1098 assert(!node.arguments.isEmpty); |
| 1089 assert(node.arguments.tail.isEmpty); | 1099 assert(node.arguments.tail.isEmpty); |
| 1090 ir.Primitive result = visit(node.arguments.head); | 1100 ir.Primitive result = visit(node.arguments.head); |
| 1101 useElementForVariable(result, element); | |
| 1091 assignedVars[variableIndex[element]] = result; | 1102 assignedVars[variableIndex[element]] = result; |
| 1092 return result; | 1103 return result; |
| 1093 } else if (Elements.isStaticOrTopLevel(element)) { | 1104 } else if (Elements.isStaticOrTopLevel(element)) { |
| 1094 // TODO(asgerf): static and top-level | 1105 // TODO(asgerf): static and top-level |
| 1095 return giveup(); | 1106 return giveup(); |
| 1096 } else if (node.receiver == null) { | 1107 } else if (node.receiver == null) { |
| 1097 // Nodes that fall in this case: | 1108 // Nodes that fall in this case: |
| 1098 // - Unresolved top-level | 1109 // - Unresolved top-level |
| 1099 // - Assignment to final variable (will not be resolved) | 1110 // - Assignment to final variable (will not be resolved) |
| 1100 return giveup(); | 1111 return giveup(); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1170 arguments.add(visit(part.expression)); | 1181 arguments.add(visit(part.expression)); |
| 1171 arguments.add(visitLiteralString(part.string)); | 1182 arguments.add(visitLiteralString(part.string)); |
| 1172 } | 1183 } |
| 1173 ir.Parameter v = new ir.Parameter(null); | 1184 ir.Parameter v = new ir.Parameter(null); |
| 1174 ir.Continuation k = new ir.Continuation([v]); | 1185 ir.Continuation k = new ir.Continuation([v]); |
| 1175 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); | 1186 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); |
| 1176 add(new ir.LetCont(k, concat)); | 1187 add(new ir.LetCont(k, concat)); |
| 1177 return v; | 1188 return v; |
| 1178 } | 1189 } |
| 1179 | 1190 |
| 1191 /// Associates [primitive] with the given [element]. | |
| 1192 /// This is used as a hint when choosing variables names later when | |
| 1193 /// translating out of the IR again. | |
| 1194 void useElementForVariable(ir.Primitive primitive, Element element) { | |
|
Kevin Millikin (Google)
2014/06/10 11:33:01
This works better as a method on Primitive, doesn'
asgerf
2014/06/10 12:22:24
Yes, good idea.
| |
| 1195 // Use the first assigned element | |
| 1196 if (primitive.element != null) return; | |
| 1197 | |
| 1198 primitive.element = element; | |
| 1199 } | |
| 1200 | |
| 1180 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1201 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1181 | 1202 |
| 1182 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; | 1203 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER; |
| 1183 | 1204 |
| 1184 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 1205 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
| 1185 try { | 1206 try { |
| 1186 return action(); | 1207 return action(); |
| 1187 } catch(e) { | 1208 } catch(e) { |
| 1188 if (e == ABORT_IRNODE_BUILDER) return null; | 1209 if (e == ABORT_IRNODE_BUILDER) return null; |
| 1189 rethrow; | 1210 rethrow; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1228 bool visitType(DartType type, Null _) => false; | 1249 bool visitType(DartType type, Null _) => false; |
| 1229 | 1250 |
| 1230 bool visitDynamicType(DynamicType type, Null _) => true; | 1251 bool visitDynamicType(DynamicType type, Null _) => true; |
| 1231 | 1252 |
| 1232 bool visitVoidType(VoidType type, Null _) => true; | 1253 bool visitVoidType(VoidType type, Null _) => true; |
| 1233 | 1254 |
| 1234 // Currently, InterfaceType and TypedefType are supported so long as they | 1255 // Currently, InterfaceType and TypedefType are supported so long as they |
| 1235 // do not have type parameters. They are subclasses of GenericType. | 1256 // do not have type parameters. They are subclasses of GenericType. |
| 1236 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; | 1257 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; |
| 1237 } | 1258 } |
| OLD | NEW |