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

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: Rebase 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(
269 getVariableUse(node.input),
270 node.interceptedClasses,
271 node.sourceInformation);
272 } 276 }
273 277
274 Expression visitCreateInstance(cps_ir.CreateInstance node) { 278 /// Translates a condition to a tree expression.
275 return new CreateInstance( 279 Expression translateCondition(cps_ir.Condition condition) {
276 node.classElement, 280 cps_ir.IsTrue isTrue = condition;
277 translateArguments(node.arguments), 281 return getVariableUse(isTrue.value);
278 translateArguments(node.typeInformation),
279 node.sourceInformation);
280 } 282 }
281 283
282 Expression visitGetField(cps_ir.GetField node) { 284 /************************ INTERIOR EXPRESSIONS ************************/
283 return new GetField(getVariableUse(node.object), node.field, 285 //
284 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);
285 } 343 }
286 344
287 Expression visitCreateBox(cps_ir.CreateBox node) { 345
288 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 };
289 } 366 }
290 367
291 visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) { 368 NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) {
292 return new CreateInvocationMirror(
293 node.selector,
294 translateArguments(node.arguments));
295 }
296
297 // Executable definitions are not visited directly. They have 'build'
298 // functions as entry points.
299 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
300 return unexpectedNode(node);
301 }
302
303 Statement visitLetPrim(cps_ir.LetPrim node) {
304 Variable variable = getVariable(node.primitive);
305 Expression value = visit(node.primitive);
306 if (node.primitive.hasAtLeastOneUse) {
307 return Assign.makeStatement(variable, value, visit(node.body));
308 } else {
309 return new ExpressionStatement(value, visit(node.body));
310 }
311 }
312
313 Statement visitLetCont(cps_ir.LetCont node) {
314 // Introduce labels for continuations that need them.
315 for (cps_ir.Continuation continuation in node.continuations) {
316 if (continuation.hasMultipleUses || continuation.isRecursive) {
317 labels[continuation] = new Label();
318 }
319 }
320 Statement body = visit(node.body);
321 // Continuations are bound at the same level, but they have to be
322 // translated as if nested. This is because the body can invoke any
323 // of them from anywhere, so it must be nested inside all of them.
324 //
325 // The continuation bodies are not always translated directly here because
326 // they may have been already translated:
327 // * For singly-used continuations, the continuation's body is
328 // translated at the site of the continuation invocation.
329 // * For recursive continuations, there is a single non-recursive
330 // invocation. The continuation's body is translated at the site
331 // of the non-recursive continuation invocation.
332 // See visitInvokeContinuation for the implementation.
333 Statement current = body;
334 for (cps_ir.Continuation continuation in node.continuations.reversed) {
335 Label label = labels[continuation];
336 if (label != null && !continuation.isRecursive) {
337 current =
338 new LabeledStatement(label, current, visit(continuation.body));
339 }
340 }
341 return current;
342 }
343
344 Statement visitLetHandler(cps_ir.LetHandler node) {
345 Statement tryBody = visit(node.body);
346 List<Variable> catchParameters =
347 node.handler.parameters.map(getVariable).toList();
348 Statement catchBody = visit(node.handler.body);
349 return new Try(tryBody, catchParameters, catchBody);
350 }
351
352 Statement visitInvokeStatic(cps_ir.InvokeStatic node) {
353 // Calls are translated to direct style.
354 List<Expression> arguments = translateArguments(node.arguments); 369 List<Expression> arguments = translateArguments(node.arguments);
355 Expression invoke = new InvokeStatic(node.target, node.selector, arguments, 370 Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
356 node.sourceInformation); 371 node.sourceInformation);
357 return continueWithExpression(node.continuation, invoke); 372 return makeCallExpression(node, invoke);
358 } 373 }
359 374
360 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { 375 NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) {
361 InvokeMethod invoke = new InvokeMethod( 376 InvokeMethod invoke = new InvokeMethod(
362 getVariableUse(node.receiver), 377 getVariableUse(node.receiver),
363 node.selector, 378 node.selector,
364 node.mask, 379 node.mask,
365 translateArguments(node.arguments), 380 translateArguments(node.arguments),
366 node.sourceInformation); 381 node.sourceInformation);
367 invoke.receiverIsNotNull = node.receiverIsNotNull; 382 invoke.receiverIsNotNull = node.receiverIsNotNull;
368 return continueWithExpression(node.continuation, invoke); 383 return makeCallExpression(node, invoke);
369 } 384 }
370 385
371 Statement visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { 386 NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
372 Expression receiver = getVariableUse(node.receiver); 387 Expression receiver = getVariableUse(node.receiver);
373 List<Expression> arguments = translateArguments(node.arguments); 388 List<Expression> arguments = translateArguments(node.arguments);
374 Expression invoke = new InvokeMethodDirectly(receiver, node.target, 389 Expression invoke = new InvokeMethodDirectly(receiver, node.target,
375 node.selector, arguments, node.sourceInformation); 390 node.selector, arguments, node.sourceInformation);
376 return continueWithExpression(node.continuation, invoke); 391 return makeCallExpression(node, invoke);
377 } 392 }
378 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
379 Statement visitThrow(cps_ir.Throw node) { 448 Statement visitThrow(cps_ir.Throw node) {
380 Expression value = getVariableUse(node.value); 449 Expression value = getVariableUse(node.value);
381 return new Throw(value); 450 return new Throw(value);
382 } 451 }
383 452
384 Statement visitRethrow(cps_ir.Rethrow node) { 453 Statement visitRethrow(cps_ir.Rethrow node) {
385 return new Rethrow(); 454 return new Rethrow();
386 } 455 }
387 456
388 Statement visitUnreachable(cps_ir.Unreachable node) { 457 Statement visitUnreachable(cps_ir.Unreachable node) {
389 return new Unreachable(); 458 return new Unreachable();
390 } 459 }
391 460
392 Statement continueWithExpression(cps_ir.Reference continuation,
393 Expression expression) {
394 cps_ir.Continuation cont = continuation.definition;
395 if (cont == returnContinuation) {
396 return new Return(expression);
397 } else {
398 assert(cont.parameters.length == 1);
399 Function nextBuilder = cont.hasExactlyOneUse ?
400 () => visit(cont.body) : () => new Break(labels[cont]);
401 return buildContinuationAssignment(cont.parameters.single, expression,
402 nextBuilder);
403 }
404 }
405
406 Statement visitLetMutable(cps_ir.LetMutable node) {
407 Variable variable = addMutableVariable(node.variable);
408 Expression value = getVariableUse(node.value);
409 Statement body = visit(node.body);
410 return Assign.makeStatement(variable, value, body);
411 }
412
413 Expression visitGetMutable(cps_ir.GetMutable node) {
414 return getMutableVariableUse(node.variable);
415 }
416
417 Expression visitSetMutable(cps_ir.SetMutable node) {
418 Variable variable = getMutableVariable(node.variable.definition);
419 Expression value = getVariableUse(node.value);
420 return new Assign(variable, value);
421 }
422
423 Statement visitTypeCast(cps_ir.TypeCast node) {
424 Expression value = getVariableUse(node.value);
425 List<Expression> typeArgs = translateArguments(node.typeArguments);
426 Expression expression =
427 new TypeOperator(value, node.type, typeArgs, isTypeTest: false);
428 return continueWithExpression(node.continuation, expression);
429 }
430
431 Expression visitTypeTest(cps_ir.TypeTest node) {
432 Expression value = getVariableUse(node.value);
433 List<Expression> typeArgs = translateArguments(node.typeArguments);
434 return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
435 }
436
437 Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) {
438 List<Expression> arguments = translateArguments(node.arguments);
439 Expression invoke = new InvokeConstructor(
440 node.type,
441 node.target,
442 node.selector,
443 arguments,
444 node.sourceInformation);
445 return continueWithExpression(node.continuation, invoke);
446 }
447
448 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) { 461 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) {
449 // Invocations of the return continuation are translated to returns. 462 // Invocations of the return continuation are translated to returns.
450 // Other continuation invocations are replaced with assignments of the 463 // Other continuation invocations are replaced with assignments of the
451 // arguments to formal parameter variables, followed by the body if 464 // arguments to formal parameter variables, followed by the body if
452 // 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
453 // referenced. 466 // referenced.
454 cps_ir.Continuation cont = node.continuation.definition; 467 cps_ir.Continuation cont = node.continuation.definition;
455 if (cont == returnContinuation) { 468 if (cont == returnContinuation) {
456 assert(node.arguments.length == 1); 469 assert(node.arguments.length == 1);
457 return new Return(getVariableUse(node.arguments.single), 470 return new Return(getVariableUse(node.arguments.single),
458 sourceInformation: node.sourceInformation); 471 sourceInformation: node.sourceInformation);
459 } else { 472 } else {
460 List<Expression> arguments = translateArguments(node.arguments); 473 List<Expression> arguments = translateArguments(node.arguments);
461 return buildPhiAssignments(cont.parameters, arguments, 474 return buildPhiAssignments(cont.parameters, arguments,
462 () { 475 () {
463 // Translate invocations of recursive and non-recursive 476 // Translate invocations of recursive and non-recursive
464 // continuations differently. 477 // continuations differently.
465 // * Non-recursive continuations 478 // * Non-recursive continuations
466 // - If there is one use, translate the continuation body 479 // - If there is one use, translate the continuation body
467 // inline at the invocation site. 480 // inline at the invocation site.
468 // - If there are multiple uses, translate to Break. 481 // - If there are multiple uses, translate to Break.
469 // * Recursive continuations 482 // * Recursive continuations
470 // - There is a single non-recursive invocation. Translate 483 // - There is a single non-recursive invocation. Translate
471 // the continuation body inline as a labeled loop at the 484 // the continuation body inline as a labeled loop at the
472 // invocation site. 485 // invocation site.
473 // - Translate the recursive invocations to Continue. 486 // - Translate the recursive invocations to Continue.
474 if (cont.isRecursive) { 487 if (cont.isRecursive) {
475 return node.isRecursive 488 return node.isRecursive
476 ? new Continue(labels[cont]) 489 ? new Continue(getLabel(cont))
477 : new WhileTrue(labels[cont], visit(cont.body)); 490 : new WhileTrue(getLabel(cont),
491 translateExpression(cont.body));
478 } else { 492 } else {
479 if (cont.hasExactlyOneUse) { 493 return cont.hasExactlyOneUse && !node.isEscapingTry
480 if (!node.isEscapingTry) { 494 ? translateExpression(cont.body)
481 return visit(cont.body); 495 : new Break(getLabel(cont));
482 }
483 labels[cont] = new Label();
484 }
485 return new Break(labels[cont]);
486 } 496 }
487 }); 497 });
488 } 498 }
489 } 499 }
490 500
491 Statement visitBranch(cps_ir.Branch node) { 501 Statement visitBranch(cps_ir.Branch node) {
492 Expression condition = visit(node.condition); 502 Expression condition = translateCondition(node.condition);
493 Statement thenStatement, elseStatement; 503 Statement thenStatement, elseStatement;
494 cps_ir.Continuation cont = node.trueContinuation.definition; 504 cps_ir.Continuation cont = node.trueContinuation.definition;
495 assert(cont.parameters.isEmpty); 505 assert(cont.parameters.isEmpty);
496 thenStatement = 506 thenStatement = cont.hasExactlyOneUse
497 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); 507 ? translateExpression(cont.body)
508 : new Break(labels[cont]);
498 cont = node.falseContinuation.definition; 509 cont = node.falseContinuation.definition;
499 assert(cont.parameters.isEmpty); 510 assert(cont.parameters.isEmpty);
500 elseStatement = 511 elseStatement = cont.hasExactlyOneUse
501 cont.hasExactlyOneUse ? visit(cont.body) : new Break(labels[cont]); 512 ? translateExpression(cont.body)
513 : new Break(labels[cont]);
502 return new If(condition, thenStatement, elseStatement); 514 return new If(condition, thenStatement, elseStatement);
503 } 515 }
504 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),
531 node.interceptedClasses,
532 node.sourceInformation);
533 }
534
535 Expression visitCreateInstance(cps_ir.CreateInstance node) {
536 return new CreateInstance(
537 node.classElement,
538 translateArguments(node.arguments),
539 translateArguments(node.typeInformation),
540 node.sourceInformation);
541 }
542
543 Expression visitGetField(cps_ir.GetField node) {
544 return new GetField(getVariableUse(node.object), node.field,
545 objectIsNotNull: node.objectIsNotNull);
546 }
547
548 Expression visitCreateBox(cps_ir.CreateBox node) {
549 return new CreateBox();
550 }
551
552 Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
553 return new CreateInvocationMirror(
554 node.selector,
555 translateArguments(node.arguments));
556 }
557
558 Expression visitGetMutable(cps_ir.GetMutable node) {
559 return getMutableVariableUse(node.variable);
560 }
561
562 Expression visitSetMutable(cps_ir.SetMutable node) {
563 Variable variable = getMutableVariable(node.variable.definition);
564 Expression value = getVariableUse(node.value);
565 return new Assign(variable, value);
566 }
567
505 Expression visitConstant(cps_ir.Constant node) { 568 Expression visitConstant(cps_ir.Constant node) {
506 return new Constant(node.value, sourceInformation: node.sourceInformation); 569 return new Constant(node.value, sourceInformation: node.sourceInformation);
507 } 570 }
508 571
509 Expression visitLiteralList(cps_ir.LiteralList node) { 572 Expression visitLiteralList(cps_ir.LiteralList node) {
510 return new LiteralList( 573 return new LiteralList(
511 node.type, 574 node.type,
512 translateArguments(node.values)); 575 translateArguments(node.values));
513 } 576 }
514 577
(...skipping 10 matching lines...) Expand all
525 588
526 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) { 589 FunctionDefinition makeSubFunction(cps_ir.FunctionDefinition function) {
527 return createInnerBuilder().buildFunction(function); 590 return createInnerBuilder().buildFunction(function);
528 } 591 }
529 592
530 Expression visitCreateFunction(cps_ir.CreateFunction node) { 593 Expression visitCreateFunction(cps_ir.CreateFunction node) {
531 FunctionDefinition def = makeSubFunction(node.definition); 594 FunctionDefinition def = makeSubFunction(node.definition);
532 return new FunctionExpression(def); 595 return new FunctionExpression(def);
533 } 596 }
534 597
535 visitParameter(cps_ir.Parameter node) {
536 // Continuation parameters are not visited (continuations themselves are
537 // not visited yet).
538 unexpectedNode(node);
539 }
540
541 visitContinuation(cps_ir.Continuation node) {
542 // Until continuations with multiple uses are supported, they are not
543 // visited.
544 unexpectedNode(node);
545 }
546
547 visitMutableVariable(cps_ir.MutableVariable node) {
548 // These occur as parameters or bound by LetMutable. They are not visited
549 // directly.
550 unexpectedNode(node);
551 }
552
553 Expression visitIsTrue(cps_ir.IsTrue node) {
554 return getVariableUse(node.value);
555 }
556
557 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) { 598 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
558 return new ReifyRuntimeType( 599 return new ReifyRuntimeType(
559 getVariableUse(node.value), node.sourceInformation); 600 getVariableUse(node.value), node.sourceInformation);
560 } 601 }
561 602
562 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) { 603 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
563 return new ReadTypeVariable( 604 return new ReadTypeVariable(
564 node.variable, 605 node.variable,
565 getVariableUse(node.target), 606 getVariableUse(node.target),
566 node.sourceInformation); 607 node.sourceInformation);
567 } 608 }
568 609
569 @override 610 Expression visitTypeExpression(cps_ir.TypeExpression node) {
570 Node visitTypeExpression(cps_ir.TypeExpression node) {
571 return new TypeExpression( 611 return new TypeExpression(
572 node.dartType, 612 node.dartType,
573 node.arguments.map(getVariableUse).toList()); 613 node.arguments.map(getVariableUse).toList());
574 } 614 }
575 615
616 Expression visitTypeTest(cps_ir.TypeTest node) {
617 Expression value = getVariableUse(node.value);
618 List<Expression> typeArgs = translateArguments(node.typeArguments);
619 return new TypeOperator(value, node.type, typeArgs, isTypeTest: true);
620 }
621
576 Expression visitGetStatic(cps_ir.GetStatic node) { 622 Expression visitGetStatic(cps_ir.GetStatic node) {
577 return new GetStatic(node.element, node.sourceInformation); 623 return new GetStatic(node.element, node.sourceInformation);
578 } 624 }
579 625
580 Statement visitGetLazyStatic(cps_ir.GetLazyStatic node) {
581 // In the tree IR, GetStatic handles lazy fields because tree
582 // expressions are allowed to have side effects.
583 GetStatic value = new GetStatic(node.element, node.sourceInformation);
584 return continueWithExpression(node.continuation, value);
585 }
586
587 Expression visitSetStatic(cps_ir.SetStatic node) { 626 Expression visitSetStatic(cps_ir.SetStatic node) {
588 return new SetStatic( 627 return new SetStatic(
589 node.element, 628 node.element,
590 getVariableUse(node.value), 629 getVariableUse(node.value),
591 node.sourceInformation); 630 node.sourceInformation);
592 } 631 }
593 632
594 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) { 633 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
595 if (node.operator == BuiltinOperator.IsFalsy) { 634 if (node.operator == BuiltinOperator.IsFalsy) {
596 return new Not(getVariableUse(node.arguments.single)); 635 return new Not(getVariableUse(node.arguments.single));
597 } 636 }
598 return new ApplyBuiltinOperator(node.operator, 637 return new ApplyBuiltinOperator(node.operator,
599 translateArguments(node.arguments)); 638 translateArguments(node.arguments));
600 } 639 }
601 640
602 Statement visitForeignCode(cps_ir.ForeignCode node) {
603 if (node.codeTemplate.isExpression) {
604 Expression foreignCode = new ForeignExpression(
605 node.codeTemplate,
606 node.type,
607 node.arguments.map(getVariableUse).toList(growable: false),
608 node.nativeBehavior,
609 node.dependency);
610 return continueWithExpression(node.continuation, foreignCode);
611 } else {
612 assert(node.continuation.definition.body is cps_ir.Unreachable);
613 return new ForeignStatement(
614 node.codeTemplate,
615 node.type,
616 node.arguments.map(getVariableUse).toList(growable: false),
617 node.nativeBehavior,
618 node.dependency);
619 }
620 }
621
622 Expression visitGetLength(cps_ir.GetLength node) { 641 Expression visitGetLength(cps_ir.GetLength node) {
623 return new GetLength(getVariableUse(node.object)); 642 return new GetLength(getVariableUse(node.object));
624 } 643 }
625 644
626 Expression visitGetIndex(cps_ir.GetIndex node) { 645 Expression visitGetIndex(cps_ir.GetIndex node) {
627 return new GetIndex(getVariableUse(node.object), 646 return new GetIndex(getVariableUse(node.object),
628 getVariableUse(node.index)); 647 getVariableUse(node.index));
629 } 648 }
630 649
631 Expression visitSetIndex(cps_ir.SetIndex node) { 650 Expression visitSetIndex(cps_ir.SetIndex node) {
632 return new SetIndex(getVariableUse(node.object), 651 return new SetIndex(getVariableUse(node.object),
633 getVariableUse(node.index), 652 getVariableUse(node.index),
634 getVariableUse(node.value)); 653 getVariableUse(node.value));
635 } 654 }
655
656 /********** UNUSED VISIT METHODS *************/
657
658 unexpectedNode(cps_ir.Node node) {
659 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
660 }
661
662 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
663 unexpectedNode(node);
664 }
665 visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
666 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
667 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
668 visitIsTrue(cps_ir.IsTrue node) => unexpectedNode(node);
636 } 669 }
637 670
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698