| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 | 45 |
| 46 Map<Primitive, Interceptor> interceptors = <Primitive, Interceptor>{}; | 46 Map<Primitive, Interceptor> interceptors = <Primitive, Interceptor>{}; |
| 47 | 47 |
| 48 // In a catch block, rethrow implicitly throws the block's exception | 48 // In a catch block, rethrow implicitly throws the block's exception |
| 49 // parameter. This is the exception parameter when nested in a catch | 49 // parameter. This is the exception parameter when nested in a catch |
| 50 // block and null otherwise. | 50 // block and null otherwise. |
| 51 Parameter _exceptionParameter = null; | 51 Parameter _exceptionParameter = null; |
| 52 | 52 |
| 53 UnsugarVisitor(this._glue); | 53 UnsugarVisitor(this._glue); |
| 54 | 54 |
| 55 bool methodUsesReceiverArgument(FunctionElement function) { |
| 56 assert(_glue.isInterceptedMethod(function)); |
| 57 ClassElement clazz = function.enclosingClass.declaration; |
| 58 return _glue.isInterceptorClass(clazz) || |
| 59 _glue.isUsedAsMixin(clazz); |
| 60 } |
| 61 |
| 55 void rewrite(FunctionDefinition function) { | 62 void rewrite(FunctionDefinition function) { |
| 63 thisParameter = function.thisParameter; |
| 56 bool inInterceptedMethod = _glue.isInterceptedMethod(function.element); | 64 bool inInterceptedMethod = _glue.isInterceptedMethod(function.element); |
| 57 | 65 |
| 58 if (function.element.name == '==' && | 66 if (function.element.name == '==' && |
| 59 function.parameters.length == 1 && | 67 function.parameters.length == 1 && |
| 60 !_glue.operatorEqHandlesNullArgument(function.element)) { | 68 !_glue.operatorEqHandlesNullArgument(function.element)) { |
| 61 // Insert the null check that the language semantics requires us to | 69 // Insert the null check that the language semantics requires us to |
| 62 // perform before calling operator ==. | 70 // perform before calling operator ==. |
| 63 insertEqNullCheck(function); | 71 insertEqNullCheck(function); |
| 64 } | 72 } |
| 65 | 73 |
| 66 if (inInterceptedMethod) { | 74 if (inInterceptedMethod) { |
| 67 thisParameter = function.thisParameter; | |
| 68 ThisParameterLocal holder = thisParameter.hint; | 75 ThisParameterLocal holder = thisParameter.hint; |
| 69 explicitReceiverParameter = new Parameter( | 76 explicitReceiverParameter = new Parameter( |
| 70 new ExplicitReceiverParameterEntity( | 77 new ExplicitReceiverParameterEntity( |
| 71 holder.executableContext)); | 78 holder.executableContext)); |
| 72 function.parameters.insert(0, explicitReceiverParameter); | 79 function.parameters.insert(0, explicitReceiverParameter); |
| 73 } | 80 } |
| 74 | 81 |
| 75 // Set all parent pointers. | 82 // Set all parent pointers. |
| 76 _parentVisitor.visit(function); | 83 _parentVisitor.visit(function); |
| 77 | 84 |
| 78 if (inInterceptedMethod) { | 85 if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) { |
| 79 explicitReceiverParameter.substituteFor(thisParameter); | 86 explicitReceiverParameter.substituteFor(thisParameter); |
| 80 } | 87 } |
| 81 | 88 |
| 82 visit(function); | 89 visit(function); |
| 83 } | 90 } |
| 84 | 91 |
| 85 Constant get trueConstant { | 92 Constant get trueConstant { |
| 86 return new Constant(new TrueConstantValue()); | 93 return new Constant(new TrueConstantValue()); |
| 87 } | 94 } |
| 88 | 95 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 | 235 |
| 229 /// Returns an interceptor for the given value, capable of responding to | 236 /// Returns an interceptor for the given value, capable of responding to |
| 230 /// [selector]. | 237 /// [selector]. |
| 231 /// | 238 /// |
| 232 /// A single getInterceptor call will be created per primitive, bound | 239 /// A single getInterceptor call will be created per primitive, bound |
| 233 /// immediately after the primitive is bound. | 240 /// immediately after the primitive is bound. |
| 234 /// | 241 /// |
| 235 /// The type propagation pass will later narrow the set of interceptors | 242 /// The type propagation pass will later narrow the set of interceptors |
| 236 /// based on the input type, and the let sinking pass will propagate the | 243 /// based on the input type, and the let sinking pass will propagate the |
| 237 /// getInterceptor call closer to its use when this is profitable. | 244 /// getInterceptor call closer to its use when this is profitable. |
| 238 Interceptor getInterceptorFor(Primitive prim, Selector selector, | 245 Primitive getInterceptorFor(Primitive prim, Selector selector, |
| 239 SourceInformation sourceInformation) { | 246 SourceInformation sourceInformation) { |
| 247 if (prim == explicitReceiverParameter) { |
| 248 // If the receiver is the explicit receiver, we are calling a method in |
| 249 // the same interceptor. |
| 250 return thisParameter; |
| 251 } |
| 240 assert(prim is! Interceptor); | 252 assert(prim is! Interceptor); |
| 241 Interceptor interceptor = interceptors[prim]; | 253 Interceptor interceptor = interceptors[prim]; |
| 242 if (interceptor == null) { | 254 if (interceptor == null) { |
| 243 interceptor = new Interceptor(prim, sourceInformation); | 255 interceptor = new Interceptor(prim, sourceInformation); |
| 244 interceptors[prim] = interceptor; | 256 interceptors[prim] = interceptor; |
| 245 InteriorNode parent = prim.parent; | 257 InteriorNode parent = prim.parent; |
| 246 insertLetPrim(interceptor, parent.body); | 258 insertLetPrim(interceptor, parent.body); |
| 247 if (prim.hint != null) { | 259 if (prim.hint != null) { |
| 248 interceptor.hint = new InterceptorEntity(prim.hint); | 260 interceptor.hint = new InterceptorEntity(prim.hint); |
| 249 } | 261 } |
| 250 } | 262 } |
| 251 // Add the interceptor classes that can respond to the given selector. | 263 // Add the interceptor classes that can respond to the given selector. |
| 252 interceptor.interceptedClasses.addAll( | 264 interceptor.interceptedClasses.addAll( |
| 253 _glue.getInterceptedClassesOn(selector)); | 265 _glue.getInterceptedClassesOn(selector)); |
| 254 return interceptor; | 266 return interceptor; |
| 255 } | 267 } |
| 256 | 268 |
| 257 processInvokeMethod(InvokeMethod node) { | 269 processInvokeMethod(InvokeMethod node) { |
| 258 Selector selector = node.selector; | 270 if (_glue.isInterceptedSelector(node.selector)) { |
| 259 if (!_glue.isInterceptedSelector(selector)) return; | 271 // Rewrite `x.foo()` => `INTERCEPTOR.foo(x, ..)`. |
| 260 | 272 Primitive receiver = node.receiver.definition; |
| 261 Primitive receiver = node.receiver.definition; | 273 Primitive newReceiver = |
| 262 Primitive newReceiver; | 274 getInterceptorFor(receiver, node.selector, node.sourceInformation); |
| 263 | 275 node.arguments.insert(0, node.receiver); |
| 264 if (receiver == explicitReceiverParameter) { | 276 node.receiver = new Reference<Primitive>(newReceiver); |
| 265 // If the receiver is the explicit receiver, we are calling a method in | |
| 266 // the same interceptor: | |
| 267 // Change 'receiver.foo()' to 'this.foo(receiver)'. | |
| 268 newReceiver = thisParameter; | |
| 269 } else { | |
| 270 newReceiver = getInterceptorFor( | |
| 271 receiver, node.selector, node.sourceInformation); | |
| 272 } | 277 } |
| 273 | |
| 274 node.arguments.insert(0, node.receiver); | |
| 275 node.receiver = new Reference<Primitive>(newReceiver); | |
| 276 } | 278 } |
| 277 | 279 |
| 278 processInvokeMethodDirectly(InvokeMethodDirectly node) { | 280 processInvokeMethodDirectly(InvokeMethodDirectly node) { |
| 279 if (_glue.isInterceptedMethod(node.target)) { | 281 if (_glue.isInterceptedMethod(node.target)) { |
| 280 Primitive nullPrim = nullConstant; | 282 // Rewrite `x.foo()` => `INTERCEPTOR.foo(x, ..)`. |
| 281 insertLetPrim(nullPrim, node); | 283 Primitive receiver = node.receiver.definition; |
| 284 Primitive newReceiver = |
| 285 getInterceptorFor(receiver, node.selector, node.sourceInformation); |
| 282 node.arguments.insert(0, node.receiver); | 286 node.arguments.insert(0, node.receiver); |
| 283 // TODO(sra): `null` is not adequate. Interceptors project the class | 287 node.receiver = new Reference<Primitive>(newReceiver); |
| 284 // hierarchy onto an interceptor hierarchy. A super call that does a | |
| 285 // method call will use the javascript 'this' parameter to avoid calling | |
| 286 // getInterceptor again, so the receiver must be the interceptor (likely | |
| 287 // `this`), not `null`. | |
| 288 node.receiver = new Reference<Primitive>(nullPrim); | |
| 289 } | 288 } |
| 290 } | 289 } |
| 291 | 290 |
| 292 processBranch(Branch node) { | 291 processBranch(Branch node) { |
| 293 // TODO(karlklose): implement the checked mode part of boolean conversion. | 292 // TODO(karlklose): implement the checked mode part of boolean conversion. |
| 294 InteriorNode parent = node.parent; | 293 InteriorNode parent = node.parent; |
| 295 IsTrue condition = node.condition; | 294 IsTrue condition = node.condition; |
| 296 | 295 |
| 297 // Do not rewrite conditions that are foreign code. | 296 // Do not rewrite conditions that are foreign code. |
| 298 // It is redundant, and causes infinite recursion (if not optimized) | 297 // It is redundant, and causes infinite recursion (if not optimized) |
| (...skipping 22 matching lines...) Expand all Loading... |
| 321 condition.value.unlink(); | 320 condition.value.unlink(); |
| 322 node.trueContinuation.unlink(); | 321 node.trueContinuation.unlink(); |
| 323 node.falseContinuation.unlink(); | 322 node.falseContinuation.unlink(); |
| 324 parent.body = newNode; | 323 parent.body = newNode; |
| 325 } | 324 } |
| 326 | 325 |
| 327 processInterceptor(Interceptor node) { | 326 processInterceptor(Interceptor node) { |
| 328 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); | 327 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); |
| 329 } | 328 } |
| 330 } | 329 } |
| OLD | NEW |