OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class Interceptors { | 5 class Interceptors { |
6 Compiler compiler; | 6 Compiler compiler; |
7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
8 | 8 |
9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 | 159 |
160 /** | 160 /** |
161 * Keeps track of locals (including parameters and phis) when building. The | 161 * Keeps track of locals (including parameters and phis) when building. The |
162 * 'this' reference is treated as parameter and hence handled by this class, | 162 * 'this' reference is treated as parameter and hence handled by this class, |
163 * too. | 163 * too. |
164 */ | 164 */ |
165 class LocalsHandler { | 165 class LocalsHandler { |
166 // The values of locals that can be directly accessed (without redirections | 166 // The values of locals that can be directly accessed (without redirections |
167 // to boxes or closure-fields). | 167 // to boxes or closure-fields). |
168 Map<Element, HInstruction> directLocals; | 168 Map<Element, HInstruction> directLocals; |
169 HInstruction thisDefinition; | |
170 Map<Element, Element> redirectionMapping; | 169 Map<Element, Element> redirectionMapping; |
171 SsaBuilder builder; | 170 SsaBuilder builder; |
172 ClosureData closureData; | 171 ClosureData closureData; |
173 | 172 |
174 LocalsHandler(this.builder) | 173 LocalsHandler(this.builder) |
175 : directLocals = new Map<Element, HInstruction>(), | 174 : directLocals = new Map<Element, HInstruction>(), |
176 redirectionMapping = new Map<Element, Element>(); | 175 redirectionMapping = new Map<Element, Element>(); |
177 | 176 |
178 /** | 177 /** |
179 * Creates a new [LocalsHandler] based on [other]. We only need to | 178 * Creates a new [LocalsHandler] based on [other]. We only need to |
180 * copy the [directLocals], since the other fields can be shared | 179 * copy the [directLocals], since the other fields can be shared |
181 * throughout the AST visit. | 180 * throughout the AST visit. |
182 */ | 181 */ |
183 LocalsHandler.from(LocalsHandler other) | 182 LocalsHandler.from(LocalsHandler other) |
184 : directLocals = new Map<Element, HInstruction>.from(other.directLocals), | 183 : directLocals = new Map<Element, HInstruction>.from(other.directLocals), |
185 redirectionMapping = other.redirectionMapping, | 184 redirectionMapping = other.redirectionMapping, |
186 builder = other.builder, | 185 builder = other.builder, |
187 thisDefinition = other.thisDefinition, | |
188 closureData = other.closureData; | 186 closureData = other.closureData; |
189 | 187 |
190 void startFunction(FunctionElement function, | 188 void startFunction(FunctionElement function, |
191 FunctionExpression node) { | 189 FunctionExpression node) { |
192 | 190 |
193 ClosureTranslator translator = | 191 ClosureTranslator translator = |
194 new ClosureTranslator(builder.compiler, builder.elements); | 192 new ClosureTranslator(builder.compiler, builder.elements); |
195 closureData = translator.translate(node); | 193 closureData = translator.translate(node); |
196 | 194 |
197 if (function.isInstanceMember()) { | 195 if (function.isInstanceMember()) { |
198 thisDefinition = new HThis(); | 196 HInstruction thisInstruction = new HThis(); |
199 builder.add(thisDefinition); | 197 updateLocal(closureData.thisElement, thisInstruction); |
| 198 builder.add(thisInstruction); |
200 } | 199 } |
201 | 200 |
202 FunctionParameters params = function.computeParameters(builder.compiler); | 201 FunctionParameters params = function.computeParameters(builder.compiler); |
203 params.forEachParameter((Element element) { | 202 params.forEachParameter((Element element) { |
204 HParameterValue parameter = new HParameterValue(element); | 203 HParameterValue parameter = new HParameterValue(element); |
205 builder.add(parameter); | 204 builder.add(parameter); |
206 // Note that for constructors [element] could be a field-element which we | 205 // Note that for constructors [element] could be a field-element which we |
207 // treat as if it was a local. | 206 // treat as if it was a local. |
208 directLocals[element] = parameter; | 207 directLocals[element] = parameter; |
209 }); | 208 }); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 */ | 298 */ |
300 HInstruction readLocal(Element element) { | 299 HInstruction readLocal(Element element) { |
301 if (isAccessedDirectly(element)) { | 300 if (isAccessedDirectly(element)) { |
302 if (directLocals[element] == null) { | 301 if (directLocals[element] == null) { |
303 builder.compiler.internalError( | 302 builder.compiler.internalError( |
304 "Could not find value", node: element.parseNode(builder.compiler)); | 303 "Could not find value", node: element.parseNode(builder.compiler)); |
305 } | 304 } |
306 return directLocals[element]; | 305 return directLocals[element]; |
307 } else if (isStoredInClosureField(element)) { | 306 } else if (isStoredInClosureField(element)) { |
308 Element redirect = redirectionMapping[element]; | 307 Element redirect = redirectionMapping[element]; |
309 // We must not use the [LocalsHandler.thisDefinition] since that could | 308 // We must not use the [LocalsHandler.readThis()] since that could |
310 // point to a captured this which would be stored in a closure-field | 309 // point to a captured this which would be stored in a closure-field |
311 // itself. | 310 // itself. |
312 HInstruction receiver = new HThis(); | 311 HInstruction receiver = new HThis(); |
313 builder.add(receiver); | 312 builder.add(receiver); |
314 HInstruction fieldGet = new HFieldGet(redirect, receiver); | 313 HInstruction fieldGet = new HFieldGet(redirect, receiver); |
315 builder.add(fieldGet); | 314 builder.add(fieldGet); |
316 return fieldGet; | 315 return fieldGet; |
317 } else if (isBoxed(element)) { | 316 } else if (isBoxed(element)) { |
318 Element redirect = redirectionMapping[element]; | 317 Element redirect = redirectionMapping[element]; |
319 // In the function that declares the captured variable the box is | 318 // In the function that declares the captured variable the box is |
320 // accessed as direct local. Inside the nested closure the box is | 319 // accessed as direct local. Inside the nested closure the box is |
321 // accessed through a closure-field. | 320 // accessed through a closure-field. |
322 // Calling [readLocal] makes sure we generate the correct code to get | 321 // Calling [readLocal] makes sure we generate the correct code to get |
323 // the box. | 322 // the box. |
324 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 323 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
325 HInstruction box = readLocal(redirect.enclosingElement); | 324 HInstruction box = readLocal(redirect.enclosingElement); |
326 HInstruction lookup = new HFieldGet(redirect, box); | 325 HInstruction lookup = new HFieldGet(redirect, box); |
327 builder.add(lookup); | 326 builder.add(lookup); |
328 return lookup; | 327 return lookup; |
329 } else { | 328 } else { |
330 assert(isUsedInTry(element)); | 329 assert(isUsedInTry(element)); |
331 HInstruction variable = new HFieldGet.fromActivation(element); | 330 HInstruction variable = new HFieldGet.fromActivation(element); |
332 builder.add(variable); | 331 builder.add(variable); |
333 return variable; | 332 return variable; |
334 } | 333 } |
335 } | 334 } |
336 | 335 |
| 336 HInstruction readThis() { |
| 337 return readLocal(closureData.thisElement); |
| 338 } |
| 339 |
337 /** | 340 /** |
338 * Sets the [element] to [value]. If the element is boxed or stored in a | 341 * Sets the [element] to [value]. If the element is boxed or stored in a |
339 * closure then the method generates code to set the value. | 342 * closure then the method generates code to set the value. |
340 */ | 343 */ |
341 void updateLocal(Element element, HInstruction value) { | 344 void updateLocal(Element element, HInstruction value) { |
342 // TODO(floitsch): replace the following if with an assert. | |
343 if (element is !VariableElement) { | |
344 builder.compiler.internalError("expected a variable", | |
345 node: element.parseNode(builder.compiler)); | |
346 } | |
347 | |
348 if (isAccessedDirectly(element)) { | 345 if (isAccessedDirectly(element)) { |
349 directLocals[element] = value; | 346 directLocals[element] = value; |
350 } else if (isStoredInClosureField(element)) { | 347 } else if (isStoredInClosureField(element)) { |
351 Element redirect = redirectionMapping[element]; | 348 Element redirect = redirectionMapping[element]; |
352 // We must not use the [LocalsHandler.thisDefinition] since that could | 349 // We must not use the [LocalsHandler.readThis()] since that could |
353 // point to a captured this which would be stored in a closure-field | 350 // point to a captured this which would be stored in a closure-field |
354 // itself. | 351 // itself. |
355 HInstruction receiver = new HThis(); | 352 HInstruction receiver = new HThis(); |
356 builder.add(receiver); | 353 builder.add(receiver); |
357 builder.add(new HFieldSet(redirect, receiver, value)); | 354 builder.add(new HFieldSet(redirect, receiver, value)); |
358 } else if (isBoxed(element)) { | 355 } else if (isBoxed(element)) { |
359 Element redirect = redirectionMapping[element]; | 356 Element redirect = redirectionMapping[element]; |
360 // The box itself could be captured, or be local. A local variable that | 357 // The box itself could be captured, or be local. A local variable that |
361 // is captured will be boxed, but the box itself will be a local. | 358 // is captured will be boxed, but the box itself will be a local. |
362 // Inside the closure the box is stored in a closure-field and cannot | 359 // Inside the closure the box is stored in a closure-field and cannot |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 assert(capturedLocal != null); | 761 assert(capturedLocal != null); |
765 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 762 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
766 } | 763 } |
767 } | 764 } |
768 | 765 |
769 push(new HForeignNew(globalizedClosureElement, capturedVariables)); | 766 push(new HForeignNew(globalizedClosureElement, capturedVariables)); |
770 } | 767 } |
771 | 768 |
772 visitIdentifier(Identifier node) { | 769 visitIdentifier(Identifier node) { |
773 if (node.isThis()) { | 770 if (node.isThis()) { |
774 if (localsHandler.thisDefinition === null) { | 771 stack.add(localsHandler.readThis()); |
775 compiler.unimplemented("Ssa.visitIdentifier.", node: node); | |
776 } | |
777 stack.add(localsHandler.thisDefinition); | |
778 } else { | 772 } else { |
779 compiler.internalError("SsaBuilder.visitIdentifier on non-this", | 773 compiler.internalError("SsaBuilder.visitIdentifier on non-this", |
780 node: node); | 774 node: node); |
781 } | 775 } |
782 } | 776 } |
783 | 777 |
784 visitIf(If node) { | 778 visitIf(If node) { |
785 // Add the condition to the current block. | 779 // Add the condition to the current block. |
786 bool hasElse = node.hasElsePart; | 780 bool hasElse = node.hasElsePart; |
787 visit(node.condition); | 781 visit(node.condition); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 void generateGetter(Send send, Element element) { | 985 void generateGetter(Send send, Element element) { |
992 Selector selector = elements.getSelector(send); | 986 Selector selector = elements.getSelector(send); |
993 if (Elements.isStaticOrTopLevelField(element)) { | 987 if (Elements.isStaticOrTopLevelField(element)) { |
994 push(new HStatic(element)); | 988 push(new HStatic(element)); |
995 if (element.kind == ElementKind.GETTER) { | 989 if (element.kind == ElementKind.GETTER) { |
996 push(new HInvokeStatic(selector, <HInstruction>[pop()])); | 990 push(new HInvokeStatic(selector, <HInstruction>[pop()])); |
997 } | 991 } |
998 } else if (element === null || Elements.isInstanceField(element)) { | 992 } else if (element === null || Elements.isInstanceField(element)) { |
999 HInstruction receiver; | 993 HInstruction receiver; |
1000 if (send.receiver == null) { | 994 if (send.receiver == null) { |
1001 receiver = localsHandler.thisDefinition; | 995 receiver = localsHandler.readThis(); |
1002 if (receiver === null) { | |
1003 compiler.unimplemented("SsaBuilder.generateGetter.", node: send); | |
1004 } | |
1005 } else { | 996 } else { |
1006 visit(send.receiver); | 997 visit(send.receiver); |
1007 receiver = pop(); | 998 receiver = pop(); |
1008 } | 999 } |
1009 SourceString getterName = send.selector.asIdentifier().source; | 1000 SourceString getterName = send.selector.asIdentifier().source; |
1010 Element staticInterceptor = null; | 1001 Element staticInterceptor = null; |
1011 if (methodInterceptionEnabled) { | 1002 if (methodInterceptionEnabled) { |
1012 staticInterceptor = interceptors.getStaticGetInterceptor(getterName); | 1003 staticInterceptor = interceptors.getStaticGetInterceptor(getterName); |
1013 } | 1004 } |
1014 if (staticInterceptor != null) { | 1005 if (staticInterceptor != null) { |
(...skipping 19 matching lines...) Expand all Loading... |
1034 add(target); | 1025 add(target); |
1035 add(new HInvokeStatic(selector, <HInstruction>[target, value])); | 1026 add(new HInvokeStatic(selector, <HInstruction>[target, value])); |
1036 } else { | 1027 } else { |
1037 add(new HStaticStore(element, value)); | 1028 add(new HStaticStore(element, value)); |
1038 } | 1029 } |
1039 stack.add(value); | 1030 stack.add(value); |
1040 } else if (element === null || Elements.isInstanceField(element)) { | 1031 } else if (element === null || Elements.isInstanceField(element)) { |
1041 SourceString dartSetterName = send.selector.asIdentifier().source; | 1032 SourceString dartSetterName = send.selector.asIdentifier().source; |
1042 HInstruction receiver; | 1033 HInstruction receiver; |
1043 if (send.receiver == null) { | 1034 if (send.receiver == null) { |
1044 receiver = localsHandler.thisDefinition; | 1035 receiver = localsHandler.readThis(); |
1045 if (receiver === null) { | |
1046 compiler.unimplemented("Ssa.generateSetter.", node: send); | |
1047 } | |
1048 } else { | 1036 } else { |
1049 visit(send.receiver); | 1037 visit(send.receiver); |
1050 receiver = pop(); | 1038 receiver = pop(); |
1051 } | 1039 } |
1052 add(new HInvokeDynamicSetter( | 1040 add(new HInvokeDynamicSetter( |
1053 selector, null, dartSetterName, receiver, value)); | 1041 selector, null, dartSetterName, receiver, value)); |
1054 stack.add(value); | 1042 stack.add(value); |
1055 } else { | 1043 } else { |
1056 localsHandler.updateLocal(element, value); | 1044 localsHandler.updateLocal(element, value); |
1057 stack.add(value); | 1045 stack.add(value); |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1229 add(target); | 1217 add(target); |
1230 inputs.add(target); | 1218 inputs.add(target); |
1231 visit(node.receiver); | 1219 visit(node.receiver); |
1232 inputs.add(pop()); | 1220 inputs.add(pop()); |
1233 addGenericSendArgumentsToList(node.arguments, inputs); | 1221 addGenericSendArgumentsToList(node.arguments, inputs); |
1234 push(new HInvokeInterceptor(selector, dartMethodName, false, inputs)); | 1222 push(new HInvokeInterceptor(selector, dartMethodName, false, inputs)); |
1235 return; | 1223 return; |
1236 } | 1224 } |
1237 | 1225 |
1238 if (node.receiver === null) { | 1226 if (node.receiver === null) { |
1239 HThis receiver = localsHandler.thisDefinition; | 1227 HThis receiver = localsHandler.readThis(); |
1240 if (receiver === null) { | |
1241 compiler.unimplemented("Ssa.visitDynamicSend.", node: node); | |
1242 } | |
1243 inputs.add(receiver); | 1228 inputs.add(receiver); |
1244 } else { | 1229 } else { |
1245 visit(node.receiver); | 1230 visit(node.receiver); |
1246 inputs.add(pop()); | 1231 inputs.add(pop()); |
1247 } | 1232 } |
1248 | 1233 |
1249 addDynamicSendArgumentsToList(node, inputs); | 1234 addDynamicSendArgumentsToList(node, inputs); |
1250 | 1235 |
1251 // The first entry in the inputs list is the receiver. | 1236 // The first entry in the inputs list is the receiver. |
1252 push(new HInvokeDynamicMethod(selector, dartMethodName, inputs)); | 1237 push(new HInvokeDynamicMethod(selector, dartMethodName, inputs)); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1317 break; | 1302 break; |
1318 default: | 1303 default: |
1319 throw "Unknown foreign: ${node.selector}"; | 1304 throw "Unknown foreign: ${node.selector}"; |
1320 } | 1305 } |
1321 } | 1306 } |
1322 | 1307 |
1323 visitSuperSend(Send node) { | 1308 visitSuperSend(Send node) { |
1324 Selector selector = elements.getSelector(node); | 1309 Selector selector = elements.getSelector(node); |
1325 Element element = elements[node]; | 1310 Element element = elements[node]; |
1326 HStatic target = new HStatic(element); | 1311 HStatic target = new HStatic(element); |
1327 HThis context = localsHandler.thisDefinition; | 1312 HThis context = localsHandler.readThis(); |
1328 if (context === null) { | |
1329 compiler.unimplemented("Ssa.visitSuperSend without thisDefinition.", | |
1330 node: node); | |
1331 } | |
1332 add(target); | 1313 add(target); |
1333 var inputs = <HInstruction>[target, context]; | 1314 var inputs = <HInstruction>[target, context]; |
1334 addStaticSendArgumentsToList(node, element, inputs); | 1315 addStaticSendArgumentsToList(node, element, inputs); |
1335 push(new HInvokeSuper(selector, inputs)); | 1316 push(new HInvokeSuper(selector, inputs)); |
1336 } | 1317 } |
1337 | 1318 |
1338 visitStaticSend(Send node) { | 1319 visitStaticSend(Send node) { |
1339 Selector selector = elements.getSelector(node); | 1320 Selector selector = elements.getSelector(node); |
1340 Element element = elements[node]; | 1321 Element element = elements[node]; |
1341 HStatic target = new HStatic(element); | 1322 HStatic target = new HStatic(element); |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1773 if (exception.type != null) { | 1754 if (exception.type != null) { |
1774 compiler.unimplemented('SsaBuilder catch with type', node: node); | 1755 compiler.unimplemented('SsaBuilder catch with type', node: node); |
1775 } | 1756 } |
1776 visit(node.block); | 1757 visit(node.block); |
1777 } | 1758 } |
1778 | 1759 |
1779 visitTypedef(Typedef node) { | 1760 visitTypedef(Typedef node) { |
1780 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 1761 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
1781 } | 1762 } |
1782 } | 1763 } |
OLD | NEW |