| 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, Pass; | 5 import '../../cps_ir/optimizers.dart' show ParentVisitor, Pass; | 
| 6 import '../../constants/values.dart'; | 6 import '../../constants/values.dart'; | 
| 7 import '../../elements/elements.dart'; | 7 import '../../elements/elements.dart'; | 
| 8 import '../../js_backend/codegen/glue.dart'; | 8 import '../../js_backend/codegen/glue.dart'; | 
| 9 import '../../universe/selector.dart' show Selector; | 9 import '../../universe/selector.dart' show Selector; | 
| 10 import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal; | 10 import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal; | 
|  | 11 import '../../cps_ir/cps_fragment.dart'; | 
| 11 | 12 | 
| 12 class ExplicitReceiverParameterEntity implements Local { | 13 class ExplicitReceiverParameterEntity implements Local { | 
| 13   String get name => 'receiver'; | 14   String get name => 'receiver'; | 
| 14   final ExecutableElement executableContext; | 15   final ExecutableElement executableContext; | 
| 15   ExplicitReceiverParameterEntity(this.executableContext); | 16   ExplicitReceiverParameterEntity(this.executableContext); | 
| 16   toString() => 'ExplicitReceiverParameterEntity($executableContext)'; | 17   toString() => 'ExplicitReceiverParameterEntity($executableContext)'; | 
| 17 } | 18 } | 
| 18 | 19 | 
| 19 /// Suggested name for an interceptor. | 20 /// Suggested name for an interceptor. | 
| 20 class InterceptorEntity extends Entity { | 21 class InterceptorEntity extends Entity { | 
| 21   Entity interceptedVariable; | 22   Entity interceptedVariable; | 
| 22 | 23 | 
| 23   InterceptorEntity(this.interceptedVariable); | 24   InterceptorEntity(this.interceptedVariable); | 
| 24 | 25 | 
| 25   String get name => interceptedVariable.name + '_'; | 26   String get name => interceptedVariable.name + '_'; | 
| 26 } | 27 } | 
| 27 | 28 | 
| 28 |  | 
| 29 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts | 29 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts | 
| 30 /// special nodes that respect JavaScript behavior. | 30 /// special nodes that respect JavaScript behavior. | 
| 31 /// | 31 /// | 
| 32 /// Performs the following rewrites: | 32 /// Performs the following rewrites: | 
| 33 ///  - Add interceptors at call sites that use interceptor calling convention. | 33 ///  - Add interceptors at call sites that use interceptor calling convention. | 
| 34 ///  - Add explicit receiver argument for methods that are called in interceptor | 34 ///  - Add explicit receiver argument for methods that are called in interceptor | 
| 35 ///    calling convention. | 35 ///    calling convention. | 
| 36 ///  - Convert two-parameter exception handlers to one-parameter ones. | 36 ///  - Convert two-parameter exception handlers to one-parameter ones. | 
| 37 class UnsugarVisitor extends RecursiveVisitor implements Pass { | 37 class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass { | 
| 38   Glue _glue; | 38   Glue _glue; | 
| 39   ParentVisitor _parentVisitor = new ParentVisitor(); |  | 
| 40 | 39 | 
| 41   Parameter thisParameter; | 40   Parameter thisParameter; | 
| 42   Parameter explicitReceiverParameter; | 41   Parameter explicitReceiverParameter; | 
| 43 | 42 | 
| 44   // In a catch block, rethrow implicitly throws the block's exception | 43   // In a catch block, rethrow implicitly throws the block's exception | 
| 45   // parameter.  This is the exception parameter when nested in a catch | 44   // parameter.  This is the exception parameter when nested in a catch | 
| 46   // block and null otherwise. | 45   // block and null otherwise. | 
| 47   Parameter _exceptionParameter = null; | 46   Parameter _exceptionParameter = null; | 
| 48 | 47 | 
| 49   UnsugarVisitor(this._glue); | 48   UnsugarVisitor(this._glue); | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 65         function.parameters.length == 1 && | 64         function.parameters.length == 1 && | 
| 66         !_glue.operatorEqHandlesNullArgument(function.element)) { | 65         !_glue.operatorEqHandlesNullArgument(function.element)) { | 
| 67       // Insert the null check that the language semantics requires us to | 66       // Insert the null check that the language semantics requires us to | 
| 68       // perform before calling operator ==. | 67       // perform before calling operator ==. | 
| 69       insertEqNullCheck(function); | 68       insertEqNullCheck(function); | 
| 70     } | 69     } | 
| 71 | 70 | 
| 72     if (inInterceptedMethod) { | 71     if (inInterceptedMethod) { | 
| 73       ThisParameterLocal holder = thisParameter.hint; | 72       ThisParameterLocal holder = thisParameter.hint; | 
| 74       explicitReceiverParameter = new Parameter( | 73       explicitReceiverParameter = new Parameter( | 
| 75           new ExplicitReceiverParameterEntity( | 74           new ExplicitReceiverParameterEntity(holder.executableContext)); | 
| 76               holder.executableContext)); | 75       explicitReceiverParameter.parent = function; | 
| 77       function.parameters.insert(0, explicitReceiverParameter); | 76       function.parameters.insert(0, explicitReceiverParameter); | 
| 78     } | 77     } | 
| 79 | 78 | 
| 80     // Set all parent pointers. |  | 
| 81     _parentVisitor.visit(function); |  | 
| 82 |  | 
| 83     if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) { | 79     if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) { | 
| 84       explicitReceiverParameter.substituteFor(thisParameter); | 80       explicitReceiverParameter.substituteFor(thisParameter); | 
| 85     } | 81     } | 
| 86 | 82 | 
| 87     visit(function); | 83     visit(function); | 
| 88   } | 84   } | 
| 89 | 85 | 
| 90   Constant get trueConstant { | 86   Constant get trueConstant { | 
| 91     return new Constant(new TrueConstantValue()); | 87     return new Constant(new TrueConstantValue()); | 
| 92   } | 88   } | 
| 93 | 89 | 
| 94   Constant get falseConstant { | 90   Constant get falseConstant { | 
| 95     return new Constant(new FalseConstantValue()); | 91     return new Constant(new FalseConstantValue()); | 
| 96   } | 92   } | 
| 97 | 93 | 
| 98   Constant get nullConstant { | 94   Constant get nullConstant { | 
| 99     return new Constant(new NullConstantValue()); | 95     return new Constant(new NullConstantValue()); | 
| 100   } | 96   } | 
| 101 | 97 | 
| 102   void insertLetPrim(Primitive primitive, Expression node) { | 98   void insertLetPrim(Primitive primitive, Expression node) { | 
| 103     LetPrim let = new LetPrim(primitive); | 99     LetPrim let = new LetPrim(primitive); | 
| 104     InteriorNode parent = node.parent; | 100     let.insertAbove(node); | 
| 105     parent.body = let; |  | 
| 106     let.body = node; |  | 
| 107     node.parent = let; |  | 
| 108     let.parent = parent; |  | 
| 109   } | 101   } | 
| 110 | 102 | 
| 111   void insertEqNullCheck(FunctionDefinition function) { | 103   void insertEqNullCheck(FunctionDefinition function) { | 
| 112     // Replace | 104     // Replace | 
| 113     // | 105     // | 
| 114     //     body; | 106     //     body; | 
| 115     // | 107     // | 
| 116     // with | 108     // with | 
| 117     // | 109     // | 
| 118     //     if (identical(arg, null)) | 110     //     if (identical(arg, null)) | 
| 119     //       return false; | 111     //       return false; | 
| 120     //     else | 112     //     else | 
| 121     //       body; | 113     //       body; | 
| 122     // | 114     // | 
| 123     Continuation originalBody = new Continuation(<Parameter>[]); | 115     CpsFragment cps = new CpsFragment(); | 
| 124     originalBody.body = function.body; | 116     Primitive isNull = cps.applyBuiltin( | 
| 125 |  | 
| 126     Continuation returnFalse = new Continuation(<Parameter>[]); |  | 
| 127     Primitive falsePrimitive = falseConstant; |  | 
| 128     returnFalse.body = |  | 
| 129         new LetPrim(falsePrimitive, |  | 
| 130             new InvokeContinuation( |  | 
| 131                 function.returnContinuation, <Primitive>[falsePrimitive])); |  | 
| 132 |  | 
| 133     Primitive nullPrimitive = nullConstant; |  | 
| 134     Primitive test = new ApplyBuiltinOperator( |  | 
| 135         BuiltinOperator.Identical, | 117         BuiltinOperator.Identical, | 
| 136           <Primitive>[function.parameters.single, nullPrimitive], | 118         <Primitive>[function.parameters.single, cps.makeNull()]); | 
| 137           function.parameters.single.sourceInformation); | 119     CpsFragment trueBranch = cps.ifTruthy(isNull); | 
| 138 | 120     trueBranch.invokeContinuation(function.returnContinuation, | 
| 139     Expression newBody = | 121         <Primitive>[trueBranch.makeFalse()]); | 
| 140         new LetCont.many(<Continuation>[returnFalse, originalBody], | 122     cps.insertAbove(function.body); | 
| 141             new LetPrim(nullPrimitive, |  | 
| 142                 new LetPrim(test, |  | 
| 143                     new Branch.loose(test, returnFalse, originalBody)))); |  | 
| 144     function.body = newBody; |  | 
| 145   } | 123   } | 
| 146 | 124 | 
| 147   /// Insert a static call to [function] at the point of [node] with result | 125   /// Insert a static call to [function] at the point of [node] with result | 
| 148   /// [result]. | 126   /// [result]. | 
| 149   /// | 127   /// | 
| 150   /// Rewrite [node] to | 128   /// Rewrite [node] to | 
| 151   /// | 129   /// | 
| 152   /// let cont continuation(result) = node | 130   /// let cont continuation(result) = node | 
| 153   /// in invoke function arguments continuation | 131   /// in invoke function arguments continuation | 
| 154   void insertStaticCall(FunctionElement function, List<Primitive> arguments, | 132   void insertStaticCall(FunctionElement function, List<Primitive> arguments, | 
| 155       Parameter result, | 133       Parameter result, Expression node) { | 
| 156       Expression node) { |  | 
| 157     InteriorNode parent = node.parent; | 134     InteriorNode parent = node.parent; | 
| 158     Continuation continuation = new Continuation([result]); | 135     Continuation continuation = new Continuation([result]); | 
| 159     continuation.body = node; |  | 
| 160     _parentVisitor.processContinuation(continuation); |  | 
| 161 | 136 | 
| 162     Selector selector = new Selector.fromElement(function); | 137     Selector selector = new Selector.fromElement(function); | 
| 163     // TODO(johnniwinther): Come up with an implementation of SourceInformation | 138     // TODO(johnniwinther): Come up with an implementation of SourceInformation | 
| 164     // for calls such as this one that don't appear in the original source. | 139     // for calls such as this one that don't appear in the original source. | 
| 165     InvokeStatic invoke = new InvokeStatic( | 140     InvokeStatic invoke = new InvokeStatic( | 
| 166         function, selector, arguments, continuation, null); | 141         function, selector, arguments, continuation, null); | 
| 167     _parentVisitor.processInvokeStatic(invoke); |  | 
| 168 | 142 | 
| 169     LetCont letCont = new LetCont(continuation, invoke); | 143     LetCont letCont = new LetCont(continuation, invoke); | 
| 170     _parentVisitor.processLetCont(letCont); |  | 
| 171 | 144 | 
| 172     parent.body = letCont; | 145     parent.body = letCont; | 
| 173     letCont.parent = parent; | 146     letCont.parent = parent; | 
|  | 147     continuation.body = node; | 
|  | 148     node.parent = continuation; | 
| 174   } | 149   } | 
| 175 | 150 | 
| 176   @override | 151   @override | 
| 177   Expression traverseLetHandler(LetHandler node) { | 152   Expression traverseLetHandler(LetHandler node) { | 
| 178     assert(node.handler.parameters.length == 2); | 153     assert(node.handler.parameters.length == 2); | 
| 179     Parameter previousExceptionParameter = _exceptionParameter; | 154     Parameter previousExceptionParameter = _exceptionParameter; | 
| 180 | 155 | 
| 181     // BEFORE: Handlers have two parameters, exception and stack trace. | 156     // BEFORE: Handlers have two parameters, exception and stack trace. | 
| 182     // AFTER: Handlers have a single parameter, which is unwrapped to get | 157     // AFTER: Handlers have a single parameter, which is unwrapped to get | 
| 183     // the exception and stack trace. | 158     // the exception and stack trace. | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 203     node.handler.parameters.removeLast(); | 178     node.handler.parameters.removeLast(); | 
| 204 | 179 | 
| 205     visit(node.handler); | 180     visit(node.handler); | 
| 206     _exceptionParameter = previousExceptionParameter; | 181     _exceptionParameter = previousExceptionParameter; | 
| 207 | 182 | 
| 208     return node.body; | 183     return node.body; | 
| 209   } | 184   } | 
| 210 | 185 | 
| 211   processThrow(Throw node) { | 186   processThrow(Throw node) { | 
| 212     // The subexpression of throw is wrapped in the JavaScript output. | 187     // The subexpression of throw is wrapped in the JavaScript output. | 
| 213     Parameter value = new Parameter(null); | 188     Parameter wrappedException = new Parameter(null); | 
| 214     insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition], | 189     insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition], | 
| 215         value, node); | 190         wrappedException, node); | 
| 216     node.value.unlink(); | 191     node.value.changeTo(wrappedException); | 
| 217     node.value = new Reference<Primitive>(value); |  | 
| 218   } | 192   } | 
| 219 | 193 | 
| 220   processRethrow(Rethrow node) { | 194   processRethrow(Rethrow node) { | 
| 221     // Rethrow can only appear in a catch block.  It throws that block's | 195     // Rethrow can only appear in a catch block.  It throws that block's | 
| 222     // (wrapped) caught exception. | 196     // (wrapped) caught exception. | 
| 223     Throw replacement = new Throw(_exceptionParameter); | 197     Throw replacement = new Throw(_exceptionParameter); | 
| 224     InteriorNode parent = node.parent; | 198     InteriorNode parent = node.parent; | 
| 225     parent.body = replacement; | 199     parent.body = replacement; | 
| 226     replacement.parent = parent; | 200     replacement.parent = parent; | 
| 227     // The original rethrow does not have any references that we need to | 201     // The original rethrow does not have any references that we need to | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
| 255     } else { | 229     } else { | 
| 256       LetCont contBinding = node.parent; | 230       LetCont contBinding = node.parent; | 
| 257       newReceiver = new Interceptor(receiver, node.sourceInformation) | 231       newReceiver = new Interceptor(receiver, node.sourceInformation) | 
| 258           ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 232           ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 
| 259       if (receiver.hint != null) { | 233       if (receiver.hint != null) { | 
| 260         newReceiver.hint = new InterceptorEntity(receiver.hint); | 234         newReceiver.hint = new InterceptorEntity(receiver.hint); | 
| 261       } | 235       } | 
| 262       insertLetPrim(newReceiver, contBinding); | 236       insertLetPrim(newReceiver, contBinding); | 
| 263     } | 237     } | 
| 264     node.arguments.insert(0, node.receiver); | 238     node.arguments.insert(0, node.receiver); | 
| 265     node.receiver = new Reference<Primitive>(newReceiver); | 239     node.receiver = new Reference<Primitive>(newReceiver)..parent = node; | 
| 266     node.receiverIsIntercepted = true; | 240     node.receiverIsIntercepted = true; | 
| 267   } | 241   } | 
| 268 | 242 | 
| 269   processInvokeMethodDirectly(InvokeMethodDirectly node) { | 243   processInvokeMethodDirectly(InvokeMethodDirectly node) { | 
| 270     if (!_glue.isInterceptedMethod(node.target)) return; | 244     if (!_glue.isInterceptedMethod(node.target)) return; | 
| 271 | 245 | 
| 272     Selector selector = node.selector; | 246     Selector selector = node.selector; | 
| 273     Primitive receiver = node.receiver.definition; | 247     Primitive receiver = node.receiver.definition; | 
| 274     Primitive newReceiver; | 248     Primitive newReceiver; | 
| 275 | 249 | 
| 276     if (receiver == explicitReceiverParameter) { | 250     if (receiver == explicitReceiverParameter) { | 
| 277       // If the receiver is the explicit receiver, we are calling a method in | 251       // If the receiver is the explicit receiver, we are calling a method in | 
| 278       // the same interceptor: | 252       // the same interceptor: | 
| 279       //  Change 'receiver.foo()'  to  'this.foo(receiver)'. | 253       //  Change 'receiver.foo()'  to  'this.foo(receiver)'. | 
| 280       newReceiver = thisParameter; | 254       newReceiver = thisParameter; | 
| 281     } else { | 255     } else { | 
| 282       LetCont contBinding = node.parent; | 256       LetCont contBinding = node.parent; | 
| 283       newReceiver = new Interceptor(receiver, node.sourceInformation) | 257       newReceiver = new Interceptor(receiver, node.sourceInformation) | 
| 284         ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 258         ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 
| 285       if (receiver.hint != null) { | 259       if (receiver.hint != null) { | 
| 286         newReceiver.hint = new InterceptorEntity(receiver.hint); | 260         newReceiver.hint = new InterceptorEntity(receiver.hint); | 
| 287       } | 261       } | 
| 288       insertLetPrim(newReceiver, contBinding); | 262       insertLetPrim(newReceiver, contBinding); | 
| 289     } | 263     } | 
| 290     node.arguments.insert(0, node.receiver); | 264     node.arguments.insert(0, node.receiver); | 
| 291     node.receiver = new Reference<Primitive>(newReceiver); | 265     node.receiver = new Reference<Primitive>(newReceiver)..parent = node; | 
| 292   } | 266   } | 
| 293 | 267 | 
| 294   processInterceptor(Interceptor node) { | 268   processInterceptor(Interceptor node) { | 
| 295     _glue.registerSpecializedGetInterceptor(node.interceptedClasses); | 269     _glue.registerSpecializedGetInterceptor(node.interceptedClasses); | 
| 296   } | 270   } | 
| 297 } | 271 } | 
| OLD | NEW | 
|---|