Chromium Code Reviews| 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 import '../../cps_ir/cps_fragment.dart'; |
| 12 import '../../common/names.dart'; | |
| 12 | 13 |
| 13 class ExplicitReceiverParameterEntity implements Local { | 14 class ExplicitReceiverParameterEntity implements Local { |
| 14 String get name => 'receiver'; | 15 String get name => 'receiver'; |
| 15 final ExecutableElement executableContext; | 16 final ExecutableElement executableContext; |
| 16 ExplicitReceiverParameterEntity(this.executableContext); | 17 ExplicitReceiverParameterEntity(this.executableContext); |
| 17 toString() => 'ExplicitReceiverParameterEntity($executableContext)'; | 18 toString() => 'ExplicitReceiverParameterEntity($executableContext)'; |
| 18 } | 19 } |
| 19 | 20 |
| 20 /// Suggested name for an interceptor. | 21 /// Suggested name for an interceptor. |
| 21 class InterceptorEntity extends Entity { | 22 class InterceptorEntity extends Entity { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 } | 89 } |
| 89 | 90 |
| 90 Constant get falseConstant { | 91 Constant get falseConstant { |
| 91 return new Constant(new FalseConstantValue()); | 92 return new Constant(new FalseConstantValue()); |
| 92 } | 93 } |
| 93 | 94 |
| 94 Constant get nullConstant { | 95 Constant get nullConstant { |
| 95 return new Constant(new NullConstantValue()); | 96 return new Constant(new NullConstantValue()); |
| 96 } | 97 } |
| 97 | 98 |
| 98 void insertLetPrim(Primitive primitive, Expression node) { | |
| 99 LetPrim let = new LetPrim(primitive); | |
| 100 let.insertAbove(node); | |
| 101 } | |
| 102 | |
| 103 void insertEqNullCheck(FunctionDefinition function) { | 99 void insertEqNullCheck(FunctionDefinition function) { |
| 104 // Replace | 100 // Replace |
| 105 // | 101 // |
| 106 // body; | 102 // body; |
| 107 // | 103 // |
| 108 // with | 104 // with |
| 109 // | 105 // |
| 110 // if (identical(arg, null)) | 106 // if (identical(arg, null)) |
| 111 // return false; | 107 // return false; |
| 112 // else | 108 // else |
| 113 // body; | 109 // body; |
| 114 // | 110 // |
| 115 CpsFragment cps = new CpsFragment(); | 111 CpsFragment cps = new CpsFragment(); |
| 116 Primitive isNull = cps.applyBuiltin( | 112 Primitive isNull = cps.applyBuiltin( |
| 117 BuiltinOperator.Identical, | 113 BuiltinOperator.Identical, |
| 118 <Primitive>[function.parameters.single, cps.makeNull()]); | 114 <Primitive>[function.parameters.single, cps.makeNull()]); |
| 119 CpsFragment trueBranch = cps.ifTruthy(isNull); | 115 CpsFragment trueBranch = cps.ifTruthy(isNull); |
| 120 trueBranch.invokeContinuation(function.returnContinuation, | 116 trueBranch.invokeContinuation(function.returnContinuation, |
| 121 <Primitive>[trueBranch.makeFalse()]); | 117 <Primitive>[trueBranch.makeFalse()]); |
| 122 cps.insertAbove(function.body); | 118 cps.insertAbove(function.body); |
| 123 } | 119 } |
| 124 | 120 |
| 125 /// Insert a static call to [function] at the point of [node] with result | 121 /// Insert a static call to [function] at above [node]. |
|
sra1
2015/11/19 21:41:46
at above -> immediately above.
asgerf
2015/11/20 16:23:54
Done.
| |
| 126 /// [result]. | 122 Primitive insertStaticCallAbove(FunctionElement function, |
| 127 /// | 123 List<Primitive> arguments, Expression node) { |
| 128 /// Rewrite [node] to | |
| 129 /// | |
| 130 /// let cont continuation(result) = node | |
| 131 /// in invoke function arguments continuation | |
| 132 void insertStaticCall(FunctionElement function, List<Primitive> arguments, | |
| 133 Parameter result, Expression node) { | |
| 134 InteriorNode parent = node.parent; | |
| 135 Continuation continuation = new Continuation([result]); | |
| 136 | |
| 137 Selector selector = new Selector.fromElement(function); | |
| 138 // TODO(johnniwinther): Come up with an implementation of SourceInformation | 124 // TODO(johnniwinther): Come up with an implementation of SourceInformation |
| 139 // for calls such as this one that don't appear in the original source. | 125 // for calls such as this one that don't appear in the original source. |
| 140 InvokeStatic invoke = new InvokeStatic( | 126 InvokeStatic invoke = new InvokeStatic( |
| 141 function, selector, arguments, continuation, null); | 127 function, new Selector.fromElement(function), arguments, null); |
| 142 | 128 new LetPrim(invoke).insertAbove(node); |
| 143 LetCont letCont = new LetCont(continuation, invoke); | 129 return invoke; |
| 144 | |
| 145 parent.body = letCont; | |
| 146 letCont.parent = parent; | |
| 147 continuation.body = node; | |
| 148 node.parent = continuation; | |
| 149 } | 130 } |
| 150 | 131 |
| 151 @override | 132 @override |
| 152 Expression traverseLetHandler(LetHandler node) { | 133 Expression traverseLetHandler(LetHandler node) { |
| 153 assert(node.handler.parameters.length == 2); | 134 assert(node.handler.parameters.length == 2); |
| 154 Parameter previousExceptionParameter = _exceptionParameter; | 135 Parameter previousExceptionParameter = _exceptionParameter; |
| 155 | 136 |
| 156 // BEFORE: Handlers have two parameters, exception and stack trace. | 137 // BEFORE: Handlers have two parameters, exception and stack trace. |
| 157 // AFTER: Handlers have a single parameter, which is unwrapped to get | 138 // AFTER: Handlers have a single parameter, which is unwrapped to get |
| 158 // the exception and stack trace. | 139 // the exception and stack trace. |
| 159 _exceptionParameter = node.handler.parameters.first; | 140 _exceptionParameter = node.handler.parameters.first; |
| 160 Parameter stackTraceParameter = node.handler.parameters.last; | 141 Parameter stackTraceParameter = node.handler.parameters.last; |
| 161 Expression body = node.handler.body; | 142 Expression body = node.handler.body; |
| 162 if (_exceptionParameter.hasAtLeastOneUse || | 143 if (_exceptionParameter.hasAtLeastOneUse || |
| 163 stackTraceParameter.hasAtLeastOneUse) { | 144 stackTraceParameter.hasAtLeastOneUse) { |
| 164 Parameter exceptionValue = new Parameter(null); | 145 InvokeStatic unwrapped = insertStaticCallAbove( |
| 165 exceptionValue.substituteFor(_exceptionParameter); | 146 _glue.getExceptionUnwrapper(), |
| 166 insertStaticCall(_glue.getExceptionUnwrapper(), [_exceptionParameter], | 147 [new Parameter(null)], // Dummy argument, see below. |
| 167 exceptionValue, body); | 148 body); |
| 149 unwrapped.substituteFor(_exceptionParameter); | |
| 150 | |
| 151 // Replace the dummy with the exception parameter. It must be set after | |
| 152 // substituting all uses of [_exceptionParameter]. | |
| 153 unwrapped.arguments[0].changeTo(_exceptionParameter); | |
| 168 | 154 |
| 169 if (stackTraceParameter.hasAtLeastOneUse) { | 155 if (stackTraceParameter.hasAtLeastOneUse) { |
| 170 Parameter stackTraceValue = new Parameter(null); | 156 InvokeStatic stackTraceValue = insertStaticCallAbove( |
| 157 _glue.getTraceFromException(), | |
| 158 [_exceptionParameter], | |
| 159 body); | |
| 171 stackTraceValue.substituteFor(stackTraceParameter); | 160 stackTraceValue.substituteFor(stackTraceParameter); |
| 172 insertStaticCall(_glue.getTraceFromException(), [_exceptionParameter], | |
| 173 stackTraceValue, body); | |
| 174 } | 161 } |
| 175 } | 162 } |
| 176 | 163 |
| 177 assert(stackTraceParameter.hasNoUses); | 164 assert(stackTraceParameter.hasNoUses); |
| 178 node.handler.parameters.removeLast(); | 165 node.handler.parameters.removeLast(); |
| 179 | 166 |
| 180 visit(node.handler); | 167 visit(node.handler); |
| 181 _exceptionParameter = previousExceptionParameter; | 168 _exceptionParameter = previousExceptionParameter; |
| 182 | 169 |
| 183 return node.body; | 170 return node.body; |
| 184 } | 171 } |
| 185 | 172 |
| 186 processThrow(Throw node) { | 173 processThrow(Throw node) { |
| 187 // The subexpression of throw is wrapped in the JavaScript output. | 174 // The subexpression of throw is wrapped in the JavaScript output. |
| 188 Parameter wrappedException = new Parameter(null); | 175 Primitive wrappedException = insertStaticCallAbove( |
| 189 insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition], | 176 _glue.getWrapExceptionHelper(), |
| 190 wrappedException, node); | 177 [node.value.definition], |
| 178 node); | |
| 191 node.value.changeTo(wrappedException); | 179 node.value.changeTo(wrappedException); |
| 192 } | 180 } |
| 193 | 181 |
| 194 processRethrow(Rethrow node) { | 182 processRethrow(Rethrow node) { |
| 195 // Rethrow can only appear in a catch block. It throws that block's | 183 // Rethrow can only appear in a catch block. It throws that block's |
| 196 // (wrapped) caught exception. | 184 // (wrapped) caught exception. |
| 197 Throw replacement = new Throw(_exceptionParameter); | 185 Throw replacement = new Throw(_exceptionParameter); |
| 198 InteriorNode parent = node.parent; | 186 InteriorNode parent = node.parent; |
| 199 parent.body = replacement; | 187 parent.body = replacement; |
| 200 replacement.parent = parent; | 188 replacement.parent = parent; |
| 201 // The original rethrow does not have any references that we need to | 189 // The original rethrow does not have any references that we need to |
| 202 // worry about unlinking. | 190 // worry about unlinking. |
| 203 } | 191 } |
| 204 | 192 |
| 205 // TODO(24523): Insert interceptor on demand when we discover we want to use | 193 // TODO(24523): Insert interceptor on demand when we discover we want to use |
| 206 // one rather than on every check. | 194 // one rather than on every check. |
| 207 processTypeTest(TypeTest node) { | 195 processTypeTest(TypeTest node) { |
| 208 assert(node.interceptor == null); | 196 assert(node.interceptor == null); |
| 209 Primitive receiver = node.value.definition; | 197 Primitive receiver = node.value.definition; |
| 210 Primitive interceptor = new Interceptor(receiver, node.sourceInformation) | 198 Primitive interceptor = new Interceptor(receiver, node.sourceInformation) |
| 211 ..interceptedClasses.addAll(_glue.interceptedClasses); | 199 ..interceptedClasses.addAll(_glue.interceptedClasses); |
| 212 insertLetPrim(interceptor, node.parent); | 200 new LetPrim(interceptor).insertAbove(node.parent); |
| 213 node.interceptor = new Reference<Primitive>(interceptor); | 201 node.interceptor = new Reference<Primitive>(interceptor); |
| 214 node.interceptor.parent = node; | 202 node.interceptor.parent = node; |
| 215 } | 203 } |
| 216 | 204 |
| 205 bool isNullConstant(Primitive prim) { | |
| 206 return prim is Constant && prim.value.isNull; | |
| 207 } | |
| 208 | |
| 217 processInvokeMethod(InvokeMethod node) { | 209 processInvokeMethod(InvokeMethod node) { |
| 218 Selector selector = node.selector; | 210 Selector selector = node.selector; |
| 219 if (!_glue.isInterceptedSelector(selector)) return; | 211 if (!_glue.isInterceptedSelector(selector)) return; |
| 220 | 212 |
| 213 // Some platform libraries will compare non-interceptable objects against | |
| 214 // null using the Dart == operator. These must be translated directly. | |
| 215 if (node.selector == Selectors.equals && | |
| 216 node.arguments.length == 1 && | |
| 217 isNullConstant(node.arguments[0].definition)) { | |
| 218 node.redefineAs(new ApplyBuiltinOperator( | |
| 219 BuiltinOperator.LooseEq, | |
| 220 [node.receiver.definition, node.arguments[0].definition], | |
| 221 node.sourceInformation)); | |
| 222 return; | |
| 223 } | |
| 224 | |
| 221 Primitive receiver = node.receiver.definition; | 225 Primitive receiver = node.receiver.definition; |
| 222 Primitive newReceiver; | 226 Primitive newReceiver; |
| 223 | 227 |
| 224 if (receiver == explicitReceiverParameter) { | 228 if (receiver == explicitReceiverParameter) { |
| 225 // If the receiver is the explicit receiver, we are calling a method in | 229 // If the receiver is the explicit receiver, we are calling a method in |
| 226 // the same interceptor: | 230 // the same interceptor: |
| 227 // Change 'receiver.foo()' to 'this.foo(receiver)'. | 231 // Change 'receiver.foo()' to 'this.foo(receiver)'. |
| 228 newReceiver = thisParameter; | 232 newReceiver = thisParameter; |
| 229 } else { | 233 } else { |
| 230 LetCont contBinding = node.parent; | |
| 231 newReceiver = new Interceptor(receiver, node.sourceInformation) | 234 newReceiver = new Interceptor(receiver, node.sourceInformation) |
| 232 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 235 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); |
| 233 if (receiver.hint != null) { | 236 if (receiver.hint != null) { |
| 234 newReceiver.hint = new InterceptorEntity(receiver.hint); | 237 newReceiver.hint = new InterceptorEntity(receiver.hint); |
| 235 } | 238 } |
| 236 insertLetPrim(newReceiver, contBinding); | 239 new LetPrim(newReceiver).insertAbove(node.parent); |
| 237 } | 240 } |
| 238 node.arguments.insert(0, node.receiver); | 241 node.arguments.insert(0, node.receiver); |
| 239 node.receiver = new Reference<Primitive>(newReceiver)..parent = node; | 242 node.receiver = new Reference<Primitive>(newReceiver)..parent = node; |
| 240 node.receiverIsIntercepted = true; | 243 node.callingConvention = CallingConvention.Intercepted; |
| 241 } | 244 } |
| 242 | 245 |
| 243 processInvokeMethodDirectly(InvokeMethodDirectly node) { | 246 processInvokeMethodDirectly(InvokeMethodDirectly node) { |
| 244 if (!_glue.isInterceptedMethod(node.target)) return; | 247 if (!_glue.isInterceptedMethod(node.target)) return; |
| 245 | 248 |
| 246 Selector selector = node.selector; | 249 Selector selector = node.selector; |
| 247 Primitive receiver = node.receiver.definition; | 250 Primitive receiver = node.receiver.definition; |
| 248 Primitive newReceiver; | 251 Primitive newReceiver; |
| 249 | 252 |
| 250 if (receiver == explicitReceiverParameter) { | 253 if (receiver == explicitReceiverParameter) { |
| 251 // If the receiver is the explicit receiver, we are calling a method in | 254 // If the receiver is the explicit receiver, we are calling a method in |
| 252 // the same interceptor: | 255 // the same interceptor: |
| 253 // Change 'receiver.foo()' to 'this.foo(receiver)'. | 256 // Change 'receiver.foo()' to 'this.foo(receiver)'. |
| 254 newReceiver = thisParameter; | 257 newReceiver = thisParameter; |
| 255 } else { | 258 } else { |
| 256 LetCont contBinding = node.parent; | |
| 257 newReceiver = new Interceptor(receiver, node.sourceInformation) | 259 newReceiver = new Interceptor(receiver, node.sourceInformation) |
| 258 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); | 260 ..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector)); |
| 259 if (receiver.hint != null) { | 261 if (receiver.hint != null) { |
| 260 newReceiver.hint = new InterceptorEntity(receiver.hint); | 262 newReceiver.hint = new InterceptorEntity(receiver.hint); |
| 261 } | 263 } |
| 262 insertLetPrim(newReceiver, contBinding); | 264 new LetPrim(newReceiver).insertAbove(node.parent); |
| 263 } | 265 } |
| 264 node.arguments.insert(0, node.receiver); | 266 node.arguments.insert(0, node.receiver); |
| 265 node.receiver = new Reference<Primitive>(newReceiver)..parent = node; | 267 node.receiver = new Reference<Primitive>(newReceiver)..parent = node; |
| 268 node.callingConvention = CallingConvention.Intercepted; | |
| 266 } | 269 } |
| 267 | 270 |
| 268 processInterceptor(Interceptor node) { | 271 processInterceptor(Interceptor node) { |
| 269 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); | 272 _glue.registerSpecializedGetInterceptor(node.interceptedClasses); |
| 270 } | 273 } |
| 271 } | 274 } |
| OLD | NEW |