| 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 // In case a primitive was introduced for the initializer expression, |
| 636 // use this variable element to help derive a good name for it. |
| 637 initialValue.useElementAsHint(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 constant.useElementAsHint(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 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1083 Element element = elements[node]; | 1093 Element element = elements[node]; |
| 1084 ast.Operator op = node.assignmentOperator; | 1094 ast.Operator op = node.assignmentOperator; |
| 1085 ir.Primitive result; | 1095 ir.Primitive result; |
| 1086 ir.Primitive getter; | 1096 ir.Primitive getter; |
| 1087 if (op.source == '=') { | 1097 if (op.source == '=') { |
| 1088 if (Elements.isLocal(element)) { | 1098 if (Elements.isLocal(element)) { |
| 1089 // Exactly one argument expected for a simple assignment. | 1099 // Exactly one argument expected for a simple assignment. |
| 1090 assert(!node.arguments.isEmpty); | 1100 assert(!node.arguments.isEmpty); |
| 1091 assert(node.arguments.tail.isEmpty); | 1101 assert(node.arguments.tail.isEmpty); |
| 1092 result = visit(node.arguments.head); | 1102 result = visit(node.arguments.head); |
| 1103 result.useElementAsHint(element); |
| 1093 assignedVars[variableIndex[element]] = result; | 1104 assignedVars[variableIndex[element]] = result; |
| 1094 return result; | 1105 return result; |
| 1095 } else if (Elements.isStaticOrTopLevel(element)) { | 1106 } else if (Elements.isStaticOrTopLevel(element)) { |
| 1096 assert(element.isField || element.isSetter); | 1107 assert(element.isField || element.isSetter); |
| 1097 assert(!node.arguments.isEmpty && node.arguments.tail.isEmpty); | 1108 assert(!node.arguments.isEmpty && node.arguments.tail.isEmpty); |
| 1098 ir.Parameter v = new ir.Parameter(null); | 1109 ir.Parameter v = new ir.Parameter(null); |
| 1099 ir.Continuation k = new ir.Continuation([v]); | 1110 ir.Continuation k = new ir.Continuation([v]); |
| 1100 Selector selector = elements.getSelector(node); | 1111 Selector selector = elements.getSelector(node); |
| 1101 ir.Definition arg = visit(node.arguments.head); | 1112 ir.Definition arg = visit(node.arguments.head); |
| 1102 ir.InvokeStatic invoke = | 1113 ir.InvokeStatic invoke = |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 ir.Primitive arg; | 1150 ir.Primitive arg; |
| 1140 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { | 1151 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) { |
| 1141 assert(node.arguments.isEmpty); | 1152 assert(node.arguments.isEmpty); |
| 1142 arg = new ir.Constant(constantSystem.createInt(1)); | 1153 arg = new ir.Constant(constantSystem.createInt(1)); |
| 1143 add(new ir.LetPrim(arg)); | 1154 add(new ir.LetPrim(arg)); |
| 1144 } else { | 1155 } else { |
| 1145 assert(!node.arguments.isEmpty); | 1156 assert(!node.arguments.isEmpty); |
| 1146 assert(node.arguments.tail.isEmpty); | 1157 assert(node.arguments.tail.isEmpty); |
| 1147 arg = visit(node.arguments.head); | 1158 arg = visit(node.arguments.head); |
| 1148 } | 1159 } |
| 1160 arg.useElementAsHint(element); |
| 1149 result = new ir.Parameter(null); | 1161 result = new ir.Parameter(null); |
| 1150 ir.Continuation k = new ir.Continuation([result]); | 1162 ir.Continuation k = new ir.Continuation([result]); |
| 1151 ir.Expression invoke = new ir.InvokeMethod(getter, selector, k, [arg]); | 1163 ir.Expression invoke = new ir.InvokeMethod(getter, selector, k, [arg]); |
| 1152 add(new ir.LetCont(k, invoke)); | 1164 add(new ir.LetCont(k, invoke)); |
| 1153 | 1165 |
| 1154 assignedVars[variableIndex[element]] = result; | 1166 assignedVars[variableIndex[element]] = result; |
| 1155 | 1167 |
| 1156 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source) && | 1168 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source) && |
| 1157 !node.isPrefix) { | 1169 !node.isPrefix) { |
| 1158 assert(getter != null); | 1170 assert(getter != null); |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1277 bool visitType(DartType type, Null _) => false; | 1289 bool visitType(DartType type, Null _) => false; |
| 1278 | 1290 |
| 1279 bool visitDynamicType(DynamicType type, Null _) => true; | 1291 bool visitDynamicType(DynamicType type, Null _) => true; |
| 1280 | 1292 |
| 1281 bool visitVoidType(VoidType type, Null _) => true; | 1293 bool visitVoidType(VoidType type, Null _) => true; |
| 1282 | 1294 |
| 1283 // Currently, InterfaceType and TypedefType are supported so long as they | 1295 // Currently, InterfaceType and TypedefType are supported so long as they |
| 1284 // do not have type parameters. They are subclasses of GenericType. | 1296 // do not have type parameters. They are subclasses of GenericType. |
| 1285 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; | 1297 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; |
| 1286 } | 1298 } |
| OLD | NEW |