| 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 |