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

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

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

Powered by Google App Engine
This is Rietveld 408576698