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

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

Issue 2246623002: Delete CPS IR (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 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
« no previous file with comments | « pkg/compiler/lib/src/js_backend/codegen/task.dart ('k') | pkg/compiler/lib/src/options.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 library dart2js.unsugar_cps;
2
3 import '../../common/names.dart';
4 import '../../constants/values.dart';
5 import '../../cps_ir/cps_fragment.dart';
6 import '../../cps_ir/cps_ir_nodes.dart';
7 import '../../cps_ir/optimizers.dart' show Pass;
8 import '../../elements/elements.dart';
9 import '../../js_backend/codegen/glue.dart';
10 import '../../universe/selector.dart' show Selector;
11
12 class ExplicitReceiverParameterEntity implements Local {
13 String get name => 'receiver';
14 final ExecutableElement executableContext;
15 ExplicitReceiverParameterEntity(this.executableContext);
16 toString() => 'ExplicitReceiverParameterEntity($executableContext)';
17 }
18
19 /// Suggested name for an interceptor.
20 class InterceptorEntity extends Entity {
21 Entity interceptedVariable;
22
23 InterceptorEntity(this.interceptedVariable);
24
25 String get name => interceptedVariable.name + '_';
26 }
27
28 /// Rewrites the initial CPS IR to make Dart semantics explicit and inserts
29 /// special nodes that respect JavaScript behavior.
30 ///
31 /// Performs the following rewrites:
32 /// - Add interceptors at call sites that use interceptor calling convention.
33 /// - Add explicit receiver argument for methods that are called in interceptor
34 /// calling convention.
35 /// - Convert two-parameter exception handlers to one-parameter ones.
36 class UnsugarVisitor extends TrampolineRecursiveVisitor implements Pass {
37 Glue _glue;
38
39 FunctionDefinition function;
40
41 Parameter get receiverParameter => function.receiverParameter;
42
43 /// The interceptor of the receiver. For some methods, this is the receiver
44 /// itself, for others, it is the interceptor parameter.
45 Parameter receiverInterceptor;
46
47 // In a catch block, rethrow implicitly throws the block's exception
48 // parameter. This is the exception parameter when nested in a catch
49 // block and null otherwise.
50 Parameter _exceptionParameter = null;
51
52 UnsugarVisitor(this._glue);
53
54 String get passName => 'Unsugaring';
55
56 void rewrite(FunctionDefinition function) {
57 this.function = function;
58 bool inInterceptedMethod = _glue.isInterceptedMethod(function.element);
59
60 if (function.element.name == '==' &&
61 function.parameters.length == 1 &&
62 !_glue.operatorEqHandlesNullArgument(function.element)) {
63 // Insert the null check that the language semantics requires us to
64 // perform before calling operator ==.
65 insertEqNullCheck(function);
66 }
67
68 if (inInterceptedMethod) {
69 function.interceptorParameter = new Parameter(null)..parent = function;
70 // Since the receiver won't be compiled to "this", set a hint on it
71 // so the parameter gets a meaningful name.
72 function.receiverParameter.hint =
73 new ExplicitReceiverParameterEntity(function.element);
74 // If we need an interceptor for the receiver, use the receiver itself
75 // if possible, otherwise the interceptor argument.
76 receiverInterceptor = _glue.methodUsesReceiverArgument(function.element)
77 ? function.interceptorParameter
78 : receiverParameter;
79 }
80
81 visit(function);
82 }
83
84 Constant get trueConstant {
85 return new Constant(new TrueConstantValue());
86 }
87
88 Constant get falseConstant {
89 return new Constant(new FalseConstantValue());
90 }
91
92 Constant get nullConstant {
93 return new Constant(new NullConstantValue());
94 }
95
96 void insertEqNullCheck(FunctionDefinition function) {
97 // Replace
98 //
99 // body;
100 //
101 // with
102 //
103 // if (identical(arg, null))
104 // return false;
105 // else
106 // body;
107 //
108 CpsFragment cps = new CpsFragment();
109 Primitive isNull = cps.applyBuiltin(BuiltinOperator.Identical,
110 <Primitive>[function.parameters.single, cps.makeNull()]);
111 CpsFragment trueBranch = cps.ifTruthy(isNull);
112 trueBranch.invokeContinuation(
113 function.returnContinuation, <Primitive>[trueBranch.makeFalse()]);
114 cps.insertAbove(function.body);
115 }
116
117 /// Insert a static call to [function] immediately above [node].
118 Primitive insertStaticCallAbove(
119 FunctionElement function, List<Primitive> arguments, Expression node) {
120 // TODO(johnniwinther): Come up with an implementation of SourceInformation
121 // for calls such as this one that don't appear in the original source.
122 InvokeStatic invoke = new InvokeStatic(
123 function, new Selector.fromElement(function), arguments, null);
124 new LetPrim(invoke).insertAbove(node);
125 return invoke;
126 }
127
128 @override
129 Expression traverseLetHandler(LetHandler node) {
130 assert(node.handler.parameters.length == 2);
131 Parameter previousExceptionParameter = _exceptionParameter;
132
133 // BEFORE: Handlers have two parameters, exception and stack trace.
134 // AFTER: Handlers have a single parameter, which is unwrapped to get
135 // the exception and stack trace.
136 _exceptionParameter = node.handler.parameters.first;
137 Parameter stackTraceParameter = node.handler.parameters.last;
138 Expression body = node.handler.body;
139 if (_exceptionParameter.hasAtLeastOneUse ||
140 stackTraceParameter.hasAtLeastOneUse) {
141 InvokeStatic unwrapped = insertStaticCallAbove(
142 _glue.getExceptionUnwrapper(),
143 [new Parameter(null)], // Dummy argument, see below.
144 body);
145 _exceptionParameter.replaceUsesWith(unwrapped);
146
147 // Replace the dummy with the exception parameter. It must be set after
148 // replacing all uses of [_exceptionParameter].
149 unwrapped.argumentRefs[0].changeTo(_exceptionParameter);
150
151 if (stackTraceParameter.hasAtLeastOneUse) {
152 InvokeStatic stackTraceValue = insertStaticCallAbove(
153 _glue.getTraceFromException(), [_exceptionParameter], body);
154 stackTraceParameter.replaceUsesWith(stackTraceValue);
155 }
156 }
157
158 assert(stackTraceParameter.hasNoUses);
159 node.handler.parameters.removeLast();
160
161 visit(node.handler);
162 _exceptionParameter = previousExceptionParameter;
163
164 return node.body;
165 }
166
167 processThrow(Throw node) {
168 // The subexpression of throw is wrapped in the JavaScript output.
169 Primitive wrappedException = insertStaticCallAbove(
170 _glue.getWrapExceptionHelper(), [node.value], node);
171 node.valueRef.changeTo(wrappedException);
172 }
173
174 processRethrow(Rethrow node) {
175 // Rethrow can only appear in a catch block. It throws that block's
176 // (wrapped) caught exception.
177 Throw replacement = new Throw(_exceptionParameter);
178 InteriorNode parent = node.parent;
179 parent.body = replacement;
180 replacement.parent = parent;
181 // The original rethrow does not have any references that we need to
182 // worry about unlinking.
183 }
184
185 bool isNullConstant(Primitive prim) {
186 return prim is Constant && prim.value.isNull;
187 }
188
189 processInvokeMethod(InvokeMethod node) {
190 Selector selector = node.selector;
191 if (!_glue.isInterceptedSelector(selector)) return;
192
193 // Some platform libraries will compare non-interceptable objects against
194 // null using the Dart == operator. These must be translated directly.
195 if (node.selector == Selectors.equals &&
196 node.argumentRefs.length == 1 &&
197 isNullConstant(node.argument(0))) {
198 node.replaceWith(new ApplyBuiltinOperator(BuiltinOperator.Identical,
199 [node.receiver, node.argument(0)], node.sourceInformation));
200 return;
201 }
202
203 Primitive receiver = node.receiver;
204 Primitive interceptor;
205
206 if (receiver == receiverParameter && receiverInterceptor != null) {
207 // TODO(asgerf): This could be done by GVN.
208 // If the receiver is 'this', we are calling a method in
209 // the same interceptor:
210 // Change 'receiver.foo()' to 'this.foo(receiver)'.
211 interceptor = receiverInterceptor;
212 } else {
213 interceptor = new Interceptor(receiver, node.sourceInformation);
214 if (receiver.hint != null) {
215 interceptor.hint = new InterceptorEntity(receiver.hint);
216 }
217 new LetPrim(interceptor).insertAbove(node.parent);
218 }
219 assert(node.interceptorRef == null);
220 node.makeIntercepted(interceptor);
221 }
222
223 processInvokeMethodDirectly(InvokeMethodDirectly node) {
224 if (!_glue.isInterceptedMethod(node.target)) return;
225
226 Primitive receiver = node.receiver;
227 Primitive interceptor;
228
229 if (receiver == receiverParameter && receiverInterceptor != null) {
230 // If the receiver is 'this', we are calling a method in
231 // the same interceptor:
232 // Change 'receiver.foo()' to 'this.foo(receiver)'.
233 interceptor = receiverInterceptor;
234 } else {
235 interceptor = new Interceptor(receiver, node.sourceInformation);
236 if (receiver.hint != null) {
237 interceptor.hint = new InterceptorEntity(receiver.hint);
238 }
239 new LetPrim(interceptor).insertAbove(node.parent);
240 }
241 assert(node.interceptorRef == null);
242 node.makeIntercepted(interceptor);
243 }
244 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/codegen/task.dart ('k') | pkg/compiler/lib/src/options.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698