| 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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 // list of references. When the delimited subexpression is plugged into the | 185 // list of references. When the delimited subexpression is plugged into the |
| 186 // surrounding context, the free occurrences can be captured or become free | 186 // surrounding context, the free occurrences can be captured or become free |
| 187 // occurrences in the next outer delimited subexpression. | 187 // occurrences in the next outer delimited subexpression. |
| 188 // | 188 // |
| 189 // Each nested visitor maintains a list that maps indexes of variables | 189 // Each nested visitor maintains a list that maps indexes of variables |
| 190 // assigned in the delimited subexpression to their reaching definition --- | 190 // assigned in the delimited subexpression to their reaching definition --- |
| 191 // that is, the definition in effect at the hole in 'current'. These are | 191 // that is, the definition in effect at the hole in 'current'. These are |
| 192 // used to determine if a join-point continuation needs to be passed | 192 // used to determine if a join-point continuation needs to be passed |
| 193 // arguments, and what the arguments are. | 193 // arguments, and what the arguments are. |
| 194 final Map<Element, int> variableIndex; | 194 final Map<Element, int> variableIndex; |
| 195 final List<Element> index2variable; |
| 195 final List<ir.Parameter> freeVars; | 196 final List<ir.Parameter> freeVars; |
| 196 final List<ir.Primitive> assignedVars; | 197 final List<ir.Primitive> assignedVars; |
| 197 | 198 |
| 198 /// Construct a top-level visitor. | 199 /// Construct a top-level visitor. |
| 199 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) | 200 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) |
| 200 : returnContinuation = new ir.Continuation.retrn(), | 201 : returnContinuation = new ir.Continuation.retrn(), |
| 201 parameters = <ir.Parameter>[], | 202 parameters = <ir.Parameter>[], |
| 202 variableIndex = <Element, int>{}, | 203 variableIndex = <Element, int>{}, |
| 203 freeVars = null, | 204 freeVars = null, |
| 204 assignedVars = <ir.Primitive>[], | 205 assignedVars = <ir.Primitive>[], |
| 206 index2variable = <Element>[], |
| 205 super(elements, compiler); | 207 super(elements, compiler); |
| 206 | 208 |
| 207 /// Construct a delimited visitor. | 209 /// Construct a delimited visitor. |
| 208 IrBuilder.delimited(IrBuilder parent) | 210 IrBuilder.delimited(IrBuilder parent) |
| 209 : sourceFile = parent.sourceFile, | 211 : sourceFile = parent.sourceFile, |
| 210 returnContinuation = parent.returnContinuation, | 212 returnContinuation = parent.returnContinuation, |
| 211 parameters = parent.parameters, | 213 parameters = parent.parameters, |
| 212 variableIndex = parent.variableIndex, | 214 variableIndex = parent.variableIndex, |
| 213 freeVars = new List<ir.Parameter>.generate( | 215 freeVars = new List<ir.Parameter>.generate( |
| 214 parent.assignedVars.length, (_) => new ir.Parameter(null), | 216 parent.assignedVars.length, (_) => new ir.Parameter(null), |
| 215 growable: false), | 217 growable: false), |
| 216 assignedVars = new List<ir.Primitive>.generate( | 218 assignedVars = new List<ir.Primitive>.generate( |
| 217 parent.assignedVars.length, (_) => null), | 219 parent.assignedVars.length, (_) => null), |
| 220 index2variable = new List<Element>.from(parent.index2variable), |
| 218 super(parent.elements, parent.compiler); | 221 super(parent.elements, parent.compiler); |
| 219 | 222 |
| 220 /** | 223 /** |
| 221 * Builds the [ir.FunctionDefinition] for a function element. In case the | 224 * Builds the [ir.FunctionDefinition] for a function element. In case the |
| 222 * function uses features that cannot be expressed in the IR, this function | 225 * function uses features that cannot be expressed in the IR, this function |
| 223 * returns `null`. | 226 * returns `null`. |
| 224 */ | 227 */ |
| 225 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 228 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
| 226 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 229 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
| 227 } | 230 } |
| 228 | 231 |
| 229 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 232 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { |
| 230 assert(invariant(element, element.isImplementation)); | 233 assert(invariant(element, element.isImplementation)); |
| 231 ast.FunctionExpression function = element.node; | 234 ast.FunctionExpression function = element.node; |
| 232 assert(function != null); | 235 assert(function != null); |
| 233 assert(!function.modifiers.isExternal); | 236 assert(!function.modifiers.isExternal); |
| 234 assert(elements[function] != null); | 237 assert(elements[function] != null); |
| 235 | 238 |
| 236 root = current = null; | 239 root = current = null; |
| 237 | 240 |
| 238 FunctionSignature signature = element.functionSignature; | 241 FunctionSignature signature = element.functionSignature; |
| 239 signature.orderedForEachParameter((parameterElement) { | 242 signature.orderedForEachParameter((parameterElement) { |
| 240 ir.Parameter parameter = new ir.Parameter(parameterElement); | 243 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 241 parameters.add(parameter); | 244 parameters.add(parameter); |
| 242 variableIndex[parameterElement] = assignedVars.length; | 245 variableIndex[parameterElement] = assignedVars.length; |
| 243 assignedVars.add(parameter); | 246 assignedVars.add(parameter); |
| 247 index2variable.add(parameterElement); |
| 244 }); | 248 }); |
| 245 | 249 |
| 246 visit(function.body); | 250 visit(function.body); |
| 247 ensureReturn(function); | 251 ensureReturn(function); |
| 248 return new ir.FunctionDefinition(returnContinuation, parameters, root); | 252 return new ir.FunctionDefinition(returnContinuation, parameters, root); |
| 249 } | 253 } |
| 250 | 254 |
| 251 ConstantSystem get constantSystem => compiler.backend.constantSystem; | 255 ConstantSystem get constantSystem => compiler.backend.constantSystem; |
| 252 | 256 |
| 253 bool get isOpen => root == null || current != null; | 257 bool get isOpen => root == null || current != null; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 // The last assignments, if any, reaching the end of the two subterms. | 343 // The last assignments, if any, reaching the end of the two subterms. |
| 340 ir.Primitive leftAssignment = leftBuilder.assignedVars[i]; | 344 ir.Primitive leftAssignment = leftBuilder.assignedVars[i]; |
| 341 ir.Primitive rightAssignment = rightBuilder.assignedVars[i]; | 345 ir.Primitive rightAssignment = rightBuilder.assignedVars[i]; |
| 342 | 346 |
| 343 if (leftAssignment != null || rightAssignment != null) { | 347 if (leftAssignment != null || rightAssignment != null) { |
| 344 // The corresponsing argument is the reaching definition if any, or a | 348 // The corresponsing argument is the reaching definition if any, or a |
| 345 // free occurrence. In the case that control does not reach both the | 349 // free occurrence. In the case that control does not reach both the |
| 346 // left and right subterms we will still have a join continuation with | 350 // left and right subterms we will still have a join continuation with |
| 347 // possibly arguments passed to it. Such singly-used continuations | 351 // possibly arguments passed to it. Such singly-used continuations |
| 348 // are eliminated by the shrinking conversions. | 352 // are eliminated by the shrinking conversions. |
| 349 parameters.add(new ir.Parameter(null)); | 353 parameters.add(new ir.Parameter(index2variable[i])); |
| 350 ir.Primitive reachingDefinition = | 354 ir.Primitive reachingDefinition = |
| 351 assignedVars[i] == null ? freeVars[i] : assignedVars[i]; | 355 assignedVars[i] == null ? freeVars[i] : assignedVars[i]; |
| 352 leftArguments.add( | 356 leftArguments.add( |
| 353 leftAssignment == null ? reachingDefinition : leftAssignment); | 357 leftAssignment == null ? reachingDefinition : leftAssignment); |
| 354 rightArguments.add( | 358 rightArguments.add( |
| 355 rightAssignment == null ? reachingDefinition : rightAssignment); | 359 rightAssignment == null ? reachingDefinition : rightAssignment); |
| 356 } | 360 } |
| 357 } | 361 } |
| 358 return parameters; | 362 return parameters; |
| 359 } | 363 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 389 for (int i = 0; i < assignedVars.length; ++i) { | 393 for (int i = 0; i < assignedVars.length; ++i) { |
| 390 // Was there an assignment in the body? | 394 // Was there an assignment in the body? |
| 391 ir.Definition reachingAssignment = bodyBuilder.assignedVars[i]; | 395 ir.Definition reachingAssignment = bodyBuilder.assignedVars[i]; |
| 392 // If not, was there an assignment in the condition? | 396 // If not, was there an assignment in the condition? |
| 393 if (reachingAssignment == null) { | 397 if (reachingAssignment == null) { |
| 394 reachingAssignment = condBuilder.assignedVars[i]; | 398 reachingAssignment = condBuilder.assignedVars[i]; |
| 395 } | 399 } |
| 396 // If not, no value needs to be passed to the join point. | 400 // If not, no value needs to be passed to the join point. |
| 397 if (reachingAssignment == null) continue; | 401 if (reachingAssignment == null) continue; |
| 398 | 402 |
| 399 parameters.add(new ir.Parameter(null)); | 403 parameters.add(new ir.Parameter(index2variable[i])); |
| 400 ir.Definition entryAssignment = assignedVars[i]; | 404 ir.Definition entryAssignment = assignedVars[i]; |
| 401 entryArguments.add( | 405 entryArguments.add( |
| 402 entryAssignment == null ? freeVars[i] : entryAssignment); | 406 entryAssignment == null ? freeVars[i] : entryAssignment); |
| 403 loopArguments.add(reachingAssignment); | 407 loopArguments.add(reachingAssignment); |
| 404 } | 408 } |
| 405 return parameters; | 409 return parameters; |
| 406 } | 410 } |
| 407 | 411 |
| 408 /// Capture free variables in the arms of a branch. | 412 /// Capture free variables in the arms of a branch. |
| 409 /// | 413 /// |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 626 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 623 assert(isOpen); | 627 assert(isOpen); |
| 624 for (ast.Node definition in node.definitions.nodes) { | 628 for (ast.Node definition in node.definitions.nodes) { |
| 625 Element element = elements[definition]; | 629 Element element = elements[definition]; |
| 626 // Definitions are either SendSets if there is an initializer, or | 630 // Definitions are either SendSets if there is an initializer, or |
| 627 // Identifiers if there is no initializer. | 631 // Identifiers if there is no initializer. |
| 628 if (definition is ast.SendSet) { | 632 if (definition is ast.SendSet) { |
| 629 assert(!definition.arguments.isEmpty); | 633 assert(!definition.arguments.isEmpty); |
| 630 assert(definition.arguments.tail.isEmpty); | 634 assert(definition.arguments.tail.isEmpty); |
| 631 ir.Primitive initialValue = visit(definition.arguments.head); | 635 ir.Primitive initialValue = visit(definition.arguments.head); |
| 636 // In case a primitive was introduced for the initializer expression, |
| 637 // use this variable element to help derive a good name for it. |
| 638 initialValue.useElementAsHint(element); |
| 632 variableIndex[element] = assignedVars.length; | 639 variableIndex[element] = assignedVars.length; |
| 633 assignedVars.add(initialValue); | 640 assignedVars.add(initialValue); |
| 641 index2variable.add(element); |
| 634 } else { | 642 } else { |
| 635 assert(definition is ast.Identifier); | 643 assert(definition is ast.Identifier); |
| 636 // The initial value is null. | 644 // The initial value is null. |
| 637 // TODO(kmillikin): Consider pooling constants. | 645 // TODO(kmillikin): Consider pooling constants. |
| 638 ir.Constant constant = new ir.Constant(constantSystem.createNull()); | 646 ir.Constant constant = new ir.Constant(constantSystem.createNull()); |
| 647 constant.useElementAsHint(element); |
| 639 add(new ir.LetPrim(constant)); | 648 add(new ir.LetPrim(constant)); |
| 640 variableIndex[element] = assignedVars.length; | 649 variableIndex[element] = assignedVars.length; |
| 641 assignedVars.add(constant); | 650 assignedVars.add(constant); |
| 651 index2variable.add(element); |
| 642 } | 652 } |
| 643 } | 653 } |
| 644 return null; | 654 return null; |
| 645 } | 655 } |
| 646 | 656 |
| 647 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 657 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 648 // where (C', x) = Build(e, C) | 658 // where (C', x) = Build(e, C) |
| 649 // | 659 // |
| 650 // Return without a subexpression is translated as if it were return null. | 660 // Return without a subexpression is translated as if it were return null. |
| 651 ir.Primitive visitReturn(ast.Return node) { | 661 ir.Primitive visitReturn(ast.Return node) { |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1087 Element element = elements[node]; | 1097 Element element = elements[node]; |
| 1088 ast.Operator op = node.assignmentOperator; | 1098 ast.Operator op = node.assignmentOperator; |
| 1089 ir.Primitive result; | 1099 ir.Primitive result; |
| 1090 ir.Primitive getter; | 1100 ir.Primitive getter; |
| 1091 if (op.source == '=') { | 1101 if (op.source == '=') { |
| 1092 if (Elements.isLocal(element)) { | 1102 if (Elements.isLocal(element)) { |
| 1093 // Exactly one argument expected for a simple assignment. | 1103 // Exactly one argument expected for a simple assignment. |
| 1094 assert(!node.arguments.isEmpty); | 1104 assert(!node.arguments.isEmpty); |
| 1095 assert(node.arguments.tail.isEmpty); | 1105 assert(node.arguments.tail.isEmpty); |
| 1096 result = visit(node.arguments.head); | 1106 result = visit(node.arguments.head); |
| 1107 result.useElementAsHint(element); |
| 1097 assignedVars[variableIndex[element]] = result; | 1108 assignedVars[variableIndex[element]] = result; |
| 1098 return result; | 1109 return result; |
| 1099 } else if (Elements.isStaticOrTopLevel(element)) { | 1110 } else if (Elements.isStaticOrTopLevel(element)) { |
| 1100 assert(element.isField || element.isSetter); | 1111 assert(element.isField || element.isSetter); |
| 1101 assert(!node.arguments.isEmpty && node.arguments.tail.isEmpty); | 1112 assert(!node.arguments.isEmpty && node.arguments.tail.isEmpty); |
| 1102 ir.Parameter v = new ir.Parameter(null); | 1113 ir.Parameter v = new ir.Parameter(null); |
| 1103 ir.Continuation k = new ir.Continuation([v]); | 1114 ir.Continuation k = new ir.Continuation([v]); |
| 1104 Selector selector = elements.getSelector(node); | 1115 Selector selector = elements.getSelector(node); |
| 1105 ir.Definition arg = visit(node.arguments.head); | 1116 ir.Definition arg = visit(node.arguments.head); |
| 1106 ir.InvokeStatic invoke = | 1117 ir.InvokeStatic invoke = |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1143 ir.Primitive arg; | 1154 ir.Primitive arg; |
| 1144 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { | 1155 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { |
| 1145 assert(node.arguments.isEmpty); | 1156 assert(node.arguments.isEmpty); |
| 1146 arg = new ir.Constant(constantSystem.createInt(1)); | 1157 arg = new ir.Constant(constantSystem.createInt(1)); |
| 1147 add(new ir.LetPrim(arg)); | 1158 add(new ir.LetPrim(arg)); |
| 1148 } else { | 1159 } else { |
| 1149 assert(!node.arguments.isEmpty); | 1160 assert(!node.arguments.isEmpty); |
| 1150 assert(node.arguments.tail.isEmpty); | 1161 assert(node.arguments.tail.isEmpty); |
| 1151 arg = visit(node.arguments.head); | 1162 arg = visit(node.arguments.head); |
| 1152 } | 1163 } |
| 1164 arg.useElementAsHint(element); |
| 1153 result = new ir.Parameter(null); | 1165 result = new ir.Parameter(null); |
| 1154 ir.Continuation k = new ir.Continuation([result]); | 1166 ir.Continuation k = new ir.Continuation([result]); |
| 1155 ir.Expression invoke = new ir.InvokeMethod(getter, selector, k, [arg]); | 1167 ir.Expression invoke = new ir.InvokeMethod(getter, selector, k, [arg]); |
| 1156 add(new ir.LetCont(k, invoke)); | 1168 add(new ir.LetCont(k, invoke)); |
| 1157 | 1169 |
| 1158 assignedVars[variableIndex[element]] = result; | 1170 assignedVars[variableIndex[element]] = result; |
| 1159 | 1171 |
| 1160 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source) && | 1172 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source) && |
| 1161 !node.isPrefix) { | 1173 !node.isPrefix) { |
| 1162 assert(getter != null); | 1174 assert(getter != null); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1281 bool visitType(DartType type, Null _) => false; | 1293 bool visitType(DartType type, Null _) => false; |
| 1282 | 1294 |
| 1283 bool visitDynamicType(DynamicType type, Null _) => true; | 1295 bool visitDynamicType(DynamicType type, Null _) => true; |
| 1284 | 1296 |
| 1285 bool visitVoidType(VoidType type, Null _) => true; | 1297 bool visitVoidType(VoidType type, Null _) => true; |
| 1286 | 1298 |
| 1287 // Currently, InterfaceType and TypedefType are supported so long as they | 1299 // Currently, InterfaceType and TypedefType are supported so long as they |
| 1288 // do not have type parameters. They are subclasses of GenericType. | 1300 // do not have type parameters. They are subclasses of GenericType. |
| 1289 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; | 1301 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; |
| 1290 } | 1302 } |
| OLD | NEW |