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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 | 135 |
136 /** | 136 /** |
137 * Keeps track of locals (including parameters and phis) when building. The | 137 * Keeps track of locals (including parameters and phis) when building. The |
138 * 'this' reference is treated as parameter and hence handled by this class, | 138 * 'this' reference is treated as parameter and hence handled by this class, |
139 * too. | 139 * too. |
140 */ | 140 */ |
141 class LocalsHandler { | 141 class LocalsHandler { |
142 // The values of locals that can be directly accessed (without redirections | 142 // The values of locals that can be directly accessed (without redirections |
143 // to boxes or closure-fields). | 143 // to boxes or closure-fields). |
144 Map<Element, HInstruction> directLocals; | 144 Map<Element, HInstruction> directLocals; |
145 HInstruction thisDefinition; | |
146 Map<Element, Element> redirectionMapping; | 145 Map<Element, Element> redirectionMapping; |
147 SsaBuilder builder; | 146 SsaBuilder builder; |
148 ClosureData closureData; | 147 ClosureData closureData; |
149 | 148 |
150 LocalsHandler(this.builder) | 149 LocalsHandler(this.builder) |
151 : directLocals = new Map<Element, HInstruction>(), | 150 : directLocals = new Map<Element, HInstruction>(), |
152 redirectionMapping = new Map<Element, Element>(); | 151 redirectionMapping = new Map<Element, Element>(); |
153 | 152 |
154 /** | 153 /** |
155 * Creates a new [LocalsHandler] based on [other]. We only need to | 154 * Creates a new [LocalsHandler] based on [other]. We only need to |
156 * copy the [directLocals], since the other fields can be shared | 155 * copy the [directLocals], since the other fields can be shared |
157 * throughout the AST visit. | 156 * throughout the AST visit. |
158 */ | 157 */ |
159 LocalsHandler.from(LocalsHandler other) | 158 LocalsHandler.from(LocalsHandler other) |
160 : directLocals = new Map<Element, HInstruction>.from(other.directLocals), | 159 : directLocals = new Map<Element, HInstruction>.from(other.directLocals), |
161 redirectionMapping = other.redirectionMapping, | 160 redirectionMapping = other.redirectionMapping, |
162 builder = other.builder, | 161 builder = other.builder, |
163 thisDefinition = other.thisDefinition, | |
164 closureData = other.closureData; | 162 closureData = other.closureData; |
165 | 163 |
166 void startFunction(FunctionElement function, | 164 void startFunction(FunctionElement function, |
167 FunctionExpression node) { | 165 FunctionExpression node) { |
168 | 166 |
169 ClosureTranslator translator = | 167 ClosureTranslator translator = |
170 new ClosureTranslator(builder.compiler, builder.elements); | 168 new ClosureTranslator(builder.compiler, builder.elements); |
171 closureData = translator.translate(node); | 169 closureData = translator.translate(node); |
172 | 170 |
173 if (function.isInstanceMember()) { | 171 if (closureData.thisElement !== null && |
174 thisDefinition = new HThis(); | 172 isAccessedDirectly(closureData.thisElement)) { |
175 builder.add(thisDefinition); | 173 HInstruction thisInstruction = new HThis(); |
| 174 updateLocal(closureData.thisElement, thisInstruction); |
| 175 builder.add(thisInstruction); |
176 } | 176 } |
177 | 177 |
178 FunctionParameters params = function.computeParameters(builder.compiler); | 178 FunctionParameters params = function.computeParameters(builder.compiler); |
179 params.forEachParameter((Element element) { | 179 params.forEachParameter((Element element) { |
180 HParameterValue parameter = new HParameterValue(element); | 180 HParameterValue parameter = new HParameterValue(element); |
181 builder.add(parameter); | 181 builder.add(parameter); |
182 // Note that for constructors [element] could be a field-element which we | 182 // Note that for constructors [element] could be a field-element which we |
183 // treat as if it was a local. | 183 // treat as if it was a local. |
184 directLocals[element] = parameter; | 184 directLocals[element] = parameter; |
185 }); | 185 }); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 */ | 275 */ |
276 HInstruction readLocal(Element element) { | 276 HInstruction readLocal(Element element) { |
277 if (isAccessedDirectly(element)) { | 277 if (isAccessedDirectly(element)) { |
278 if (directLocals[element] == null) { | 278 if (directLocals[element] == null) { |
279 builder.compiler.internalError( | 279 builder.compiler.internalError( |
280 "Could not find value", node: element.parseNode(builder.compiler)); | 280 "Could not find value", node: element.parseNode(builder.compiler)); |
281 } | 281 } |
282 return directLocals[element]; | 282 return directLocals[element]; |
283 } else if (isStoredInClosureField(element)) { | 283 } else if (isStoredInClosureField(element)) { |
284 Element redirect = redirectionMapping[element]; | 284 Element redirect = redirectionMapping[element]; |
285 // We must not use the [LocalsHandler.thisDefinition] since that could | 285 // We must not use the [LocalsHandler.readThis()] since that could |
286 // point to a captured this which would be stored in a closure-field | 286 // point to a captured this which would be stored in a closure-field |
287 // itself. | 287 // itself. |
288 HInstruction receiver = new HThis(); | 288 HInstruction receiver = new HThis(); |
289 builder.add(receiver); | 289 builder.add(receiver); |
290 HInstruction fieldGet = new HFieldGet(redirect, receiver); | 290 HInstruction fieldGet = new HFieldGet(redirect, receiver); |
291 builder.add(fieldGet); | 291 builder.add(fieldGet); |
292 return fieldGet; | 292 return fieldGet; |
293 } else if (isBoxed(element)) { | 293 } else if (isBoxed(element)) { |
294 Element redirect = redirectionMapping[element]; | 294 Element redirect = redirectionMapping[element]; |
295 // In the function that declares the captured variable the box is | 295 // In the function that declares the captured variable the box is |
296 // accessed as direct local. Inside the nested closure the box is | 296 // accessed as direct local. Inside the nested closure the box is |
297 // accessed through a closure-field. | 297 // accessed through a closure-field. |
298 // Calling [readLocal] makes sure we generate the correct code to get | 298 // Calling [readLocal] makes sure we generate the correct code to get |
299 // the box. | 299 // the box. |
300 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 300 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
301 HInstruction box = readLocal(redirect.enclosingElement); | 301 HInstruction box = readLocal(redirect.enclosingElement); |
302 HInstruction lookup = new HFieldGet(redirect, box); | 302 HInstruction lookup = new HFieldGet(redirect, box); |
303 builder.add(lookup); | 303 builder.add(lookup); |
304 return lookup; | 304 return lookup; |
305 } else { | 305 } else { |
306 assert(isUsedInTry(element)); | 306 assert(isUsedInTry(element)); |
307 HInstruction variable = new HFieldGet.fromActivation(element); | 307 HInstruction variable = new HFieldGet.fromActivation(element); |
308 builder.add(variable); | 308 builder.add(variable); |
309 return variable; | 309 return variable; |
310 } | 310 } |
311 } | 311 } |
312 | 312 |
| 313 HInstruction readThis() { |
| 314 return readLocal(closureData.thisElement); |
| 315 } |
| 316 |
313 /** | 317 /** |
314 * Sets the [element] to [value]. If the element is boxed or stored in a | 318 * Sets the [element] to [value]. If the element is boxed or stored in a |
315 * closure then the method generates code to set the value. | 319 * closure then the method generates code to set the value. |
316 */ | 320 */ |
317 void updateLocal(Element element, HInstruction value) { | 321 void updateLocal(Element element, HInstruction value) { |
318 // TODO(floitsch): replace the following if with an assert. | |
319 if (element is !VariableElement) { | |
320 builder.compiler.internalError("expected a variable", | |
321 node: element.parseNode(builder.compiler)); | |
322 } | |
323 | |
324 if (isAccessedDirectly(element)) { | 322 if (isAccessedDirectly(element)) { |
325 directLocals[element] = value; | 323 directLocals[element] = value; |
326 } else if (isStoredInClosureField(element)) { | 324 } else if (isStoredInClosureField(element)) { |
327 Element redirect = redirectionMapping[element]; | 325 Element redirect = redirectionMapping[element]; |
328 // We must not use the [LocalsHandler.thisDefinition] since that could | 326 // We must not use the [LocalsHandler.readThis()] since that could |
329 // point to a captured this which would be stored in a closure-field | 327 // point to a captured this which would be stored in a closure-field |
330 // itself. | 328 // itself. |
331 HInstruction receiver = new HThis(); | 329 HInstruction receiver = new HThis(); |
332 builder.add(receiver); | 330 builder.add(receiver); |
333 builder.add(new HFieldSet(redirect, receiver, value)); | 331 builder.add(new HFieldSet(redirect, receiver, value)); |
334 } else if (isBoxed(element)) { | 332 } else if (isBoxed(element)) { |
335 Element redirect = redirectionMapping[element]; | 333 Element redirect = redirectionMapping[element]; |
336 // The box itself could be captured, or be local. A local variable that | 334 // The box itself could be captured, or be local. A local variable that |
337 // is captured will be boxed, but the box itself will be a local. | 335 // is captured will be boxed, but the box itself will be a local. |
338 // Inside the closure the box is stored in a closure-field and cannot | 336 // Inside the closure the box is stored in a closure-field and cannot |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 assert(capturedLocal != null); | 855 assert(capturedLocal != null); |
858 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 856 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
859 } | 857 } |
860 } | 858 } |
861 | 859 |
862 push(new HForeignNew(globalizedClosureElement, capturedVariables)); | 860 push(new HForeignNew(globalizedClosureElement, capturedVariables)); |
863 } | 861 } |
864 | 862 |
865 visitIdentifier(Identifier node) { | 863 visitIdentifier(Identifier node) { |
866 if (node.isThis()) { | 864 if (node.isThis()) { |
867 if (localsHandler.thisDefinition === null) { | 865 stack.add(localsHandler.readThis()); |
868 compiler.unimplemented("Ssa.visitIdentifier.", node: node); | |
869 } | |
870 stack.add(localsHandler.thisDefinition); | |
871 } else { | 866 } else { |
872 compiler.internalError("SsaBuilder.visitIdentifier on non-this", | 867 compiler.internalError("SsaBuilder.visitIdentifier on non-this", |
873 node: node); | 868 node: node); |
874 } | 869 } |
875 } | 870 } |
876 | 871 |
877 visitIf(If node) { | 872 visitIf(If node) { |
878 // Add the condition to the current block. | 873 // Add the condition to the current block. |
879 bool hasElse = node.hasElsePart; | 874 bool hasElse = node.hasElsePart; |
880 visit(node.condition); | 875 visit(node.condition); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 void generateGetter(Send send, Element element) { | 1079 void generateGetter(Send send, Element element) { |
1085 Selector selector = elements.getSelector(send); | 1080 Selector selector = elements.getSelector(send); |
1086 if (Elements.isStaticOrTopLevelField(element)) { | 1081 if (Elements.isStaticOrTopLevelField(element)) { |
1087 push(new HStatic(element)); | 1082 push(new HStatic(element)); |
1088 if (element.kind == ElementKind.GETTER) { | 1083 if (element.kind == ElementKind.GETTER) { |
1089 push(new HInvokeStatic(selector, <HInstruction>[pop()])); | 1084 push(new HInvokeStatic(selector, <HInstruction>[pop()])); |
1090 } | 1085 } |
1091 } else if (element === null || Elements.isInstanceField(element)) { | 1086 } else if (element === null || Elements.isInstanceField(element)) { |
1092 HInstruction receiver; | 1087 HInstruction receiver; |
1093 if (send.receiver == null) { | 1088 if (send.receiver == null) { |
1094 receiver = localsHandler.thisDefinition; | 1089 receiver = localsHandler.readThis(); |
1095 if (receiver === null) { | |
1096 compiler.unimplemented("SsaBuilder.generateGetter.", node: send); | |
1097 } | |
1098 } else { | 1090 } else { |
1099 visit(send.receiver); | 1091 visit(send.receiver); |
1100 receiver = pop(); | 1092 receiver = pop(); |
1101 } | 1093 } |
1102 SourceString getterName = send.selector.asIdentifier().source; | 1094 SourceString getterName = send.selector.asIdentifier().source; |
1103 Element staticInterceptor = null; | 1095 Element staticInterceptor = null; |
1104 if (methodInterceptionEnabled) { | 1096 if (methodInterceptionEnabled) { |
1105 staticInterceptor = interceptors.getStaticGetInterceptor(getterName); | 1097 staticInterceptor = interceptors.getStaticGetInterceptor(getterName); |
1106 } | 1098 } |
1107 if (staticInterceptor != null) { | 1099 if (staticInterceptor != null) { |
(...skipping 19 matching lines...) Expand all Loading... |
1127 add(target); | 1119 add(target); |
1128 add(new HInvokeStatic(selector, <HInstruction>[target, value])); | 1120 add(new HInvokeStatic(selector, <HInstruction>[target, value])); |
1129 } else { | 1121 } else { |
1130 add(new HStaticStore(element, value)); | 1122 add(new HStaticStore(element, value)); |
1131 } | 1123 } |
1132 stack.add(value); | 1124 stack.add(value); |
1133 } else if (element === null || Elements.isInstanceField(element)) { | 1125 } else if (element === null || Elements.isInstanceField(element)) { |
1134 SourceString dartSetterName = send.selector.asIdentifier().source; | 1126 SourceString dartSetterName = send.selector.asIdentifier().source; |
1135 HInstruction receiver; | 1127 HInstruction receiver; |
1136 if (send.receiver == null) { | 1128 if (send.receiver == null) { |
1137 receiver = localsHandler.thisDefinition; | 1129 receiver = localsHandler.readThis(); |
1138 if (receiver === null) { | |
1139 compiler.unimplemented("Ssa.generateSetter.", node: send); | |
1140 } | |
1141 } else { | 1130 } else { |
1142 visit(send.receiver); | 1131 visit(send.receiver); |
1143 receiver = pop(); | 1132 receiver = pop(); |
1144 } | 1133 } |
1145 add(new HInvokeDynamicSetter( | 1134 add(new HInvokeDynamicSetter( |
1146 selector, null, dartSetterName, receiver, value)); | 1135 selector, null, dartSetterName, receiver, value)); |
1147 stack.add(value); | 1136 stack.add(value); |
1148 } else { | 1137 } else { |
1149 localsHandler.updateLocal(element, value); | 1138 localsHandler.updateLocal(element, value); |
1150 stack.add(value); | 1139 stack.add(value); |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1322 add(target); | 1311 add(target); |
1323 inputs.add(target); | 1312 inputs.add(target); |
1324 visit(node.receiver); | 1313 visit(node.receiver); |
1325 inputs.add(pop()); | 1314 inputs.add(pop()); |
1326 addGenericSendArgumentsToList(node.arguments, inputs); | 1315 addGenericSendArgumentsToList(node.arguments, inputs); |
1327 push(new HInvokeInterceptor(selector, dartMethodName, false, inputs)); | 1316 push(new HInvokeInterceptor(selector, dartMethodName, false, inputs)); |
1328 return; | 1317 return; |
1329 } | 1318 } |
1330 | 1319 |
1331 if (node.receiver === null) { | 1320 if (node.receiver === null) { |
1332 HThis receiver = localsHandler.thisDefinition; | 1321 inputs.add(localsHandler.readThis()); |
1333 if (receiver === null) { | |
1334 compiler.unimplemented("Ssa.visitDynamicSend.", node: node); | |
1335 } | |
1336 inputs.add(receiver); | |
1337 } else { | 1322 } else { |
1338 visit(node.receiver); | 1323 visit(node.receiver); |
1339 inputs.add(pop()); | 1324 inputs.add(pop()); |
1340 } | 1325 } |
1341 | 1326 |
1342 addDynamicSendArgumentsToList(node, inputs); | 1327 addDynamicSendArgumentsToList(node, inputs); |
1343 | 1328 |
1344 // The first entry in the inputs list is the receiver. | 1329 // The first entry in the inputs list is the receiver. |
1345 push(new HInvokeDynamicMethod(selector, dartMethodName, inputs)); | 1330 push(new HInvokeDynamicMethod(selector, dartMethodName, inputs)); |
1346 | 1331 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1410 break; | 1395 break; |
1411 default: | 1396 default: |
1412 throw "Unknown foreign: ${node.selector}"; | 1397 throw "Unknown foreign: ${node.selector}"; |
1413 } | 1398 } |
1414 } | 1399 } |
1415 | 1400 |
1416 visitSuperSend(Send node) { | 1401 visitSuperSend(Send node) { |
1417 Selector selector = elements.getSelector(node); | 1402 Selector selector = elements.getSelector(node); |
1418 Element element = elements[node]; | 1403 Element element = elements[node]; |
1419 HStatic target = new HStatic(element); | 1404 HStatic target = new HStatic(element); |
1420 HThis context = localsHandler.thisDefinition; | 1405 HInstruction context = localsHandler.readThis(); |
1421 if (context === null) { | |
1422 compiler.unimplemented("Ssa.visitSuperSend without thisDefinition.", | |
1423 node: node); | |
1424 } | |
1425 add(target); | 1406 add(target); |
1426 var inputs = <HInstruction>[target, context]; | 1407 var inputs = <HInstruction>[target, context]; |
1427 addStaticSendArgumentsToList(node, element, inputs); | 1408 addStaticSendArgumentsToList(node, element, inputs); |
1428 push(new HInvokeSuper(selector, inputs)); | 1409 push(new HInvokeSuper(selector, inputs)); |
1429 } | 1410 } |
1430 | 1411 |
1431 visitStaticSend(Send node) { | 1412 visitStaticSend(Send node) { |
1432 Selector selector = elements.getSelector(node); | 1413 Selector selector = elements.getSelector(node); |
1433 Element element = elements[node]; | 1414 Element element = elements[node]; |
1434 HStatic target = new HStatic(element); | 1415 HStatic target = new HStatic(element); |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1868 if (exception.type != null) { | 1849 if (exception.type != null) { |
1869 compiler.unimplemented('SsaBuilder catch with type', node: node); | 1850 compiler.unimplemented('SsaBuilder catch with type', node: node); |
1870 } | 1851 } |
1871 visit(node.block); | 1852 visit(node.block); |
1872 } | 1853 } |
1873 | 1854 |
1874 visitTypedef(Typedef node) { | 1855 visitTypedef(Typedef node) { |
1875 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 1856 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
1876 } | 1857 } |
1877 } | 1858 } |
OLD | NEW |