Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(453)

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/unsugar.dart

Issue 1458703007: dart2js cps: Refactor CallExpressions into Primitives. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698