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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_fragment.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
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library cps_ir.cps_fragment;
6
7 import '../constants/values.dart';
8 import '../elements/elements.dart';
9 import '../io/source_information.dart';
10 import '../types/types.dart' show TypeMask;
11 import '../universe/selector.dart' show Selector;
12 import 'cps_ir_nodes.dart';
13
14 /// Builds a CPS fragment that can be plugged into another CPS term.
15 ///
16 /// A CPS fragment contains a CPS term, possibly with a "hole" in it denoting
17 /// where to insert new IR nodes. We say a fragment is "open" if it has such
18 /// a hole. Otherwise, the fragment is "closed" and cannot be extended further.
19 ///
20 /// This class is designed for building non-trivial CPS terms in a readable and
21 /// non-error prone manner. It is not designed to manipulate existing IR nodes,
22 /// nor is it intended to shield the user from every complexity in the IR.
23 ///
24 /// EXAMPLES:
25 ///
26 /// Call `cont` with `obj.field + 1` as argument:
27 ///
28 /// CpsFragment cps = new CpsFragment();
29 /// var fieldValue = cps.letPrim(new GetField(obj, field));
30 /// var plusOne = cps.applyBuiltin(BuiltinOperator.NumAdd,
31 /// [fieldValue, cps.makeOne()]);
32 /// cps.invokeContinuation(cont, [plusOne]);
33 ///
34 /// If `condition` is true then invoke `cont1`, else `cont2`.
35 ///
36 /// cps.ifTruthy(condition).invokeContinuation(cont1, []);
37 /// cps.invokeContinuation(cont2, []);
38 ///
39 /// If `condition` is true then invoke `cont` with a bound primitive:
40 ///
41 /// CpsFragment branch = cps.ifTruthy(condition);
42 /// branch.invokeContinuation(cont, [branch.letPrim(arg)]);
43 ///
44 /// Loop and call a method until it returns false:
45 ///
46 /// Continuation loop = cps.beginLoop();
47 /// var result = cps.invokeMethod(receiver, selector, ...);
48 /// cps.ifFalsy(result).invokeContinuation(exit, []);
49 /// cps.continueLoop(loop);
50 ///
51 class CpsFragment {
52 /// The root of the IR built using this fragment.
53 Expression root;
54
55 /// Node whose body is the hole in this CPS fragment. May be null.
56 InteriorNode context;
57
58 /// Source information to attach to every IR node created in the fragment.
59 SourceInformation sourceInformation;
60
61 CpsFragment([this.sourceInformation, this.context]);
62
63 bool get isOpen => root == null || context != null;
64 bool get isClosed => !isOpen;
65 bool get isEmpty => root == null;
66
67 /// Asserts that the fragment is non-empty and closed and returns the IR that
68 /// was built.
69 Expression get result {
70 assert(!isEmpty);
71 assert(isClosed);
72 return root;
73 }
74
75 /// Put the given expression into the fragment's hole.
76 ///
77 /// Afterwards the fragment is closed and cannot be extended until a new
78 /// [context] is set.
79 void put(Expression node) {
80 assert(root == null || context != null); // We must put the node somewhere.
81 if (root == null) {
82 root = node;
83 }
84 if (context != null) {
85 context.body = node;
86 node.parent = context;
87 }
88 context = null;
89 }
90
91 /// Bind a primitive. Returns the same primitive for convenience.
92 Primitive letPrim(Primitive prim) {
93 assert(prim != null);
94 LetPrim let = new LetPrim(prim);
95 put(let);
96 context = let;
97 return prim;
98 }
99
100 /// Bind a constant value.
101 Primitive makeConstant(ConstantValue constant) {
102 return letPrim(new Constant(constant));
103 }
104
105 Primitive makeZero() => makeConstant(new IntConstantValue(0));
106 Primitive makeOne() => makeConstant(new IntConstantValue(1));
107 Primitive makeMinusOne() => makeConstant(new IntConstantValue(-1));
108 Primitive makeNull() => makeConstant(new NullConstantValue());
109 Primitive makeTrue() => makeConstant(new TrueConstantValue());
110 Primitive makeFalse() => makeConstant(new FalseConstantValue());
111
112 /// Invoke a built-in operator.
113 Primitive applyBuiltin(BuiltinOperator op, List<Primitive> args) {
114 return letPrim(new ApplyBuiltinOperator(op, args, sourceInformation));
115 }
116
117 Primitive refine(Primitive value, TypeMask type) {
118 return letPrim(new Refinement(value, type));
119 }
120
121 Primitive invokeBuiltin(
122 BuiltinMethod method, Primitive receiver, List<Primitive> arguments,
123 {bool receiverIsNotNull: false}) {
124 ApplyBuiltinMethod apply =
125 new ApplyBuiltinMethod(method, receiver, arguments, sourceInformation);
126 return letPrim(apply);
127 }
128
129 /// Inserts an invocation and returns a primitive holding the returned value.
130 Primitive invokeMethod(Primitive receiver, Selector selector, TypeMask mask,
131 List<Primitive> arguments,
132 {Primitive interceptor, CallingConvention callingConvention}) {
133 InvokeMethod invoke = new InvokeMethod(receiver, selector, mask, arguments,
134 sourceInformation: sourceInformation,
135 callingConvention: callingConvention,
136 interceptor: interceptor);
137 return letPrim(invoke);
138 }
139
140 /// Inserts an invocation and returns a primitive holding the returned value.
141 Primitive invokeStatic(FunctionElement target, List<Primitive> arguments) {
142 return letPrim(new InvokeStatic(target, new Selector.fromElement(target),
143 arguments, sourceInformation));
144 }
145
146 /// Inserts an invocation to a static function that throws an error.
147 ///
148 /// This closes the fragment; no more nodes may be added.
149 void invokeStaticThrower(FunctionElement target, List<Primitive> arguments) {
150 invokeStatic(target, arguments);
151 put(new Unreachable());
152 }
153
154 /// Invoke a non-recursive continuation.
155 ///
156 /// This closes the fragment; no more nodes may be inserted.
157 void invokeContinuation(Continuation cont, [List<Primitive> arguments]) {
158 if (arguments == null) arguments = <Primitive>[];
159 put(new InvokeContinuation(cont, arguments));
160 }
161
162 /// Build a loop with the given loop variables and initial values.
163 /// Call [continueLoop] with the returned continuation to iterate the loop.
164 ///
165 /// The loop body becomes the new hole.
166 Continuation beginLoop(
167 [List<Parameter> loopVars, List<Primitive> initialValues]) {
168 if (initialValues == null) {
169 assert(loopVars == null);
170 loopVars = <Parameter>[];
171 initialValues = <Primitive>[];
172 }
173 Continuation cont = new Continuation(loopVars);
174 put(new LetCont(cont, new InvokeContinuation(cont, initialValues)));
175 context = cont;
176 return cont;
177 }
178
179 /// Continue a loop started by [beginLoop].
180 ///
181 /// This closes the fragment; no more nodes may be inserted.
182 void continueLoop(Continuation cont, [List<Primitive> updatedLoopVariables]) {
183 put(new InvokeContinuation(cont, updatedLoopVariables, isRecursive: true));
184 }
185
186 /// Branch on [condition].
187 ///
188 /// Returns a new fragment for the 'then' branch, or the 'else' branch
189 /// if [negate] is true.
190 ///
191 /// The other branch becomes the new hole.
192 CpsFragment branch(Primitive condition,
193 {bool negate: false, bool strict: false}) {
194 Continuation trueCont = new Continuation(<Parameter>[]);
195 Continuation falseCont = new Continuation(<Parameter>[]);
196 put(new LetCont.two(
197 trueCont,
198 falseCont,
199 new Branch(condition, trueCont, falseCont, sourceInformation,
200 strict: strict)));
201 if (negate) {
202 context = trueCont;
203 return new CpsFragment(sourceInformation, falseCont);
204 } else {
205 context = falseCont;
206 return new CpsFragment(sourceInformation, trueCont);
207 }
208 }
209
210 /// Branch on [condition].
211 ///
212 /// Returns a new fragment for the 'then' branch.
213 ///
214 /// The 'else' branch becomes the new hole.
215 CpsFragment ifTruthy(Primitive condition) => branch(condition);
216
217 /// Branch on [condition].
218 ///
219 /// Returns a new fragment for the 'else' branch.
220 ///
221 /// The 'then' branch becomes the new hole.
222 CpsFragment ifFalsy(Primitive condition) => branch(condition, negate: true);
223
224 /// Create a new empty continuation and bind it here.
225 ///
226 /// Convenient for making a join point where multiple branches
227 /// meet later.
228 ///
229 /// The LetCont body becomes the new hole.
230 ///
231 /// Example use:
232 ///
233 /// Continuation fail = cps.letCont();
234 ///
235 /// // Fail if something
236 /// cps.ifTrue(<condition>)
237 /// ..invokeMethod(<method>)
238 /// ..invokeContinuation(fail);
239 ///
240 /// // Fail if something else
241 /// cps.ifTrue(<anotherCondition>)
242 /// ..invokeMethod(<anotherMethod>)
243 /// ..invokeContinuation(fail);
244 ///
245 /// // Build the fail branch
246 /// cps.insideContinuation(fail)
247 /// ..invokeStaticThrower(...);
248 ///
249 /// // Go to the happy branch
250 /// cps.invokeContinuation(cont..)
251 ///
252 Continuation letCont([List<Parameter> parameters]) {
253 if (parameters == null) parameters = <Parameter>[];
254 Continuation cont = new Continuation(parameters);
255 bindContinuation(cont);
256 return cont;
257 }
258
259 /// Binds an existing continuation at this position.
260 ///
261 /// The LetCont body becomes the new hole.
262 void bindContinuation(Continuation cont) {
263 LetCont let = new LetCont(cont, null);
264 put(let);
265 context = let;
266 }
267
268 /// Inlines [target] at the current position, substituting the provided
269 /// arguments.
270 ///
271 /// Returns a primitive containing the function's return value.
272 ///
273 /// The new hole is the point after [target] has returned. The fragment
274 /// remains open, even if [target] never returns.
275 ///
276 /// The [target] function is destroyed and should not be reused.
277 Primitive inlineFunction(
278 FunctionDefinition target, Primitive receiver, List<Primitive> arguments,
279 {Entity hint, Primitive interceptor}) {
280 if (interceptor != null) {
281 target.interceptorParameter.replaceUsesWith(interceptor);
282 }
283 if (receiver != null) {
284 target.receiverParameter.replaceUsesWith(receiver);
285 }
286 for (int i = 0; i < arguments.length; ++i) {
287 target.parameters[i].replaceUsesWith(arguments[i]);
288 }
289 Continuation returnCont = target.returnContinuation;
290 bindContinuation(returnCont);
291 put(target.body);
292 Parameter returnValue = returnCont.parameters.single;
293 returnValue.hint = hint;
294 context = returnCont;
295 return returnValue;
296 }
297
298 /// Returns a fragment whose context is the body of the given continuation.
299 ///
300 /// Does not change the state of this CPS fragment.
301 ///
302 /// Useful for building the body of a continuation created using [letCont].
303 CpsFragment insideContinuation(Continuation cont) {
304 return new CpsFragment(sourceInformation, cont);
305 }
306
307 /// Puts the given fragment into this one.
308 ///
309 /// If [other] was an open fragment, its hole becomes the new hole
310 /// in this fragment.
311 ///
312 /// [other] is reset to an empty fragment after this.
313 void append(CpsFragment other) {
314 if (other.root == null) return;
315 put(other.root);
316 context = other.context;
317 other.context = null;
318 other.root = null;
319 }
320
321 /// Reads the value of the given mutable variable.
322 Primitive getMutable(MutableVariable variable) {
323 return letPrim(new GetMutable(variable));
324 }
325
326 /// Sets the value of the given mutable variable.
327 void setMutable(MutableVariable variable, Primitive value) {
328 letPrim(new SetMutable(variable, value));
329 }
330
331 /// Declare a new mutable variable.
332 void letMutable(MutableVariable variable, Primitive initialValue) {
333 LetMutable let = new LetMutable(variable, initialValue);
334 put(let);
335 context = let;
336 }
337
338 void insertBelow(InteriorNode node) {
339 assert(isOpen);
340 if (isEmpty) return;
341 Expression child = node.body;
342 node.body = root;
343 root.parent = node;
344 context.body = child;
345 child.parent = context;
346 root = context = null;
347 }
348
349 void insertAbove(InteriorExpression node) {
350 insertBelow(node.parent);
351 }
352 }
353
354 /// Removes [node], unlinking all its references and replaces it with [newNode].
355 void destroyAndReplace(Expression node, Expression newNode) {
356 InteriorNode parent = node.parent;
357 RemovalVisitor.remove(node);
358 parent.body = newNode;
359 newNode.parent = parent;
360 }
361
362 /// Removes all [Refinement] uses of a given primitive that has no effective
363 /// uses.
364 void destroyRefinementsOfDeadPrimitive(Primitive prim) {
365 while (prim.firstRef != null) {
366 Refinement refine = prim.firstRef.parent;
367 destroyRefinementsOfDeadPrimitive(refine);
368 LetPrim letPrim = refine.parent;
369 InteriorNode parent = letPrim.parent;
370 parent.body = letPrim.body;
371 letPrim.body.parent = parent;
372 prim.firstRef.unlink();
373 }
374 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/builtin_operator.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698