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

Side by Side Diff: pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart

Issue 1251083002: dart2js cps: Avoid deep recursion using trampolines and basic blocks. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Change type propagation + minor fixes Created 5 years, 5 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 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library tree_ir_builder; 5 library tree_ir_builder;
6 6
7 import '../dart2jslib.dart' as dart2js; 7 import '../dart2jslib.dart' as dart2js;
8 import '../elements/elements.dart'; 8 import '../elements/elements.dart';
9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
10 import '../util/util.dart' show CURRENT_ELEMENT_SPANNABLE; 10 import '../util/util.dart' show CURRENT_ELEMENT_SPANNABLE;
11 import 'tree_ir_nodes.dart'; 11 import 'tree_ir_nodes.dart';
12 12
13 typedef Statement NodeCallback(Statement next);
14
13 /** 15 /**
14 * Builder translates from CPS-based IR to direct-style Tree. 16 * Builder translates from CPS-based IR to direct-style Tree.
15 * 17 *
16 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced 18 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced
17 * non-exit continuation `Cont(v, body)` is translated into a direct-style call 19 * non-exit continuation `Cont(v, body)` is translated into a direct-style call
18 * whose value is bound in the continuation body: 20 * whose value is bound in the continuation body:
19 * 21 *
20 * `LetVal(v, Invoke(fun, args), body)` 22 * `LetVal(v, Invoke(fun, args), body)`
21 * 23 *
22 * and the continuation definition is eliminated. A similar translation is 24 * and the continuation definition is eliminated. A similar translation is
(...skipping 12 matching lines...) Expand all
35 * `LetLabel(L, v, body)` 37 * `LetLabel(L, v, body)`
36 * 38 *
37 * Block arguments are later replaced with data flow during the Tree-to-Tree 39 * Block arguments are later replaced with data flow during the Tree-to-Tree
38 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree 40 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
39 * control-flow recognition. 41 * control-flow recognition.
40 * 42 *
41 * Otherwise, the output of Builder looks very much like the input. In 43 * Otherwise, the output of Builder looks very much like the input. In
42 * particular, intermediate values and blocks used for local control flow are 44 * particular, intermediate values and blocks used for local control flow are
43 * still all named. 45 * still all named.
44 */ 46 */
45 class Builder implements cps_ir.Visitor<Node> { 47 class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
46 final dart2js.InternalErrorFunction internalError; 48 final dart2js.InternalErrorFunction internalError;
47 49
48 final Map<cps_ir.Primitive, Variable> primitive2variable = 50 final Map<cps_ir.Primitive, Variable> primitive2variable =
49 <cps_ir.Primitive, Variable>{}; 51 <cps_ir.Primitive, Variable>{};
50 final Map<cps_ir.MutableVariable, Variable> mutable2variable = 52 final Map<cps_ir.MutableVariable, Variable> mutable2variable =
51 <cps_ir.MutableVariable, Variable>{}; 53 <cps_ir.MutableVariable, Variable>{};
52 54
53 // Continuations with more than one use are replaced with Tree labels. This 55 // Continuations with more than one use are replaced with Tree labels. This
54 // is the mapping from continuations to labels. 56 // is the mapping from continuations to labels.
55 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; 57 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 /// referred to by [reference]. 104 /// referred to by [reference].
103 /// This increments the reference count for the given variable, so the 105 /// This increments the reference count for the given variable, so the
104 /// returned expression must be used in the tree. 106 /// returned expression must be used in the tree.
105 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) { 107 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference) {
106 if (thisParameter != null && reference.definition == thisParameter) { 108 if (thisParameter != null && reference.definition == thisParameter) {
107 return new This(); 109 return new This();
108 } 110 }
109 return new VariableUse(getVariable(reference.definition)); 111 return new VariableUse(getVariable(reference.definition));
110 } 112 }
111 113
114 Label getLabel(cps_ir.Continuation cont) {
115 return labels.putIfAbsent(cont, () => new Label());
116 }
117
112 Variable addFunctionParameter(cps_ir.Definition variable) { 118 Variable addFunctionParameter(cps_ir.Definition variable) {
113 if (variable is cps_ir.Parameter) { 119 if (variable is cps_ir.Parameter) {
114 return getVariable(variable); 120 return getVariable(variable);
115 } else { 121 } else {
116 return addMutableVariable(variable as cps_ir.MutableVariable) 122 return addMutableVariable(variable as cps_ir.MutableVariable)
117 ..isCaptured = true; 123 ..isCaptured = true;
118 } 124 }
119 } 125 }
120 126
121 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { 127 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
122 currentElement = node.element; 128 currentElement = node.element;
123 if (parent != null) { 129 if (parent != null) {
124 // Local function's 'this' refers to enclosing method's 'this' 130 // Local function's 'this' refers to enclosing method's 'this'
125 thisParameter = parent.thisParameter; 131 thisParameter = parent.thisParameter;
126 } else { 132 } else {
127 thisParameter = node.thisParameter; 133 thisParameter = node.thisParameter;
128 } 134 }
129 List<Variable> parameters = 135 List<Variable> parameters =
130 node.parameters.map(addFunctionParameter).toList(); 136 node.parameters.map(addFunctionParameter).toList();
131 returnContinuation = node.returnContinuation; 137 returnContinuation = node.returnContinuation;
132 phiTempVar = new Variable(node.element, null); 138 phiTempVar = new Variable(node.element, null);
133 Statement body = visit(node.body); 139 Statement body = translateExpression(node.body);
134 return new FunctionDefinition(node.element, parameters, body); 140 return new FunctionDefinition(node.element, parameters, body);
135 } 141 }
136 142
137 /// Returns a list of variables corresponding to the arguments to a method 143 /// Returns a list of variables corresponding to the arguments to a method
138 /// call or similar construct. 144 /// call or similar construct.
139 /// 145 ///
140 /// The `readCount` for these variables will be incremented. 146 /// The `readCount` for these variables will be incremented.
141 /// 147 ///
142 /// The list will be typed as a list of [Expression] to allow inplace updates 148 /// The list will be typed as a list of [Expression] to allow inplace updates
143 /// on the list during the rewrite phases. 149 /// on the list during the rewrite phases.
144 List<Expression> translateArguments(List<cps_ir.Reference> args) { 150 List<Expression> translateArguments(List<cps_ir.Reference> args) {
145 return new List<Expression>.generate(args.length, 151 return new List<Expression>.generate(args.length,
146 (int index) => getVariableUse(args[index]), 152 (int index) => getVariableUse(args[index]),
147 growable: false); 153 growable: false);
148 } 154 }
149 155
150 Statement buildContinuationAssignment(
151 cps_ir.Parameter parameter,
152 Expression argument,
153 Statement buildRest()) {
154 Expression expr;
155 if (parameter.hasAtLeastOneUse) {
156 expr = new Assign(getVariable(parameter), argument);
157 } else {
158 expr = argument;
159 }
160 return new ExpressionStatement(expr, buildRest());
161 }
162
163 /// Simultaneously assigns each argument to the corresponding parameter, 156 /// Simultaneously assigns each argument to the corresponding parameter,
164 /// then continues at the statement created by [buildRest]. 157 /// then continues at the statement created by [buildRest].
165 Statement buildPhiAssignments( 158 Statement buildPhiAssignments(
166 List<cps_ir.Parameter> parameters, 159 List<cps_ir.Parameter> parameters,
167 List<Expression> arguments, 160 List<Expression> arguments,
168 Statement buildRest()) { 161 Statement buildRest()) {
169 assert(parameters.length == arguments.length); 162 assert(parameters.length == arguments.length);
170 // We want a parallel assignment to all parameters simultaneously. 163 // We want a parallel assignment to all parameters simultaneously.
171 // Since we do not have parallel assignments in dart_tree, we must linearize 164 // Since we do not have parallel assignments in dart_tree, we must linearize
172 // the assignments without attempting to read a previously-overwritten 165 // the assignments without attempting to read a previously-overwritten
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 } 238 }
246 239
247 if (first == null) { 240 if (first == null) {
248 first = buildRest(); 241 first = buildRest();
249 } else { 242 } else {
250 current.next = buildRest(); 243 current.next = buildRest();
251 } 244 }
252 return first; 245 return first;
253 } 246 }
254 247
255 visit(cps_ir.Node node) => node.accept(this); 248 visit(cps_ir.Node node) => throw 'Use translateXXX instead of visit';
256 249
257 unexpectedNode(cps_ir.Node node) { 250 /// Translates a CPS expression into a tree statement.
258 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); 251 ///
252 /// To avoid deep recursion, we traverse each basic blocks without
253 /// recursion.
254 ///
255 /// Non-tail expressions evaluate to a callback to be invoked once the
256 /// successor statement has been constructed. These callbacks are stored
257 /// in a stack until the block's tail expression has been translated.
258 Statement translateExpression(cps_ir.Expression node) {
259 List<NodeCallback> stack = <NodeCallback>[];
260 while (node is! cps_ir.TailExpression) {
261 stack.add(node.accept(this));
262 node = node.next;
263 }
264 Statement result = node.accept(this); // Translate the tail expression.
265 for (NodeCallback fun in stack.reversed) {
266 result = fun(result);
267 }
268 return result;
259 } 269 }
260 270
261 Expression visitSetField(cps_ir.SetField node) { 271 /// Translates a CPS primitive to a tree expression.
262 return new SetField(getVariableUse(node.object), 272 ///
263 node.field, 273 /// This simply calls the visit method for the primitive.
264 getVariableUse(node.value)); 274 Expression translatePrimitive(cps_ir.Primitive prim) {
265 } 275 return prim.accept(this);
266
267 Expression visitInterceptor(cps_ir.Interceptor node) {
268 return new Interceptor(getVariableUse(node.input), node.interceptedClasses);
269 } 276 }
270 277
271 Expression visitCreateInstance(cps_ir.CreateInstance node) { 278 /// Translates a condition to a tree expression.
272 return new CreateInstance( 279 Expression translateCondition(cps_ir.Condition condition) {
273 node.classElement, 280 cps_ir.IsTrue isTrue = condition;
274 translateArguments(node.arguments), 281 return getVariableUse(isTrue.value);
275 translateArguments(node.typeInformation),
276 node.sourceInformation);
277 } 282 }
278 283
279 Expression visitGetField(cps_ir.GetField node) { 284 /************************ INTERIOR EXPRESSIONS ************************/
280 return new GetField(getVariableUse(node.object), node.field, 285 //
281 objectIsNotNull: node.objectIsNotNull); 286 // Visit methods for interior expressions must return a function:
287 //
288 // (Statement next) => <result statement>
289 //
290
291 NodeCallback visitLetPrim(cps_ir.LetPrim node) => (Statement next) {
292 Variable variable = getVariable(node.primitive);
293 Expression value = translatePrimitive(node.primitive);
294 if (node.primitive.hasAtLeastOneUse) {
295 return Assign.makeStatement(variable, value, next);
296 } else {
297 return new ExpressionStatement(value, next);
298 }
299 };
300
301 // Continuations are bound at the same level, but they have to be
302 // translated as if nested. This is because the body can invoke any
303 // of them from anywhere, so it must be nested inside all of them.
304 //
305 // The continuation bodies are not always translated directly here because
306 // they may have been already translated:
307 // * For singly-used continuations, the continuation's body is
308 // translated at the site of the continuation invocation.
309 // * For recursive continuations, there is a single non-recursive
310 // invocation. The continuation's body is translated at the site
311 // of the non-recursive continuation invocation.
312 // See [visitInvokeContinuation] for the implementation.
313 NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) {
314 for (cps_ir.Continuation continuation in node.continuations) {
315 // This happens after the body of the LetCont has been translated.
316 // Labels are created on-demand if the continuation could not be inlined,
317 // so the existence of the label indicates if a labeled statement should
318 // be emitted.
319 Label label = labels[continuation];
320 if (label != null && !continuation.isRecursive) {
321 // Recursively build the body. We only do this for join continuations,
322 // so we should not risk overly deep recursion.
323 next = new LabeledStatement(
324 label,
325 next,
326 translateExpression(continuation.body));
327 }
328 }
329 return next;
330 };
331
332 NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) {
333 List<Variable> catchParameters =
334 node.handler.parameters.map(getVariable).toList();
335 Statement catchBody = translateExpression(node.handler.body);
336 return new Try(next, catchParameters, catchBody);
337 };
338
339 NodeCallback visitLetMutable(cps_ir.LetMutable node) {
340 Variable variable = addMutableVariable(node.variable);
341 Expression value = getVariableUse(node.value);
342 return (Statement next) => Assign.makeStatement(variable, value, next);
282 } 343 }
283 344
284 Expression visitCreateBox(cps_ir.CreateBox node) { 345
285 return new CreateBox(); 346 /************************ CALL EXPRESSIONS ************************/
347 //
348 // Visit methods for call expressions must return a function:
349 //
350 // (Statement next) => <result statement>
351 //
352 // The result statement must include an assignment to the continuation
353 // parameter, if the parameter is used.
354 //
355
356 NodeCallback makeCallExpression(cps_ir.CallExpression call,
357 Expression expression) {
358 return (Statement next) {
359 cps_ir.Parameter result = call.continuation.definition.parameters.single;
360 if (result.hasAtLeastOneUse) {
361 return Assign.makeStatement(getVariable(result), expression, next);
362 } else {
363 return new ExpressionStatement(expression, next);
364 }
365 };
286 } 366 }
287 367
288 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { 368 NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) {
289 return new CreateInvocationMirror(
290 node.selector,
291 translateArguments(node.arguments));
292 }
293
294 // Executable definitions are not visited directly. They have 'build'
295 // functions as entry points.
296 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
297 return unexpectedNode(node);
298 }
299
300 Statement visitLetPrim(cps_ir.LetPrim node) {
301 Variable variable = getVariable(node.primitive);
302 Expression value = visit(node.primitive);
303 if (node.primitive.hasAtLeastOneUse) {
304 return Assign.makeStatement(variable, value, visit(node.body));
305 } else {
306 return new ExpressionStatement(value, visit(node.body));
307 }
308 }
309
310 Statement visitLetCont(cps_ir.LetCont node) {
311 // Introduce labels for continuations that need them.
312 for (cps_ir.Continuation continuation in node.continuations) {
313 if (continuation.hasMultipleUses || continuation.isRecursive) {
314 labels[continuation] = new Label();
315 }
316 }
317 Statement body = visit(node.body);
318 // Continuations are bound at the same level, but they have to be
319 // translated as if nested. This is because the body can invoke any
320 // of them from anywhere, so it must be nested inside all of them.
321 //
322 // The continuation bodies are not always translated directly here because
323 // they may have been already translated:
324 // * For singly-used continuations, the continuation's body is
325 // translated at the site of the continuation invocation.
326 // * For recursive continuations, there is a single non-recursive
327 // invocation. The continuation's body is translated at the site
328 // of the non-recursive continuation invocation.
329 // See visitInvokeContinuation for the implementation.
330 Statement current = body;
331 for (cps_ir.Continuation continuation in node.continuations.reversed) {
332 Label label = labels[continuation];
333 if (label != null && !continuation.isRecursive) {
334 current =
335 new LabeledStatement(label, current, visit(continuation.body));
336 }
337 }
338 return current;
339 }
340
341 Statement visitLetHandler(cps_ir.LetHandler node) {
342 Statement tryBody = visit(node.body);
343 List<Variable> catchParameters =
344 node.handler.parameters.map(getVariable).toList();
345 Statement catchBody = visit(node.handler.body);
346 return new Try(tryBody, catchParameters, catchBody);
347 }
348
349 Statement visitInvokeStatic(cps_ir.InvokeStatic node) {
350 // Calls are translated to direct style.
351 List<Expression> arguments = translateArguments(node.arguments); 369 List<Expression> arguments = translateArguments(node.arguments);
352 Expression invoke = new InvokeStatic(node.target, node.selector, arguments, 370 Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
353 node.sourceInformation); 371 node.sourceInformation);
354 return continueWithExpression(node.continuation, invoke); 372 return makeCallExpression(node, invoke);
355 } 373 }
356 374
357 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { 375 NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) {
358 InvokeMethod invoke = new InvokeMethod( 376 InvokeMethod invoke = new InvokeMethod(
359 getVariableUse(node.receiver), 377 getVariableUse(node.receiver),
360 node.selector, 378 node.selector,
361 node.mask, 379 node.mask,
362 translateArguments(node.arguments), 380 translateArguments(node.arguments),
363 node.sourceInformation); 381 node.sourceInformation);
364 invoke.receiverIsNotNull = node.receiverIsNotNull; 382 invoke.receiverIsNotNull = node.receiverIsNotNull;
365 return continueWithExpression(node.continuation, invoke); 383 return makeCallExpression(node, invoke);
366 } 384 }
367 385
368 Statement visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { 386 NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
369 Expression receiver = getVariableUse(node.receiver); 387 Expression receiver = getVariableUse(node.receiver);
370 List<Expression> arguments = translateArguments(node.arguments); 388 List<Expression> arguments = translateArguments(node.arguments);
371 Expression invoke = new InvokeMethodDirectly(receiver, node.target, 389 Expression invoke = new InvokeMethodDirectly(receiver, node.target,
372 node.selector, arguments, node.sourceInformation); 390 node.selector, arguments, node.sourceInformation);
373 return continueWithExpression(node.continuation, invoke); 391 return makeCallExpression(node, invoke);
374 } 392 }
375 393
394 NodeCallback visitTypeCast(cps_ir.TypeCast node) {
395 Expression value = getVariableUse(node.value);
396 List<Expression> typeArgs = translateArguments(node.typeArguments);
397 Expression expression =
398 new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
399 return makeCallExpression(node, expression);
400 }
401
402 NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) {
403 List<Expression> arguments = translateArguments(node.arguments);
404 Expression invoke = new InvokeConstructor(
405 node.type,
406 node.target,
407 node.selector,
408 arguments,
409 node.sourceInformation);
410 return makeCallExpression(node, invoke);
411 }
412
413 NodeCallback visitForeignCode(cps_ir.ForeignCode node) {
414 if (node.codeTemplate.isExpression) {
415 Expression foreignCode = new ForeignExpression(
416 node.codeTemplate,
417 node.type,
418 node.arguments.map(getVariableUse).toList(growable: false),
419 node.nativeBehavior,
420 node.dependency);
421 return makeCallExpression(node, foreignCode);
422 } else {
423 return (Statement next) {
424 assert(next is Unreachable); // We are not using the `next` statement.
425 return new ForeignStatement(
426 node.codeTemplate,
427 node.type,
428 node.arguments.map(getVariableUse).toList(growable: false),
429 node.nativeBehavior,
430 node.dependency);
431 };
432 }
433 }
434
435 NodeCallback visitGetLazyStatic(cps_ir.GetLazyStatic node) {
436 // In the tree IR, GetStatic handles lazy fields because we do not need
437 // as fine-grained control over side effects.
438 GetStatic value = new GetStatic(node.element, node.sourceInformation);
439 return makeCallExpression(node, value);
440 }
441
442
443 /************************** TAIL EXPRESSIONS **************************/
444 //
445 // Visit methods for tail expressions must return a statement directly
446 // (not a function like interior and call expressions).
447
376 Statement visitThrow(cps_ir.Throw node) { 448 Statement visitThrow(cps_ir.Throw node) {
377 Expression value = getVariableUse(node.value); 449 Expression value = getVariableUse(node.value);
378 return new Throw(value); 450 return new Throw(value);
379 } 451 }
380 452
381 Statement visitRethrow(cps_ir.Rethrow node) { 453 Statement visitRethrow(cps_ir.Rethrow node) {
382 return new Rethrow(); 454 return new Rethrow();
383 } 455 }
384 456
385 Statement visitUnreachable(cps_ir.Unreachable node) { 457 Statement visitUnreachable(cps_ir.Unreachable node) {
386 return new Unreachable(); 458 return new Unreachable();
387 } 459 }
388 460
389 Statement continueWithExpression(cps_ir.Reference continuation,
390 Expression expression) {
391 cps_ir.Continuation cont = continuation.definition;
392 if (cont == returnContinuation) {
393 return new Return(expression);
394 } else {
395 assert(cont.parameters.length == 1);
396 Function nextBuilder = cont.hasExactlyOneUse ?
397 () => visit(cont.body) : () => new Break(labels[cont]);
398 return buildContinuationAssignment(cont.parameters.single, expression,
399 nextBuilder);
400 }
401 }
402
403 Statement visitLetMutable(cps_ir.LetMutable node) {
404 Variable variable = addMutableVariable(node.variable);
405 Expression value = getVariableUse(node.value);
406 Statement body = visit(node.body);
407 return Assign.makeStatement(variable, value, body);
408 }
409
410 Expression visitGetMutable(cps_ir.GetMutable node) {
411 return getMutableVariableUse(node.variable);
412 }
413
414 Expression visitSetMutable(cps_ir.SetMutable node) {
415 Variable variable = getMutableVariable(node.variable.definition);
416 Expression value = getVariableUse(node.value);
417 return new Assign(variable, value);
418 }
419
420 Statement visitTypeCast(cps_ir.TypeCast node) {
421 Expression value = getVariableUse(node.value);
422 List<Expression> typeArgs = translateArguments(node.typeArguments);
423 Expression expression =
424 new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
425 return continueWithExpression(node.continuation, expression);
426 }
427
428 Expression visitTypeTest(cps_ir.TypeTest node) {
429 Expression value = getVariableUse(node.value);
430 List<Expression> typeArgs = translateArguments(node.typeArguments);
431 return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
432 }
433
434 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) {
435 List<Expression> arguments = translateArguments(node.arguments);
436 Expression invoke = new InvokeConstructor(
437 node.type,
438 node.target,
439 node.selector,
440 arguments,
441 node.sourceInformation);
442 return continueWithExpression(node.continuation, invoke);
443 }
444
445 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) { 461 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) {
446 // Invocations of the return continuation are translated to returns. 462 // Invocations of the return continuation are translated to returns.
447 // Other continuation invocations are replaced with assignments of the 463 // Other continuation invocations are replaced with assignments of the
448 // arguments to formal parameter variables, followed by the body if 464 // arguments to formal parameter variables, followed by the body if
449 // the continuation is singly reference or a break if it is multiply 465 // the continuation is singly reference or a break if it is multiply
450 // referenced. 466 // referenced.
451 cps_ir.Continuation cont = node.continuation.definition; 467 cps_ir.Continuation cont = node.continuation.definition;
452 if (cont == returnContinuation) { 468 if (cont == returnContinuation) {
453 assert(node.arguments.length == 1); 469 assert(node.arguments.length == 1);
454 return new Return(getVariableUse(node.arguments.single), 470 return new Return(getVariableUse(node.arguments.single),
455 sourceInformation: node.sourceInformation); 471 sourceInformation: node.sourceInformation);
456 } else { 472 } else {
457 List<Expression> arguments = translateArguments(node.arguments); 473 List<Expression> arguments = translateArguments(node.arguments);
458 return buildPhiAssignments(cont.parameters, arguments, 474 return buildPhiAssignments(cont.parameters, arguments,
459 () { 475 () {
460 // Translate invocations of recursive and non-recursive 476 // Translate invocations of recursive and non-recursive
461 // continuations differently. 477 // continuations differently.
462 // * Non-recursive continuations 478 // * Non-recursive continuations
463 // - If there is one use, translate the continuation body 479 // - If there is one use, translate the continuation body
464 // inline at the invocation site. 480 // inline at the invocation site.
465 // - If there are multiple uses, translate to Break. 481 // - If there are multiple uses, translate to Break.
466 // * Recursive continuations 482 // * Recursive continuations
467 // - There is a single non-recursive invocation. Translate 483 // - There is a single non-recursive invocation. Translate
468 // the continuation body inline as a labeled loop at the 484 // the continuation body inline as a labeled loop at the
469 // invocation site. 485 // invocation site.
470 // - Translate the recursive invocations to Continue. 486 // - Translate the recursive invocations to Continue.
471 if (cont.isRecursive) { 487 if (cont.isRecursive) {
472 return node.isRecursive 488 return node.isRecursive
473 ? new Continue(labels[cont]) 489 ? new Continue(getLabel(cont))
474 : new WhileTrue(labels[cont], visit(cont.body)); 490 : new WhileTrue(getLabel(cont),
491 translateExpression(cont.body));
475 } else { 492 } else {
476 if (cont.hasExactlyOneUse) { 493 return cont.hasExactlyOneUse && !node.isEscapingTry
477 if (!node.isEscapingTry) { 494 ? translateExpression(cont.body)
478 return visit(cont.body); 495 : new Break(getLabel(cont));
479 }
480 labels[cont] = new Label();
481 }
482 return new Break(labels[cont]);
483 } 496 }
484 }); 497 });
485 } 498 }
486 } 499 }
487 500
488 Statement visitBranch(cps_ir.Branch node) { 501 Statement visitBranch(cps_ir.Branch node) {
489 Expression condition = visit(node.condition); 502 Expression condition = translateCondition(node.condition);
490 Statement thenStatement, elseStatement; 503 Statement thenStatement, elseStatement;
491 cps_ir.Continuation cont = node.trueContinuation.definition; 504 cps_ir.Continuation cont = node.trueContinuation.definition;
492 assert(cont.parameters.isEmpty); 505 assert(cont.parameters.isEmpty);
493 thenStatement = 506 thenStatement = cont.hasExactlyOneUse
494 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); 507 ? translateExpression(cont.body)
508 : new Break(labels[cont]);
495 cont = node.falseContinuation.definition; 509 cont = node.falseContinuation.definition;
496 assert(cont.parameters.isEmpty); 510 assert(cont.parameters.isEmpty);
497 elseStatement = 511 elseStatement = cont.hasExactlyOneUse
498 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); 512 ? translateExpression(cont.body)
513 : new Break(labels[cont]);
499 return new If(condition, thenStatement, elseStatement); 514 return new If(condition, thenStatement, elseStatement);
500 } 515 }
501 516
517
518 /************************** PRIMITIVES **************************/
519 //
520 // Visit methods for primitives must return an expression.
521 //
522
523 Expression visitSetField(cps_ir.SetField node) {
524 return new SetField(getVariableUse(node.object),
525 node.field,
526 getVariableUse(node.value));
527 }
528
529 Expression visitInterceptor(cps_ir.Interceptor node) {
530 return new Interceptor(getVariableUse(node.input), node.interceptedClasses);
531 }
532
533 Expression visitCreateInstance(cps_ir.CreateInstance node) {
534 return new CreateInstance(
535 node.classElement,
536 translateArguments(node.arguments),
537 translateArguments(node.typeInformation),
538 node.sourceInformation);
539 }
540
541 Expression visitGetField(cps_ir.GetField node) {
542 return new GetField(getVariableUse(node.object), node.field,
543 objectIsNotNull: node.objectIsNotNull);
544 }
545
546 Expression visitCreateBox(cps_ir.CreateBox node) {
547 return new CreateBox();
548 }
549
550 Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
551 return new CreateInvocationMirror(
552 node.selector,
553 translateArguments(node.arguments));
554 }
555
556 Expression visitGetMutable(cps_ir.GetMutable node) {
557 return getMutableVariableUse(node.variable);
558 }
559
560 Expression visitSetMutable(cps_ir.SetMutable node) {
561 Variable variable = getMutableVariable(node.variable.definition);
562 Expression value = getVariableUse(node.value);
563 return new Assign(variable, value);
564 }
565
502 Expression visitConstant(cps_ir.Constant node) { 566 Expression visitConstant(cps_ir.Constant node) {
503 return new Constant(node.value, sourceInformation: node.sourceInformation); 567 return new Constant(node.value, sourceInformation: node.sourceInformation);
504 } 568 }
505 569
506 Expression visitLiteralList(cps_ir.LiteralList node) { 570 Expression visitLiteralList(cps_ir.LiteralList node) {
507 return new LiteralList( 571 return new LiteralList(
508 node.type, 572 node.type,
509 translateArguments(node.values)); 573 translateArguments(node.values));
510 } 574 }
511 575
(...skipping 10 matching lines...) Expand all
522 586
523 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { 587 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) {
524 return createInnerBuilder().buildFunction(function); 588 return createInnerBuilder().buildFunction(function);
525 } 589 }
526 590
527 Expression visitCreateFunction(cps_ir.CreateFunction node) { 591 Expression visitCreateFunction(cps_ir.CreateFunction node) {
528 FunctionDefinition def = makeSubFunction(node.definition); 592 FunctionDefinition def = makeSubFunction(node.definition);
529 return new FunctionExpression(def); 593 return new FunctionExpression(def);
530 } 594 }
531 595
532 visitParameter(cps_ir.Parameter node) {
533 // Continuation parameters are not visited (continuations themselves are
534 // not visited yet).
535 unexpectedNode(node);
536 }
537
538 visitContinuation(cps_ir.Continuation node) {
539 // Until continuations with multiple uses are supported, they are not
540 // visited.
541 unexpectedNode(node);
542 }
543
544 visitMutableVariable(cps_ir.MutableVariable node) {
545 // These occur as parameters or bound by LetMutable. They are not visited
546 // directly.
547 unexpectedNode(node);
548 }
549
550 Expression visitIsTrue(cps_ir.IsTrue node) {
551 return getVariableUse(node.value);
552 }
553
554 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { 596 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
555 return new ReifyRuntimeType( 597 return new ReifyRuntimeType(
556 getVariableUse(node.value), node.sourceInformation); 598 getVariableUse(node.value), node.sourceInformation);
557 } 599 }
558 600
559 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { 601 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
560 return new ReadTypeVariable( 602 return new ReadTypeVariable(
561 node.variable, 603 node.variable,
562 getVariableUse(node.target), 604 getVariableUse(node.target),
563 node.sourceInformation); 605 node.sourceInformation);
564 } 606 }
565 607
566 @override 608 Expression visitTypeExpression(cps_ir.TypeExpression node) {
567 Node visitTypeExpression(cps_ir.TypeExpression node) {
568 return new TypeExpression( 609 return new TypeExpression(
569 node.dartType, 610 node.dartType,
570 node.arguments.map(getVariableUse).toList()); 611 node.arguments.map(getVariableUse).toList());
571 } 612 }
572 613
614 Expression visitTypeTest(cps_ir.TypeTest node) {
615 Expression value = getVariableUse(node.value);
616 List<Expression> typeArgs = translateArguments(node.typeArguments);
617 return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
618 }
619
573 Expression visitGetStatic(cps_ir.GetStatic node) { 620 Expression visitGetStatic(cps_ir.GetStatic node) {
574 return new GetStatic(node.element, node.sourceInformation); 621 return new GetStatic(node.element, node.sourceInformation);
575 } 622 }
576 623
577 Statement visitGetLazyStatic(cps_ir.GetLazyStatic node) {
578 // In the tree IR, GetStatic handles lazy fields because tree
579 // expressions are allowed to have side effects.
580 GetStatic value = new GetStatic(node.element, node.sourceInformation);
581 return continueWithExpression(node.continuation, value);
582 }
583
584 Expression visitSetStatic(cps_ir.SetStatic node) { 624 Expression visitSetStatic(cps_ir.SetStatic node) {
585 return new SetStatic( 625 return new SetStatic(
586 node.element, 626 node.element,
587 getVariableUse(node.value), 627 getVariableUse(node.value),
588 node.sourceInformation); 628 node.sourceInformation);
589 } 629 }
590 630
591 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) { 631 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
592 if (node.operator == BuiltinOperator.IsFalsy) { 632 if (node.operator == BuiltinOperator.IsFalsy) {
593 return new Not(getVariableUse(node.arguments.single)); 633 return new Not(getVariableUse(node.arguments.single));
594 } 634 }
595 return new ApplyBuiltinOperator(node.operator, 635 return new ApplyBuiltinOperator(node.operator,
596 translateArguments(node.arguments)); 636 translateArguments(node.arguments));
597 } 637 }
598 638
599 Statement visitForeignCode(cps_ir.ForeignCode node) {
600 if (node.codeTemplate.isExpression) {
601 Expression foreignCode = new ForeignExpression(
602 node.codeTemplate,
603 node.type,
604 node.arguments.map(getVariableUse).toList(growable: false),
605 node.nativeBehavior,
606 node.dependency);
607 return continueWithExpression(node.continuation, foreignCode);
608 } else {
609 assert(node.continuation.definition.body is cps_ir.Unreachable);
610 return new ForeignStatement(
611 node.codeTemplate,
612 node.type,
613 node.arguments.map(getVariableUse).toList(growable: false),
614 node.nativeBehavior,
615 node.dependency);
616 }
617 }
618
619 Expression visitGetLength(cps_ir.GetLength node) { 639 Expression visitGetLength(cps_ir.GetLength node) {
620 return new GetLength(getVariableUse(node.object)); 640 return new GetLength(getVariableUse(node.object));
621 } 641 }
622 642
623 Expression visitGetIndex(cps_ir.GetIndex node) { 643 Expression visitGetIndex(cps_ir.GetIndex node) {
624 return new GetIndex(getVariableUse(node.object), 644 return new GetIndex(getVariableUse(node.object),
625 getVariableUse(node.index)); 645 getVariableUse(node.index));
626 } 646 }
627 647
628 Expression visitSetIndex(cps_ir.SetIndex node) { 648 Expression visitSetIndex(cps_ir.SetIndex node) {
629 return new SetIndex(getVariableUse(node.object), 649 return new SetIndex(getVariableUse(node.object),
630 getVariableUse(node.index), 650 getVariableUse(node.index),
631 getVariableUse(node.value)); 651 getVariableUse(node.value));
632 } 652 }
653
654 /********** UNUSED VISIT METHODS *************/
655
656 unexpectedNode(cps_ir.Node node) {
657 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
658 }
659
660 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
661 unexpectedNode(node);
662 }
663 visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
664 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
665 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
666 visitIsTrue(cps_ir.IsTrue node) => unexpectedNode(node);
633 } 667 }
634 668
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698