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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 // arguments, and what the arguments are. | 199 // arguments, and what the arguments are. |
200 final Map<Element, int> variableIndex; | 200 final Map<Element, int> variableIndex; |
201 final List<Element> index2variable; | 201 final List<Element> index2variable; |
202 final List<ir.Parameter> freeVars; | 202 final List<ir.Parameter> freeVars; |
203 final List<ir.Primitive> assignedVars; | 203 final List<ir.Primitive> assignedVars; |
204 | 204 |
205 ConstExpBuilder constantBuilder; | 205 ConstExpBuilder constantBuilder; |
206 | 206 |
207 final List<ConstDeclaration> localConstants; | 207 final List<ConstDeclaration> localConstants; |
208 | 208 |
| 209 FunctionElement currentFunction; |
| 210 final DetectClosureVariables closureLocals; |
| 211 |
209 /// Construct a top-level visitor. | 212 /// Construct a top-level visitor. |
210 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) | 213 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) |
211 : returnContinuation = new ir.Continuation.retrn(), | 214 : returnContinuation = new ir.Continuation.retrn(), |
212 parameters = <ir.Parameter>[], | 215 parameters = <ir.Parameter>[], |
213 variableIndex = <Element, int>{}, | 216 variableIndex = <Element, int>{}, |
214 freeVars = null, | 217 freeVars = null, |
215 assignedVars = <ir.Primitive>[], | 218 assignedVars = <ir.Primitive>[], |
216 index2variable = <Element>[], | 219 index2variable = <Element>[], |
217 localConstants = <ConstDeclaration>[], | 220 localConstants = <ConstDeclaration>[], |
| 221 closureLocals = new DetectClosureVariables(elements), |
218 super(elements, compiler) { | 222 super(elements, compiler) { |
219 constantBuilder = new ConstExpBuilder(this); | 223 constantBuilder = new ConstExpBuilder(this); |
220 } | 224 } |
221 | 225 |
222 /// Construct a delimited visitor. | 226 /// Construct a delimited visitor. |
223 IrBuilder.delimited(IrBuilder parent) | 227 IrBuilder.delimited(IrBuilder parent) |
224 : sourceFile = parent.sourceFile, | 228 : sourceFile = parent.sourceFile, |
225 returnContinuation = parent.returnContinuation, | 229 returnContinuation = parent.returnContinuation, |
226 parameters = parent.parameters, | 230 parameters = parent.parameters, |
227 variableIndex = parent.variableIndex, | 231 variableIndex = parent.variableIndex, |
228 freeVars = new List<ir.Parameter>.generate( | 232 freeVars = new List<ir.Parameter>.generate( |
229 parent.assignedVars.length, (_) => new ir.Parameter(null), | 233 parent.assignedVars.length, (_) => new ir.Parameter(null), |
230 growable: false), | 234 growable: false), |
231 assignedVars = new List<ir.Primitive>.generate( | 235 assignedVars = new List<ir.Primitive>.generate( |
232 parent.assignedVars.length, (_) => null), | 236 parent.assignedVars.length, (_) => null), |
233 index2variable = new List<Element>.from(parent.index2variable), | 237 index2variable = new List<Element>.from(parent.index2variable), |
234 constantBuilder = parent.constantBuilder, | 238 constantBuilder = parent.constantBuilder, |
235 localConstants = parent.localConstants, | 239 localConstants = parent.localConstants, |
| 240 currentFunction = parent.currentFunction, |
| 241 closureLocals = parent.closureLocals, |
236 super(parent.elements, parent.compiler); | 242 super(parent.elements, parent.compiler); |
237 | 243 |
238 /** | 244 /** |
239 * Builds the [ir.FunctionDefinition] for a function element. In case the | 245 * Builds the [ir.FunctionDefinition] for a function element. In case the |
240 * function uses features that cannot be expressed in the IR, this function | 246 * function uses features that cannot be expressed in the IR, this function |
241 * returns `null`. | 247 * returns `null`. |
242 */ | 248 */ |
243 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 249 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
244 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 250 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
245 } | 251 } |
246 | 252 |
247 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 253 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { |
248 assert(invariant(element, element.isImplementation)); | 254 assert(invariant(element, element.isImplementation)); |
| 255 currentFunction = element; |
249 ast.FunctionExpression function = element.node; | 256 ast.FunctionExpression function = element.node; |
250 assert(function != null); | 257 assert(function != null); |
251 assert(!function.modifiers.isExternal); | 258 assert(!function.modifiers.isExternal); |
252 assert(elements[function] != null); | 259 assert(elements[function] != null); |
253 | 260 |
| 261 closureLocals.visit(function); |
| 262 |
254 root = current = null; | 263 root = current = null; |
255 | 264 |
256 FunctionSignature signature = element.functionSignature; | 265 FunctionSignature signature = element.functionSignature; |
257 signature.orderedForEachParameter((parameterElement) { | 266 signature.orderedForEachParameter((ParameterElement parameterElement) { |
| 267 // TODO(asgerf): Handle parameters with default values. (Use a ConstExp) |
| 268 if (parameterElement.initializer != null) { |
| 269 giveup(parameterElement.node, 'Function parameter with default value'); |
| 270 } |
258 ir.Parameter parameter = new ir.Parameter(parameterElement); | 271 ir.Parameter parameter = new ir.Parameter(parameterElement); |
259 parameters.add(parameter); | 272 parameters.add(parameter); |
260 variableIndex[parameterElement] = assignedVars.length; | 273 if (isClosureVariable(parameterElement)) { |
261 assignedVars.add(parameter); | 274 add(new ir.SetClosureVariable(parameterElement, parameter)); |
262 index2variable.add(parameterElement); | 275 } else { |
| 276 variableIndex[parameterElement] = assignedVars.length; |
| 277 assignedVars.add(parameter); |
| 278 index2variable.add(parameterElement); |
| 279 } |
263 }); | 280 }); |
264 | 281 |
265 visit(function.body); | 282 visit(function.body); |
266 ensureReturn(function); | 283 ensureReturn(function); |
267 return new ir.FunctionDefinition(returnContinuation, parameters, root, | 284 return new ir.FunctionDefinition(element, returnContinuation, parameters, |
268 localConstants); | 285 root, localConstants); |
269 } | 286 } |
270 | 287 |
271 ConstantSystem get constantSystem => compiler.backend.constantSystem; | 288 ConstantSystem get constantSystem => compiler.backend.constantSystem; |
272 | 289 |
273 bool get isOpen => root == null || current != null; | 290 bool get isOpen => root == null || current != null; |
274 | 291 |
275 // Plug an expression into the 'hole' in the context being accumulated. The | 292 // Plug an expression into the 'hole' in the context being accumulated. The |
276 // empty context (just a hole) is represented by root (and current) being | 293 // empty context (just a hole) is represented by root (and current) being |
277 // null. Since the hole in the current context is filled by this function, | 294 // null. Since the hole in the current context is filled by this function, |
278 // the new hole must be in the newly added expression---which becomes the | 295 // the new hole must be in the newly added expression---which becomes the |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 reachingDefinition.substituteFor(bodyBuilder.freeVars[i]); | 525 reachingDefinition.substituteFor(bodyBuilder.freeVars[i]); |
509 } else { | 526 } else { |
510 condBuilder.assignedVars[i].substituteFor(bodyBuilder.freeVars[i]); | 527 condBuilder.assignedVars[i].substituteFor(bodyBuilder.freeVars[i]); |
511 } | 528 } |
512 reachingDefinition.substituteFor(condBuilder.freeVars[i]); | 529 reachingDefinition.substituteFor(condBuilder.freeVars[i]); |
513 } | 530 } |
514 } | 531 } |
515 | 532 |
516 ir.Primitive visitFor(ast.For node) { | 533 ir.Primitive visitFor(ast.For node) { |
517 assert(isOpen); | 534 assert(isOpen); |
| 535 // TODO(asgerf): Handle closure variables declared in a for-loop. |
| 536 if (node.initializer is ast.VariableDefinitions) { |
| 537 ast.VariableDefinitions definitions = node.initializer; |
| 538 for (ast.Node definition in definitions.definitions.nodes) { |
| 539 Element element = elements[definition]; |
| 540 if (isClosureVariable(element)) { |
| 541 return giveup(definition, 'Closure variable in for loop initializer'); |
| 542 } |
| 543 } |
| 544 } |
| 545 |
518 // For loops use three named continuations: the entry to the condition, | 546 // For loops use three named continuations: the entry to the condition, |
519 // the entry to the body, and the loop exit (break). The CPS translation | 547 // the entry to the body, and the loop exit (break). The CPS translation |
520 // of [[for (initializer; condition; update) body; successor]] is: | 548 // of [[for (initializer; condition; update) body; successor]] is: |
521 // | 549 // |
522 // [[initializer]]; | 550 // [[initializer]]; |
523 // let cont loop(x, ...) = | 551 // let cont loop(x, ...) = |
524 // let cont exit() = [[successor]] in | 552 // let cont exit() = [[successor]] in |
525 // let cont body() = [[body]]; [[update]]; loop(v, ...) in | 553 // let cont body() = [[body]]; [[update]]; loop(v, ...) in |
526 // let prim cond = [[condition]] in | 554 // let prim cond = [[condition]] in |
527 // branch cond (body, exit) in | 555 // branch cond (body, exit) in |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 for (ast.SendSet definition in node.definitions.nodes) { | 752 for (ast.SendSet definition in node.definitions.nodes) { |
725 assert(!definition.arguments.isEmpty); | 753 assert(!definition.arguments.isEmpty); |
726 assert(definition.arguments.tail.isEmpty); | 754 assert(definition.arguments.tail.isEmpty); |
727 VariableElement element = elements[definition]; | 755 VariableElement element = elements[definition]; |
728 ConstExp value = constantBuilder.visit(definition.arguments.head); | 756 ConstExp value = constantBuilder.visit(definition.arguments.head); |
729 localConstants.add(new ConstDeclaration(element, value)); | 757 localConstants.add(new ConstDeclaration(element, value)); |
730 } | 758 } |
731 } else { | 759 } else { |
732 for (ast.Node definition in node.definitions.nodes) { | 760 for (ast.Node definition in node.definitions.nodes) { |
733 Element element = elements[definition]; | 761 Element element = elements[definition]; |
| 762 ir.Primitive initialValue; |
734 // Definitions are either SendSets if there is an initializer, or | 763 // Definitions are either SendSets if there is an initializer, or |
735 // Identifiers if there is no initializer. | 764 // Identifiers if there is no initializer. |
736 if (definition is ast.SendSet) { | 765 if (definition is ast.SendSet) { |
737 assert(!definition.arguments.isEmpty); | 766 assert(!definition.arguments.isEmpty); |
738 assert(definition.arguments.tail.isEmpty); | 767 assert(definition.arguments.tail.isEmpty); |
739 ir.Primitive initialValue = visit(definition.arguments.head); | 768 initialValue = visit(definition.arguments.head); |
| 769 } else { |
| 770 assert(definition is ast.Identifier); |
| 771 // The initial value is null. |
| 772 // TODO(kmillikin): Consider pooling constants. |
| 773 initialValue = makePrimConst(constantSystem.createNull()); |
| 774 add(new ir.LetPrim(initialValue)); |
| 775 } |
| 776 if (isClosureVariable(element)) { |
| 777 add(new ir.SetClosureVariable(element, initialValue, |
| 778 isDeclaration: true)); |
| 779 } else { |
740 // In case a primitive was introduced for the initializer expression, | 780 // In case a primitive was introduced for the initializer expression, |
741 // use this variable element to help derive a good name for it. | 781 // use this variable element to help derive a good name for it. |
742 initialValue.useElementAsHint(element); | 782 initialValue.useElementAsHint(element); |
743 variableIndex[element] = assignedVars.length; | 783 variableIndex[element] = assignedVars.length; |
744 assignedVars.add(initialValue); | 784 assignedVars.add(initialValue); |
745 index2variable.add(element); | 785 index2variable.add(element); |
746 } else { | |
747 assert(definition is ast.Identifier); | |
748 // The initial value is null. | |
749 // TODO(kmillikin): Consider pooling constants. | |
750 ir.Constant constant = makePrimConst(constantSystem.createNull()); | |
751 constant.useElementAsHint(element); | |
752 add(new ir.LetPrim(constant)); | |
753 variableIndex[element] = assignedVars.length; | |
754 assignedVars.add(constant); | |
755 index2variable.add(element); | |
756 } | 786 } |
757 } | 787 } |
758 } | 788 } |
759 return null; | 789 return null; |
760 } | 790 } |
761 | 791 |
762 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 792 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
763 // where (C', x) = Build(e, C) | 793 // where (C', x) = Build(e, C) |
764 // | 794 // |
765 // Return without a subexpression is translated as if it were return null. | 795 // Return without a subexpression is translated as if it were return null. |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 ir.Primitive visitAssert(ast.Send node) { | 982 ir.Primitive visitAssert(ast.Send node) { |
953 assert(isOpen); | 983 assert(isOpen); |
954 return giveup(node, 'Assert'); | 984 return giveup(node, 'Assert'); |
955 } | 985 } |
956 | 986 |
957 ir.Primitive visitNamedArgument(ast.NamedArgument node) { | 987 ir.Primitive visitNamedArgument(ast.NamedArgument node) { |
958 assert(isOpen); | 988 assert(isOpen); |
959 return visit(node.expression); | 989 return visit(node.expression); |
960 } | 990 } |
961 | 991 |
| 992 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) { |
| 993 ir.Parameter v = new ir.Parameter(null); |
| 994 ir.Continuation k = new ir.Continuation([v]); |
| 995 ir.Expression expression = build(k); |
| 996 add(new ir.LetCont(k, expression)); |
| 997 return v; |
| 998 } |
| 999 |
962 ir.Primitive translateClosureCall(ir.Primitive receiver, | 1000 ir.Primitive translateClosureCall(ir.Primitive receiver, |
963 Selector closureSelector, | 1001 Selector closureSelector, |
964 ast.NodeList arguments) { | 1002 ast.NodeList arguments) { |
965 Selector namedCallSelector = new Selector(closureSelector.kind, | 1003 Selector namedCallSelector = new Selector(closureSelector.kind, |
966 "call", | 1004 "call", |
967 closureSelector.library, | 1005 closureSelector.library, |
968 closureSelector.argumentCount, | 1006 closureSelector.argumentCount, |
969 closureSelector.namedArguments); | 1007 closureSelector.namedArguments); |
970 List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false); | 1008 List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false); |
971 ir.Parameter v = new ir.Parameter(null); | 1009 return continueWithExpression( |
972 ir.Continuation k = new ir.Continuation([v]); | 1010 (k) => new ir.InvokeMethod(receiver, namedCallSelector, k, args)); |
973 ir.Expression invoke = | |
974 new ir.InvokeMethod(receiver, namedCallSelector, k, args); | |
975 add(new ir.LetCont(k, invoke)); | |
976 return v; | |
977 } | 1011 } |
978 | 1012 |
979 ir.Primitive visitClosureSend(ast.Send node) { | 1013 ir.Primitive visitClosureSend(ast.Send node) { |
980 assert(isOpen); | 1014 assert(isOpen); |
981 Element element = elements[node]; | 1015 Element element = elements[node]; |
982 ir.Primitive closureTarget; | 1016 ir.Primitive closureTarget; |
983 if (element == null) { | 1017 if (element == null) { |
984 closureTarget = visit(node.selector); | 1018 closureTarget = visit(node.selector); |
| 1019 } else if (isClosureVariable(element)) { |
| 1020 closureTarget = new ir.GetClosureVariable(element); |
| 1021 add(new ir.LetPrim(closureTarget)); |
985 } else { | 1022 } else { |
986 assert(Elements.isLocal(element)); | 1023 assert(Elements.isLocal(element)); |
987 closureTarget = lookupLocal(element); | 1024 closureTarget = lookupLocal(element); |
988 } | 1025 } |
989 Selector closureSelector = elements.getSelector(node); | 1026 Selector closureSelector = elements.getSelector(node); |
990 return translateClosureCall(closureTarget, closureSelector, | 1027 return translateClosureCall(closureTarget, closureSelector, |
991 node.argumentsNode); | 1028 node.argumentsNode); |
992 } | 1029 } |
993 | 1030 |
994 /// If [node] is null, returns this. | 1031 /// If [node] is null, returns this. |
(...skipping 18 matching lines...) Expand all Loading... |
1013 } | 1050 } |
1014 | 1051 |
1015 ir.Primitive visitDynamicSend(ast.Send node) { | 1052 ir.Primitive visitDynamicSend(ast.Send node) { |
1016 assert(isOpen); | 1053 assert(isOpen); |
1017 Selector selector = elements.getSelector(node); | 1054 Selector selector = elements.getSelector(node); |
1018 ir.Primitive receiver = visitReceiver(node.receiver); | 1055 ir.Primitive receiver = visitReceiver(node.receiver); |
1019 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1056 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
1020 for (ast.Node n in node.arguments) { | 1057 for (ast.Node n in node.arguments) { |
1021 arguments.add(visit(n)); | 1058 arguments.add(visit(n)); |
1022 } | 1059 } |
1023 ir.Parameter v = new ir.Parameter(null); | 1060 return continueWithExpression( |
1024 ir.Continuation k = new ir.Continuation([v]); | 1061 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
1025 ir.Expression invoke = | |
1026 createDynamicInvoke(node, selector, receiver, k, arguments); | |
1027 add(new ir.LetCont(k, invoke)); | |
1028 return v; | |
1029 } | 1062 } |
1030 | 1063 |
1031 _GetterElements translateGetter(ast.Send node, Selector selector) { | 1064 _GetterElements translateGetter(ast.Send node, Selector selector) { |
1032 Element element = elements[node]; | 1065 Element element = elements[node]; |
1033 ir.Primitive result; | 1066 ir.Primitive result; |
1034 ir.Primitive receiver; | 1067 ir.Primitive receiver; |
1035 ir.Primitive index; | 1068 ir.Primitive index; |
1036 | 1069 |
1037 if (Elements.isErroneousElement(element)) { | 1070 if (Elements.isErroneousElement(element)) { |
1038 giveup(node, 'Erroneous element on GetterSend'); | 1071 return giveup(node, 'Erroneous element on GetterSend'); |
1039 return null; | |
1040 } | 1072 } |
1041 | 1073 |
1042 if (element != null && element.isConst) { | 1074 if (element != null && element.isConst) { |
1043 // Reference to constant local, top-level or static field | 1075 // Reference to constant local, top-level or static field |
1044 | |
1045 result = translateConstant(node); | 1076 result = translateConstant(node); |
| 1077 } else if (isClosureVariable(element)) { |
| 1078 result = new ir.GetClosureVariable(element); |
| 1079 add(new ir.LetPrim(result)); |
1046 } else if (Elements.isLocal(element)) { | 1080 } else if (Elements.isLocal(element)) { |
1047 // Reference to local variable | 1081 // Reference to local variable |
1048 | |
1049 result = lookupLocal(element); | 1082 result = lookupLocal(element); |
1050 } else if (element == null || | 1083 } else if (element == null || |
1051 Elements.isInstanceField(element) || | 1084 Elements.isInstanceField(element) || |
1052 Elements.isInstanceMethod(element) || | 1085 Elements.isInstanceMethod(element) || |
1053 selector.isIndex || | 1086 selector.isIndex || |
1054 node.isSuperCall) { | 1087 node.isSuperCall) { |
1055 // Dynamic dispatch to a getter. Sometimes resolution will suggest a target | 1088 // Dynamic dispatch to a getter. Sometimes resolution will suggest a target |
1056 // element, but in these cases we must still emit a dynamic dispatch. The | 1089 // element, but in these cases we must still emit a dynamic dispatch. The |
1057 // target element may be an instance method in case we are converting a | 1090 // target element may be an instance method in case we are converting a |
1058 // method to a function object. | 1091 // method to a function object. |
1059 | 1092 |
1060 receiver = visitReceiver(node.receiver); | 1093 receiver = visitReceiver(node.receiver); |
1061 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1094 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
1062 if (selector.isIndex) { | 1095 if (selector.isIndex) { |
1063 index = visit(node.arguments.head); | 1096 index = visit(node.arguments.head); |
1064 arguments.add(index); | 1097 arguments.add(index); |
1065 } | 1098 } |
1066 | 1099 |
1067 ir.Parameter v = new ir.Parameter(null); | |
1068 ir.Continuation k = new ir.Continuation([v]); | |
1069 assert(selector.kind == SelectorKind.GETTER || | 1100 assert(selector.kind == SelectorKind.GETTER || |
1070 selector.kind == SelectorKind.INDEX); | 1101 selector.kind == SelectorKind.INDEX); |
1071 ir.Expression invoke = | 1102 result = continueWithExpression( |
1072 createDynamicInvoke(node, selector, receiver, k, arguments); | 1103 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
1073 add(new ir.LetCont(k, invoke)); | 1104 } else if (element.isField || element.isGetter || element.isSetter) { |
1074 result = v; | 1105 // Access to a static field or getter (non-static case handled above). |
1075 } else if (element.isField || element.isGetter || | 1106 // Even if there is only a setter, we compile as if it was a getter, |
1076 // Access to a static field or getter (non-static case handled above). | 1107 // so the vm can fail at runtime. |
1077 // Even if there is only a setter, we compile as if it was a getter, | |
1078 // so the vm can fail at runtime. | |
1079 | |
1080 element.isSetter) { | |
1081 ir.Parameter v = new ir.Parameter(null); | |
1082 ir.Continuation k = new ir.Continuation([v]); | |
1083 assert(selector.kind == SelectorKind.GETTER || | 1108 assert(selector.kind == SelectorKind.GETTER || |
1084 selector.kind == SelectorKind.SETTER); | 1109 selector.kind == SelectorKind.SETTER); |
1085 ir.Expression invoke = | 1110 result = continueWithExpression( |
1086 new ir.InvokeStatic(element, selector, k, []); | 1111 (k) => new ir.InvokeStatic(element, selector, k, [])); |
1087 add(new ir.LetCont(k, invoke)); | |
1088 result = v; | |
1089 } else if (Elements.isStaticOrTopLevelFunction(element)) { | 1112 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
1090 // Convert a top-level or static function to a function object. | 1113 // Convert a top-level or static function to a function object. |
1091 | |
1092 result = translateConstant(node); | 1114 result = translateConstant(node); |
1093 } else { | 1115 } else { |
1094 throw "Unexpected SendSet getter: $node, $element"; | 1116 throw "Unexpected SendSet getter: $node, $element"; |
1095 } | 1117 } |
1096 return new _GetterElements( | 1118 return new _GetterElements( |
1097 result: result,index: index, receiver: receiver); | 1119 result: result,index: index, receiver: receiver); |
1098 } | 1120 } |
1099 | 1121 |
1100 ir.Primitive visitGetterSend(ast.Send node) { | 1122 ir.Primitive visitGetterSend(ast.Send node) { |
1101 assert(isOpen); | 1123 assert(isOpen); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1247 if (type.isMalformed) return giveup(node, "Malformed type for is"); | 1269 if (type.isMalformed) return giveup(node, "Malformed type for is"); |
1248 ir.Primitive receiver = visit(node.receiver); | 1270 ir.Primitive receiver = visit(node.receiver); |
1249 ir.IsCheck isCheck = new ir.IsCheck(receiver, type); | 1271 ir.IsCheck isCheck = new ir.IsCheck(receiver, type); |
1250 add(new ir.LetPrim(isCheck)); | 1272 add(new ir.LetPrim(isCheck)); |
1251 return node.isIsNotCheck ? buildNegation(isCheck) : isCheck; | 1273 return node.isIsNotCheck ? buildNegation(isCheck) : isCheck; |
1252 } | 1274 } |
1253 if (op.source == "as") { | 1275 if (op.source == "as") { |
1254 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 1276 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); |
1255 if (type.isMalformed) return giveup(node, "Malformed type for as"); | 1277 if (type.isMalformed) return giveup(node, "Malformed type for as"); |
1256 ir.Primitive receiver = visit(node.receiver); | 1278 ir.Primitive receiver = visit(node.receiver); |
1257 ir.Parameter v = new ir.Parameter(null); | 1279 return continueWithExpression( |
1258 ir.Continuation k = new ir.Continuation([v]); | 1280 (k) => new ir.AsCast(receiver, type, k)); |
1259 ir.AsCast asCast = new ir.AsCast(receiver, type, k); | |
1260 add(new ir.LetCont(k, asCast)); | |
1261 return v; | |
1262 } | 1281 } |
1263 return giveup(node); | 1282 return giveup(node); |
1264 } | 1283 } |
1265 | 1284 |
1266 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] | 1285 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] |
1267 // where (C', xs) = arguments.fold(Build, C) | 1286 // where (C', xs) = arguments.fold(Build, C) |
1268 ir.Primitive visitStaticSend(ast.Send node) { | 1287 ir.Primitive visitStaticSend(ast.Send node) { |
1269 assert(isOpen); | 1288 assert(isOpen); |
1270 Element element = elements[node]; | 1289 Element element = elements[node]; |
1271 // TODO(lry): support constructors / factory calls. | 1290 // TODO(lry): support constructors / factory calls. |
1272 if (element.isConstructor) return giveup(node, 'StaticSend: constructor'); | 1291 if (element.isConstructor) return giveup(node, 'StaticSend: constructor'); |
1273 // TODO(lry): support foreign functions. | 1292 // TODO(lry): support foreign functions. |
1274 if (element.isForeign(compiler)) return giveup(node, 'StaticSend: foreign'); | 1293 if (element.isForeign(compiler)) return giveup(node, 'StaticSend: foreign'); |
1275 // TODO(lry): for elements that could not be resolved emit code to throw a | 1294 // TODO(lry): for elements that could not be resolved emit code to throw a |
1276 // [NoSuchMethodError]. | 1295 // [NoSuchMethodError]. |
1277 if (element.isErroneous) return giveup(node, 'StaticSend: erroneous'); | 1296 if (element.isErroneous) return giveup(node, 'StaticSend: erroneous'); |
1278 // TODO(lry): generate IR for object identicality. | 1297 // TODO(lry): generate IR for object identicality. |
1279 if (element == compiler.identicalFunction) { | 1298 if (element == compiler.identicalFunction) { |
1280 return giveup(node, 'StaticSend: identical'); | 1299 return giveup(node, 'StaticSend: identical'); |
1281 } | 1300 } |
1282 | 1301 |
1283 Selector selector = elements.getSelector(node); | 1302 Selector selector = elements.getSelector(node); |
1284 | 1303 |
1285 // TODO(lry): support default arguments, need support for locals. | 1304 // TODO(lry): support default arguments, need support for locals. |
1286 List<ir.Definition> arguments = node.arguments.mapToList(visit, | 1305 List<ir.Definition> arguments = node.arguments.mapToList(visit, |
1287 growable:false); | 1306 growable:false); |
1288 ir.Parameter v = new ir.Parameter(null); | 1307 return continueWithExpression( |
1289 ir.Continuation k = new ir.Continuation([v]); | 1308 (k) => new ir.InvokeStatic(element, selector, k, arguments)); |
1290 ir.Expression invoke = | |
1291 new ir.InvokeStatic(element, selector, k, arguments); | |
1292 add(new ir.LetCont(k, invoke)); | |
1293 return v; | |
1294 } | 1309 } |
1295 | 1310 |
1296 ir.Primitive visitSuperSend(ast.Send node) { | 1311 ir.Primitive visitSuperSend(ast.Send node) { |
1297 assert(isOpen); | 1312 assert(isOpen); |
1298 if (node.isPropertyAccess) { | 1313 if (node.isPropertyAccess) { |
1299 return visitGetterSend(node); | 1314 return visitGetterSend(node); |
1300 } else { | 1315 } else { |
1301 return visitDynamicSend(node); | 1316 return visitDynamicSend(node); |
1302 } | 1317 } |
1303 } | 1318 } |
1304 | 1319 |
1305 visitTypePrefixSend(ast.Send node) { | 1320 visitTypePrefixSend(ast.Send node) { |
1306 compiler.internalError(node, "visitTypePrefixSend should not be called."); | 1321 compiler.internalError(node, "visitTypePrefixSend should not be called."); |
1307 } | 1322 } |
1308 | 1323 |
1309 ir.Primitive visitTypeLiteralSend(ast.Send node) { | 1324 ir.Primitive visitTypeLiteralSend(ast.Send node) { |
1310 assert(isOpen); | 1325 assert(isOpen); |
1311 // If the user is trying to invoke the type literal or variable, | 1326 // If the user is trying to invoke the type literal or variable, |
1312 // it must be treated as a function call. | 1327 // it must be treated as a function call. |
1313 if (node.argumentsNode != null) { | 1328 if (node.argumentsNode != null) { |
1314 // TODO(sigurdm): Change this to match proposed semantics of issue #19725. | 1329 // TODO(sigurdm): Handle this to match proposed semantics of issue #19725. |
1315 return visitDynamicSend(node); | 1330 return giveup(node, 'Type literal invoked as function'); |
1316 } | 1331 } |
1317 | 1332 |
1318 DartType type = elements.getTypeLiteralType(node); | 1333 DartType type = elements.getTypeLiteralType(node); |
1319 if (type is TypeVariableType) { | 1334 if (type is TypeVariableType) { |
1320 ir.Primitive prim = new ir.ReifyTypeVar(type.element); | 1335 ir.Primitive prim = new ir.ReifyTypeVar(type.element); |
1321 add(new ir.LetPrim(prim)); | 1336 add(new ir.LetPrim(prim)); |
1322 return prim; | 1337 return prim; |
1323 } else { | 1338 } else { |
1324 return translateConstant(node); | 1339 return translateConstant(node); |
1325 } | 1340 } |
1326 } | 1341 } |
1327 | 1342 |
| 1343 /// True if [element] is a local variable, local function, or parameter that |
| 1344 /// is accessed from an inner function. Recursive self-references in a local |
| 1345 /// function count as closure accesses. |
| 1346 bool isClosureVariable(Element element) { |
| 1347 return closureLocals.isClosureVariable(element); |
| 1348 } |
| 1349 |
1328 ir.Primitive visitSendSet(ast.SendSet node) { | 1350 ir.Primitive visitSendSet(ast.SendSet node) { |
1329 assert(isOpen); | 1351 assert(isOpen); |
1330 Element element = elements[node]; | 1352 Element element = elements[node]; |
1331 ast.Operator op = node.assignmentOperator; | 1353 ast.Operator op = node.assignmentOperator; |
1332 // For complex operators, this is the result of getting (before assigning) | 1354 // For complex operators, this is the result of getting (before assigning) |
1333 ir.Primitive originalValue; | 1355 ir.Primitive originalValue; |
1334 // For []+= style operators, this saves the index. | 1356 // For []+= style operators, this saves the index. |
1335 ir.Primitive index; | 1357 ir.Primitive index; |
1336 ir.Primitive receiver; | 1358 ir.Primitive receiver; |
1337 // This is what gets assigned. | 1359 // This is what gets assigned. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1379 arg = visit(assignArg); | 1401 arg = visit(assignArg); |
1380 } | 1402 } |
1381 valueToStore = new ir.Parameter(null); | 1403 valueToStore = new ir.Parameter(null); |
1382 ir.Continuation k = new ir.Continuation([valueToStore]); | 1404 ir.Continuation k = new ir.Continuation([valueToStore]); |
1383 ir.Expression invoke = | 1405 ir.Expression invoke = |
1384 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]); | 1406 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]); |
1385 add(new ir.LetCont(k, invoke)); | 1407 add(new ir.LetCont(k, invoke)); |
1386 } | 1408 } |
1387 | 1409 |
1388 // Set the value | 1410 // Set the value |
1389 if (Elements.isLocal(element)) { | 1411 if (isClosureVariable(element)) { |
| 1412 add(new ir.SetClosureVariable(element, valueToStore)); |
| 1413 } else if (Elements.isLocal(element)) { |
1390 valueToStore.useElementAsHint(element); | 1414 valueToStore.useElementAsHint(element); |
1391 assignedVars[variableIndex[element]] = valueToStore; | 1415 assignedVars[variableIndex[element]] = valueToStore; |
1392 } else if (Elements.isStaticOrTopLevel(element)) { | 1416 } else if (Elements.isStaticOrTopLevel(element)) { |
1393 assert(element.isField || element.isSetter); | 1417 assert(element.isField || element.isSetter); |
1394 ir.Parameter v = new ir.Parameter(null); | |
1395 ir.Continuation k = new ir.Continuation([v]); | |
1396 Selector selector = elements.getSelector(node); | 1418 Selector selector = elements.getSelector(node); |
1397 ir.InvokeStatic invoke = | 1419 continueWithExpression( |
1398 new ir.InvokeStatic(element, selector, k, [valueToStore]); | 1420 (k) => new ir.InvokeStatic(element, selector, k, [valueToStore])); |
1399 add(new ir.LetCont(k, invoke)); | |
1400 } else { | 1421 } else { |
1401 if (element != null && Elements.isUnresolved(element)) { | 1422 if (element != null && Elements.isUnresolved(element)) { |
1402 return giveup(node, 'SendSet: non-local, non-static, unresolved'); | 1423 return giveup(node, 'SendSet: non-local, non-static, unresolved'); |
1403 } | 1424 } |
1404 // Setter or index-setter invocation | 1425 // Setter or index-setter invocation |
1405 ir.Parameter v = new ir.Parameter(null); | |
1406 ir.Continuation k = new ir.Continuation([v]); | |
1407 Selector selector = elements.getSelector(node); | 1426 Selector selector = elements.getSelector(node); |
1408 assert(selector.kind == SelectorKind.SETTER || | 1427 assert(selector.kind == SelectorKind.SETTER || |
1409 selector.kind == SelectorKind.INDEX); | 1428 selector.kind == SelectorKind.INDEX); |
1410 List<ir.Definition> arguments = selector.isIndexSet | 1429 List<ir.Definition> arguments = selector.isIndexSet |
1411 ? [index, valueToStore] | 1430 ? [index, valueToStore] |
1412 : [valueToStore]; | 1431 : [valueToStore]; |
1413 ir.Expression invoke = | 1432 continueWithExpression( |
1414 createDynamicInvoke(node, selector, receiver, k, arguments); | 1433 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
1415 add(new ir.LetCont(k, invoke)); | |
1416 } | 1434 } |
1417 | 1435 |
1418 if (node.isPostfix) { | 1436 if (node.isPostfix) { |
1419 assert(originalValue != null); | 1437 assert(originalValue != null); |
1420 return originalValue; | 1438 return originalValue; |
1421 } else { | 1439 } else { |
1422 return valueToStore; | 1440 return valueToStore; |
1423 } | 1441 } |
1424 } | 1442 } |
1425 | 1443 |
1426 ir.Primitive visitNewExpression(ast.NewExpression node) { | 1444 ir.Primitive visitNewExpression(ast.NewExpression node) { |
1427 assert(isOpen); | 1445 assert(isOpen); |
1428 if (node.isConst) { | 1446 if (node.isConst) { |
1429 return translateConstant(node); | 1447 return translateConstant(node); |
1430 } | 1448 } |
1431 FunctionElement element = elements[node.send]; | 1449 FunctionElement element = elements[node.send]; |
1432 if (Elements.isUnresolved(element)) { | 1450 if (Elements.isUnresolved(element)) { |
1433 return giveup(node, 'NewExpression: unresolved constructor'); | 1451 return giveup(node, 'NewExpression: unresolved constructor'); |
1434 } | 1452 } |
1435 Selector selector = elements.getSelector(node.send); | 1453 Selector selector = elements.getSelector(node.send); |
1436 ast.Node selectorNode = node.send.selector; | 1454 ast.Node selectorNode = node.send.selector; |
1437 GenericType type = elements.getType(node); | 1455 GenericType type = elements.getType(node); |
1438 List<ir.Primitive> args = | 1456 List<ir.Primitive> args = |
1439 node.send.arguments.mapToList(visit, growable:false); | 1457 node.send.arguments.mapToList(visit, growable:false); |
1440 ir.Parameter v = new ir.Parameter(null); | 1458 return continueWithExpression( |
1441 ir.Continuation k = new ir.Continuation([v]); | 1459 (k) => new ir.InvokeConstructor(type, element,selector, k, args)); |
1442 ir.InvokeConstructor invoke = | |
1443 new ir.InvokeConstructor(type, element,selector, k, args); | |
1444 add(new ir.LetCont(k, invoke)); | |
1445 return v; | |
1446 } | 1460 } |
1447 | 1461 |
1448 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { | 1462 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) { |
1449 assert(isOpen); | 1463 assert(isOpen); |
1450 ir.Primitive first = visit(node.first); | 1464 ir.Primitive first = visit(node.first); |
1451 ir.Primitive second = visit(node.second); | 1465 ir.Primitive second = visit(node.second); |
1452 ir.Parameter v = new ir.Parameter(null); | 1466 return continueWithExpression( |
1453 ir.Continuation k = new ir.Continuation([v]); | 1467 (k) => new ir.ConcatenateStrings(k, [first, second])); |
1454 ir.ConcatenateStrings concat = | |
1455 new ir.ConcatenateStrings(k, [first, second]); | |
1456 add(new ir.LetCont(k, concat)); | |
1457 return v; | |
1458 } | 1468 } |
1459 | 1469 |
1460 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) { | 1470 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) { |
1461 assert(isOpen); | 1471 assert(isOpen); |
1462 List<ir.Primitive> arguments = []; | 1472 List<ir.Primitive> arguments = []; |
1463 arguments.add(visitLiteralString(node.string)); | 1473 arguments.add(visitLiteralString(node.string)); |
1464 var it = node.parts.iterator; | 1474 var it = node.parts.iterator; |
1465 while (it.moveNext()) { | 1475 while (it.moveNext()) { |
1466 ast.StringInterpolationPart part = it.current; | 1476 ast.StringInterpolationPart part = it.current; |
1467 arguments.add(visit(part.expression)); | 1477 arguments.add(visit(part.expression)); |
1468 arguments.add(visitLiteralString(part.string)); | 1478 arguments.add(visitLiteralString(part.string)); |
1469 } | 1479 } |
1470 ir.Parameter v = new ir.Parameter(null); | 1480 return continueWithExpression( |
1471 ir.Continuation k = new ir.Continuation([v]); | 1481 (k) => new ir.ConcatenateStrings(k, arguments)); |
1472 ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments); | |
1473 add(new ir.LetCont(k, concat)); | |
1474 return v; | |
1475 } | 1482 } |
1476 | 1483 |
1477 ir.Primitive translateConstant(ast.Node node, [Constant value]) { | 1484 ir.Primitive translateConstant(ast.Node node, [Constant value]) { |
1478 assert(isOpen); | 1485 assert(isOpen); |
1479 if (value == null) { | 1486 if (value == null) { |
1480 value = getConstantForNode(node); | 1487 value = getConstantForNode(node); |
1481 } | 1488 } |
1482 ir.Primitive primitive = makeConst(constantBuilder.visit(node), value); | 1489 ir.Primitive primitive = makeConst(constantBuilder.visit(node), value); |
1483 add(new ir.LetPrim(primitive)); | 1490 add(new ir.LetPrim(primitive)); |
1484 return primitive; | 1491 return primitive; |
1485 } | 1492 } |
1486 | 1493 |
| 1494 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { |
| 1495 return new IrBuilder(elements, compiler, sourceFile) |
| 1496 .buildFunctionInternal(elements[node]); |
| 1497 } |
| 1498 |
| 1499 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 1500 FunctionElement element = elements[node]; |
| 1501 ir.FunctionDefinition inner = makeSubFunction(node); |
| 1502 ir.CreateFunction prim = new ir.CreateFunction(inner); |
| 1503 add(new ir.LetPrim(prim)); |
| 1504 return prim; |
| 1505 } |
| 1506 |
| 1507 ir.Primitive visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 1508 FunctionElement element = elements[node.function]; |
| 1509 ir.FunctionDefinition inner = makeSubFunction(node.function); |
| 1510 if (isClosureVariable(element)) { |
| 1511 add(new ir.DeclareFunction(element, inner)); |
| 1512 } else { |
| 1513 ir.CreateFunction prim = new ir.CreateFunction(inner); |
| 1514 add(new ir.LetPrim(prim)); |
| 1515 variableIndex[element] = assignedVars.length; |
| 1516 assignedVars.add(prim); |
| 1517 index2variable.add(element); |
| 1518 prim.useElementAsHint(element); |
| 1519 } |
| 1520 return null; |
| 1521 } |
| 1522 |
1487 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1523 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
1488 | 1524 |
1489 ir.Primitive giveup(ast.Node node, [String reason]) { | 1525 dynamic giveup(ast.Node node, [String reason]) { |
1490 throw ABORT_IRNODE_BUILDER; | 1526 throw ABORT_IRNODE_BUILDER; |
1491 } | 1527 } |
1492 | 1528 |
1493 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 1529 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { |
1494 try { | 1530 try { |
1495 return action(); | 1531 return action(); |
1496 } catch(e, tr) { | 1532 } catch(e, tr) { |
1497 if (e == ABORT_IRNODE_BUILDER) { | 1533 if (e == ABORT_IRNODE_BUILDER) { |
1498 return null; | 1534 return null; |
1499 } | 1535 } |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1655 ConstExp visitConditional(ast.Conditional node) { | 1691 ConstExp visitConditional(ast.Conditional node) { |
1656 BoolConstant condition = computeConstant(node.condition); | 1692 BoolConstant condition = computeConstant(node.condition); |
1657 return visit(condition.isTrue ? node.thenExpression : node.elseExpression); | 1693 return visit(condition.isTrue ? node.thenExpression : node.elseExpression); |
1658 } | 1694 } |
1659 | 1695 |
1660 ConstExp visitNode(ast.Node node) { | 1696 ConstExp visitNode(ast.Node node) { |
1661 throw "Unexpected constant: $node"; | 1697 throw "Unexpected constant: $node"; |
1662 } | 1698 } |
1663 | 1699 |
1664 } | 1700 } |
| 1701 |
| 1702 /// Classifies local variables and local functions as 'closure variables'. |
| 1703 /// A closure variable is one that is accessed from an inner function nested |
| 1704 /// one or more levels inside the one that declares it. |
| 1705 class DetectClosureVariables extends ast.Visitor { |
| 1706 final TreeElements elements; |
| 1707 DetectClosureVariables(this.elements); |
| 1708 |
| 1709 FunctionElement currentFunction; |
| 1710 Set<Element> usedFromClosure = new Set<Element>(); |
| 1711 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); |
| 1712 |
| 1713 bool isClosureVariable(Element element) => usedFromClosure.contains(element); |
| 1714 |
| 1715 void markAsClosureVariable(Element element) { |
| 1716 usedFromClosure.add(element); |
| 1717 } |
| 1718 |
| 1719 visit(ast.Node node) => node.accept(this); |
| 1720 |
| 1721 visitNode(ast.Node node) { |
| 1722 node.visitChildren(this); |
| 1723 } |
| 1724 |
| 1725 visitSend(ast.Send node) { |
| 1726 Element element = elements[node]; |
| 1727 if (Elements.isLocal(element) && |
| 1728 !element.isConst && |
| 1729 element.enclosingElement != currentFunction) { |
| 1730 markAsClosureVariable(element); |
| 1731 } |
| 1732 node.visitChildren(this); |
| 1733 } |
| 1734 |
| 1735 visitFunctionExpression(ast.FunctionExpression node) { |
| 1736 FunctionElement oldFunction = currentFunction; |
| 1737 currentFunction = elements[node]; |
| 1738 visit(node.body); |
| 1739 currentFunction = oldFunction; |
| 1740 } |
| 1741 |
| 1742 } |
OLD | NEW |