OLD | NEW |
1 library dart2js.unsugar_cps; | 1 library dart2js.unsugar_cps; |
2 | 2 |
3 import '../../cps_ir/cps_ir_nodes.dart'; | 3 import '../../cps_ir/cps_ir_nodes.dart'; |
4 | 4 |
5 import '../../cps_ir/optimizers.dart' show ParentVisitor; | 5 import '../../cps_ir/optimizers.dart' show ParentVisitor; |
6 import '../../constants/values.dart'; | 6 import '../../constants/values.dart'; |
7 import '../../elements/elements.dart'; | 7 import '../../elements/elements.dart'; |
8 import '../../io/source_information.dart'; | 8 import '../../io/source_information.dart'; |
9 import '../../js_backend/codegen/glue.dart'; | 9 import '../../js_backend/codegen/glue.dart'; |
10 import '../../universe/universe.dart' show Selector; | 10 import '../../universe/universe.dart' show Selector; |
(...skipping 25 matching lines...) Expand all Loading... |
36 /// - Add explicit receiver argument for methods that are called in interceptor | 36 /// - Add explicit receiver argument for methods that are called in interceptor |
37 /// calling convention. | 37 /// calling convention. |
38 /// - Convert two-parameter exception handlers to one-parameter ones. | 38 /// - Convert two-parameter exception handlers to one-parameter ones. |
39 class UnsugarVisitor extends RecursiveVisitor { | 39 class UnsugarVisitor extends RecursiveVisitor { |
40 Glue _glue; | 40 Glue _glue; |
41 ParentVisitor _parentVisitor = new ParentVisitor(); | 41 ParentVisitor _parentVisitor = new ParentVisitor(); |
42 | 42 |
43 Parameter thisParameter; | 43 Parameter thisParameter; |
44 Parameter explicitReceiverParameter; | 44 Parameter explicitReceiverParameter; |
45 | 45 |
46 Map<Primitive, Interceptor> interceptors = <Primitive, Interceptor>{}; | |
47 | |
48 // In a catch block, rethrow implicitly throws the block's exception | 46 // In a catch block, rethrow implicitly throws the block's exception |
49 // parameter. This is the exception parameter when nested in a catch | 47 // parameter. This is the exception parameter when nested in a catch |
50 // block and null otherwise. | 48 // block and null otherwise. |
51 Parameter _exceptionParameter = null; | 49 Parameter _exceptionParameter = null; |
52 | 50 |
53 UnsugarVisitor(this._glue); | 51 UnsugarVisitor(this._glue); |
54 | 52 |
55 bool methodUsesReceiverArgument(FunctionElement function) { | 53 bool methodUsesReceiverArgument(FunctionElement function) { |
56 assert(_glue.isInterceptedMethod(function)); | 54 assert(_glue.isInterceptedMethod(function)); |
57 ClassElement clazz = function.enclosingClass.declaration; | 55 ClassElement clazz = function.enclosingClass.declaration; |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 // Rethrow can only appear in a catch block. It throws that block's | 224 // Rethrow can only appear in a catch block. It throws that block's |
227 // (wrapped) caught exception. | 225 // (wrapped) caught exception. |
228 Throw replacement = new Throw(_exceptionParameter); | 226 Throw replacement = new Throw(_exceptionParameter); |
229 InteriorNode parent = node.parent; | 227 InteriorNode parent = node.parent; |
230 parent.body = replacement; | 228 parent.body = replacement; |
231 replacement.parent = parent; | 229 replacement.parent = parent; |
232 // The original rethrow does not have any references that we need to | 230 // The original rethrow does not have any references that we need to |
233 // worry about unlinking. | 231 // worry about unlinking. |
234 } | 232 } |
235 | 233 |
236 /// Returns an interceptor for the given value, capable of responding to | 234 processInvokeMethod(InvokeMethod node) { |
237 /// [selector]. | 235 Selector selector = node.selector; |
238 /// | 236 if (!_glue.isInterceptedSelector(selector)) return; |
239 /// A single getInterceptor call will be created per primitive, bound | 237 |
240 /// immediately after the primitive is bound. | 238 Primitive receiver = node.receiver.definition; |
241 /// | 239 Primitive newReceiver; |
242 /// The type propagation pass will later narrow the set of interceptors | 240 |
243 /// based on the input type, and the let sinking pass will propagate the | 241 if (receiver == explicitReceiverParameter) { |
244 /// getInterceptor call closer to its use when this is profitable. | |
245 Primitive getInterceptorFor(Primitive prim, Selector selector, | |
246 SourceInformation sourceInformation) { | |
247 if (prim == explicitReceiverParameter) { | |
248 // If the receiver is the explicit receiver, we are calling a method in | 242 // If the receiver is the explicit receiver, we are calling a method in |
249 // the same interceptor. | 243 // the same interceptor: |
250 return thisParameter; | 244 // Change 'receiver.foo()' to 'this.foo(receiver)'. |
| 245 newReceiver = thisParameter; |
| 246 } else { |
| 247 LetCont contBinding = node.parent; |
| 248 newReceiver = new Interceptor(receiver, node.sourceInformation) |
| 249 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); |
| 250 if (receiver.hint != null) { |
| 251 newReceiver.hint = new InterceptorEntity(receiver.hint); |
| 252 } |
| 253 insertLetPrim(newReceiver, contBinding); |
251 } | 254 } |
252 assert(prim is! Interceptor); | 255 node.arguments.insert(0, node.receiver); |
253 Interceptor interceptor = interceptors[prim]; | 256 node.receiver = new Reference<Primitive>(newReceiver); |
254 if (interceptor == null) { | |
255 interceptor = new Interceptor(prim, sourceInformation); | |
256 interceptors[prim] = interceptor; | |
257 InteriorNode parent = prim.parent; | |
258 insertLetPrim(interceptor, parent.body); | |
259 if (prim.hint != null) { | |
260 interceptor.hint = new InterceptorEntity(prim.hint); | |
261 } | |
262 } | |
263 // Add the interceptor classes that can respond to the given selector. | |
264 interceptor.interceptedClasses.addAll( | |
265 _glue.getInterceptedClassesOn(selector)); | |
266 return interceptor; | |
267 } | |
268 | |
269 processInvokeMethod(InvokeMethod node) { | |
270 if (_glue.isInterceptedSelector(node.selector)) { | |
271 // Rewrite `x.foo()` => `INTERCEPTOR.foo(x, ..)`. | |
272 Primitive receiver = node.receiver.definition; | |
273 Primitive newReceiver = | |
274 getInterceptorFor(receiver, node.selector, node.sourceInformation); | |
275 node.arguments.insert(0, node.receiver); | |
276 node.receiver = new Reference<Primitive>(newReceiver); | |
277 } | |
278 } | 257 } |
279 | 258 |
280 processInvokeMethodDirectly(InvokeMethodDirectly node) { | 259 processInvokeMethodDirectly(InvokeMethodDirectly node) { |
281 if (_glue.isInterceptedMethod(node.target)) { | 260 if (!_glue.isInterceptedMethod(node.target)) return; |
282 // Rewrite `x.foo()` => `INTERCEPTOR.foo(x, ..)`. | 261 |
283 Primitive receiver = node.receiver.definition; | 262 Selector selector = node.selector; |
284 Primitive newReceiver = | 263 Primitive receiver = node.receiver.definition; |
285 getInterceptorFor(receiver, node.selector, node.sourceInformation); | 264 Primitive newReceiver; |
286 node.arguments.insert(0, node.receiver); | 265 |
287 node.receiver = new Reference<Primitive>(newReceiver); | 266 if (receiver == explicitReceiverParameter) { |
| 267 // If the receiver is the explicit receiver, we are calling a method in |
| 268 // the same interceptor: |
| 269 // Change 'receiver.foo()' to 'this.foo(receiver)'. |
| 270 newReceiver = thisParameter; |
| 271 } else { |
| 272 LetCont contBinding = node.parent; |
| 273 newReceiver = new Interceptor(receiver, node.sourceInformation) |
| 274 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); |
| 275 if (receiver.hint != null) { |
| 276 newReceiver.hint = new InterceptorEntity(receiver.hint); |
| 277 } |
| 278 insertLetPrim(newReceiver, contBinding); |
288 } | 279 } |
| 280 node.arguments.insert(0, node.receiver); |
| 281 node.receiver = new Reference<Primitive>(newReceiver); |
289 } | 282 } |
290 | 283 |
291 processBranch(Branch node) { | 284 processBranch(Branch node) { |
292 // TODO(karlklose): implement the checked mode part of boolean conversion. | 285 // TODO(karlklose): implement the checked mode part of boolean conversion. |
293 InteriorNode parent = node.parent; | 286 InteriorNode parent = node.parent; |
294 IsTrue condition = node.condition; | 287 IsTrue condition = node.condition; |
295 | 288 |
296 // Do not rewrite conditions that are foreign code. | 289 // Do not rewrite conditions that are foreign code. |
297 // It is redundant, and causes infinite recursion (if not optimized) | 290 // It is redundant, and causes infinite recursion (if not optimized) |
298 // in the implementation of identical, which itself contains a condition. | 291 // in the implementation of identical, which itself contains a condition. |
(...skipping 21 matching lines...) Expand all Loading... |
320 condition.value.unlink(); | 313 condition.value.unlink(); |
321 node.trueContinuation.unlink(); | 314 node.trueContinuation.unlink(); |
322 node.falseContinuation.unlink(); | 315 node.falseContinuation.unlink(); |
323 parent.body = newNode; | 316 parent.body = newNode; |
324 } | 317 } |
325 | 318 |
326 processInterceptor(Interceptor node) { | 319 processInterceptor(Interceptor node) { |
327 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); | 320 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); |
328 } | 321 } |
329 } | 322 } |
OLD | NEW |