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

Side by Side Diff: pkg/compiler/lib/src/tree_ir/tree_ir_builder.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) 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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library tree_ir_builder;
6
7 import '../common.dart';
8 import '../constants/values.dart';
9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
10 import '../elements/elements.dart';
11 import '../io/source_information.dart';
12 import '../js_backend/codegen/glue.dart';
13 import 'tree_ir_nodes.dart';
14
15 typedef Statement NodeCallback(Statement next);
16
17 /**
18 * Builder translates from CPS-based IR to direct-style Tree.
19 *
20 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced
21 * non-exit continuation `Cont(v, body)` is translated into a direct-style call
22 * whose value is bound in the continuation body:
23 *
24 * `LetVal(v, Invoke(fun, args), body)`
25 *
26 * and the continuation definition is eliminated. A similar translation is
27 * applied to continuation invocations where the continuation is
28 * singly-referenced, though such invocations should not appear in optimized
29 * IR.
30 *
31 * A call `Invoke(fun, cont, args)`, where cont is multiply referenced, is
32 * translated into a call followed by a jump with an argument:
33 *
34 * `Jump L(Invoke(fun, args))`
35 *
36 * and the continuation is translated into a named block that takes an
37 * argument:
38 *
39 * `LetLabel(L, v, body)`
40 *
41 * Block arguments are later replaced with data flow during the Tree-to-Tree
42 * translation out of SSA. Jumps are eliminated during the Tree-to-Tree
43 * control-flow recognition.
44 *
45 * Otherwise, the output of Builder looks very much like the input. In
46 * particular, intermediate values and blocks used for local control flow are
47 * still all named.
48 */
49 class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
50 final InternalErrorFunction internalError;
51 final Glue glue;
52
53 final Map<cps_ir.Primitive, Variable> primitive2variable =
54 <cps_ir.Primitive, Variable>{};
55 final Map<cps_ir.MutableVariable, Variable> mutable2variable =
56 <cps_ir.MutableVariable, Variable>{};
57 final Set<cps_ir.Constant> inlinedConstants = new Set<cps_ir.Constant>();
58
59 // Continuations with more than one use are replaced with Tree labels. This
60 // is the mapping from continuations to labels.
61 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
62
63 ExecutableElement currentElement;
64
65 /// The parameter to be translated to 'this'. This can either be the receiver
66 /// parameter, the interceptor parameter, or null if the method has neither.
67 cps_ir.Parameter thisParameter;
68 cps_ir.Continuation returnContinuation;
69
70 Builder(this.internalError, this.glue);
71
72 /// Variable used in [buildPhiAssignments] as a temporary when swapping
73 /// variables.
74 Variable phiTempVar;
75
76 Variable addMutableVariable(cps_ir.MutableVariable irVariable) {
77 assert(!mutable2variable.containsKey(irVariable));
78 Variable variable = new Variable(currentElement, irVariable.hint);
79 mutable2variable[irVariable] = variable;
80 return variable;
81 }
82
83 Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) {
84 return mutable2variable[mutableVariable];
85 }
86
87 VariableUse getMutableVariableUse(
88 cps_ir.Reference<cps_ir.MutableVariable> reference,
89 SourceInformation sourceInformation) {
90 Variable variable = getMutableVariable(reference.definition);
91 return new VariableUse(variable, sourceInformation: sourceInformation);
92 }
93
94 /// Obtains the variable representing the given primitive. Returns null for
95 /// primitives that have no reference and do not need a variable.
96 Variable getVariable(cps_ir.Primitive primitive) {
97 primitive = primitive.effectiveDefinition;
98 return primitive2variable.putIfAbsent(
99 primitive, () => new Variable(currentElement, primitive.hint));
100 }
101
102 /// Obtains a reference to the tree Variable corresponding to the IR primitive
103 /// referred to by [reference].
104 /// This increments the reference count for the given variable, so the
105 /// returned expression must be used in the tree.
106 Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference,
107 {SourceInformation sourceInformation}) {
108 cps_ir.Primitive prim = reference.definition.effectiveDefinition;
109 if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) {
110 return new Constant(prim.value);
111 }
112 if (thisParameter != null && prim == thisParameter) {
113 return new This();
114 }
115 return new VariableUse(getVariable(prim),
116 sourceInformation: sourceInformation);
117 }
118
119 Expression getVariableUseOrNull(
120 cps_ir.Reference<cps_ir.Primitive> reference) {
121 return reference == null ? null : getVariableUse(reference);
122 }
123
124 Label getLabel(cps_ir.Continuation cont) {
125 return labels.putIfAbsent(cont, () => new Label());
126 }
127
128 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
129 currentElement = node.element;
130 List<Variable> parameters = node.parameters.map(getVariable).toList();
131 if (node.interceptorParameter != null) {
132 parameters.insert(0, getVariable(node.receiverParameter));
133 thisParameter = glue.methodUsesReceiverArgument(node.element)
134 ? node.interceptorParameter
135 : node.receiverParameter;
136 } else {
137 thisParameter = node.receiverParameter;
138 }
139 returnContinuation = node.returnContinuation;
140 phiTempVar = new Variable(node.element, null);
141 Statement body = translateExpression(node.body);
142 return new FunctionDefinition(node.element, parameters, body,
143 sourceInformation: node.sourceInformation);
144 }
145
146 /// Returns a list of variables corresponding to the arguments to a method
147 /// call or similar construct.
148 ///
149 /// The `readCount` for these variables will be incremented.
150 ///
151 /// The list will be typed as a list of [Expression] to allow inplace updates
152 /// on the list during the rewrite phases.
153 List<Expression> translateArguments(List<cps_ir.Reference> args) {
154 return new List<Expression>.generate(
155 args.length, (int index) => getVariableUse(args[index]),
156 growable: false);
157 }
158
159 /// Simultaneously assigns each argument to the corresponding parameter,
160 /// then continues at the statement created by [buildRest].
161 Statement buildPhiAssignments(List<cps_ir.Parameter> parameters,
162 List<Expression> arguments, Statement buildRest()) {
163 assert(parameters.length == arguments.length);
164 // We want a parallel assignment to all parameters simultaneously.
165 // Since we do not have parallel assignments in dart_tree, we must linearize
166 // the assignments without attempting to read a previously-overwritten
167 // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x},
168 // for this we must introduce a temporary variable: {t = x; x = y; y = t}.
169
170 // [rightHand] is the inverse of [arguments], that is, it maps variables
171 // to the assignments on which is occurs as the right-hand side.
172 Map<Variable, List<int>> rightHand = <Variable, List<int>>{};
173 for (int i = 0; i < parameters.length; i++) {
174 Variable param = getVariable(parameters[i]);
175 Expression arg = arguments[i];
176 if (arg is VariableUse) {
177 if (param == null || param == arg.variable) {
178 // No assignment necessary.
179 --arg.variable.readCount;
180 continue;
181 }
182 // v1 = v0
183 List<int> list = rightHand[arg.variable];
184 if (list == null) {
185 rightHand[arg.variable] = list = <int>[];
186 }
187 list.add(i);
188 } else {
189 // v1 = this;
190 }
191 }
192
193 Statement first, current;
194 void addAssignment(Variable dst, Expression src) {
195 if (first == null) {
196 first = current = Assign.makeStatement(dst, src);
197 } else {
198 current = current.next = Assign.makeStatement(dst, src);
199 }
200 }
201
202 List<Expression> assignmentSrc = new List<Expression>(parameters.length);
203 List<bool> done = new List<bool>.filled(parameters.length, false);
204 void visitAssignment(int i) {
205 if (done[i]) {
206 return;
207 }
208 Variable param = getVariable(parameters[i]);
209 Expression arg = arguments[i];
210 if (param == null || (arg is VariableUse && param == arg.variable)) {
211 return; // No assignment necessary.
212 }
213 if (assignmentSrc[i] != null) {
214 // Cycle found; store argument in a temporary variable.
215 // The temporary will then be used as right-hand side when the
216 // assignment gets added.
217 VariableUse source = assignmentSrc[i];
218 if (source.variable != phiTempVar) {
219 // Only move to temporary once.
220 assignmentSrc[i] = new VariableUse(phiTempVar);
221 addAssignment(phiTempVar, arg);
222 }
223 return;
224 }
225 assignmentSrc[i] = arg;
226 List<int> paramUses = rightHand[param];
227 if (paramUses != null) {
228 for (int useIndex in paramUses) {
229 visitAssignment(useIndex);
230 }
231 }
232 addAssignment(param, assignmentSrc[i]);
233 done[i] = true;
234 }
235
236 for (int i = 0; i < parameters.length; i++) {
237 if (!done[i]) {
238 visitAssignment(i);
239 }
240 }
241
242 if (first == null) {
243 first = buildRest();
244 } else {
245 current.next = buildRest();
246 }
247 return first;
248 }
249
250 visit(cps_ir.Node node) => throw 'Use translateXXX instead of visit';
251
252 /// Translates a CPS expression into a tree statement.
253 ///
254 /// To avoid deep recursion, we traverse each basic blocks without
255 /// recursion.
256 ///
257 /// Non-tail expressions evaluate to a callback to be invoked once the
258 /// successor statement has been constructed. These callbacks are stored
259 /// in a stack until the block's tail expression has been translated.
260 Statement translateExpression(cps_ir.Expression node) {
261 List<NodeCallback> stack = <NodeCallback>[];
262 while (node is! cps_ir.TailExpression) {
263 stack.add(node.accept(this));
264 node = node.next;
265 }
266 Statement result = node.accept(this); // Translate the tail expression.
267 for (NodeCallback fun in stack.reversed) {
268 result = fun(result);
269 }
270 return result;
271 }
272
273 /// Translates a CPS primitive to a tree expression.
274 ///
275 /// This simply calls the visit method for the primitive.
276 translatePrimitive(cps_ir.Primitive prim) {
277 return prim.accept(this);
278 }
279
280 /************************ CONSTANT COPYING *****************************/
281
282 /// Estimate of the number of characters needed to emit a use of the given
283 /// constant.
284 int constantSize(PrimitiveConstantValue value) {
285 // TODO(asgerf): We could interface with the emitter to get the exact size.
286 if (value is StringConstantValue) {
287 // Account for the quotes, but ignore the cost of encoding non-ASCII
288 // characters to avoid traversing the string and depending on encoding.
289 return value.length + 2;
290 } else if (value is BoolConstantValue) {
291 return 2; // Printed as !0 and !1 when minified
292 } else {
293 // TODO(asgerf): Get the exact length of numbers using '1e10' notation.
294 return '${value.primitiveValue}'.length;
295 }
296 }
297
298 /// The number of uses [prim] has, or `-1` if it is used in a phi assignment.
299 int countNonPhiUses(cps_ir.Primitive prim) {
300 int count = 0;
301 for (cps_ir.Reference ref = prim.firstRef; ref != null; ref = ref.next) {
302 cps_ir.Node use = ref.parent;
303 if (use is cps_ir.InvokeContinuation) {
304 return -1;
305 }
306 count++;
307 }
308 return count;
309 }
310
311 /// True if the given [constant] should be copied to every use site.
312 bool shouldCopyToUses(cps_ir.Constant constant) {
313 if (!constant.value.isPrimitive) return false;
314 if (constant.hasAtMostOneUse) return true;
315 int uses = countNonPhiUses(constant);
316 if (uses == -1) return false; // Copying might prevent elimination of a phi.
317 int size = constantSize(constant.value);
318 // Compare the expected code size output of copying vs sharing.
319 const int USE = 2; // Minified locals usually have length 2.
320 const int ASSIGN = USE + 2; // Variable and '=' and ';'
321 const int BIAS = 2; // Artificial bias to slightly favor copying.
322 int costOfSharing = USE * uses + size + ASSIGN + BIAS;
323 int costOfCopying = size * uses;
324 return costOfCopying <= costOfSharing;
325 }
326
327 /************************ INTERIOR EXPRESSIONS ************************/
328 //
329 // Visit methods for interior expressions must return a function:
330 //
331 // (Statement next) => <result statement>
332 //
333
334 NodeCallback visitLetPrim(cps_ir.LetPrim node) {
335 if (node.primitive is cps_ir.Constant && shouldCopyToUses(node.primitive)) {
336 inlinedConstants.add(node.primitive);
337 return (Statement next) => next;
338 }
339 Variable variable = getVariable(node.primitive);
340 var value = translatePrimitive(node.primitive);
341 if (value is Expression) {
342 if (node.primitive.hasAtLeastOneUse) {
343 return (Statement next) => Assign.makeStatement(variable, value, next);
344 } else {
345 return (Statement next) => new ExpressionStatement(value, next);
346 }
347 } else {
348 assert(value is NodeCallback);
349 return value;
350 }
351 }
352
353 // Continuations are bound at the same level, but they have to be
354 // translated as if nested. This is because the body can invoke any
355 // of them from anywhere, so it must be nested inside all of them.
356 //
357 // The continuation bodies are not always translated directly here because
358 // they may have been already translated:
359 // * For singly-used continuations, the continuation's body is
360 // translated at the site of the continuation invocation.
361 // * For recursive continuations, there is a single non-recursive
362 // invocation. The continuation's body is translated at the site
363 // of the non-recursive continuation invocation.
364 // See [visitInvokeContinuation] for the implementation.
365 NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) {
366 for (cps_ir.Continuation continuation in node.continuations) {
367 // This happens after the body of the LetCont has been translated.
368 // Labels are created on-demand if the continuation could not be inlin ed,
369 // so the existence of the label indicates if a labeled statement shou ld
370 // be emitted.
371 Label label = labels[continuation];
372 if (label != null && !continuation.isRecursive) {
373 // Recursively build the body. We only do this for join continuation s,
374 // so we should not risk overly deep recursion.
375 next = new LabeledStatement(
376 label, next, translateExpression(continuation.body));
377 }
378 }
379 return next;
380 };
381
382 NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) {
383 List<Variable> catchParameters =
384 node.handler.parameters.map(getVariable).toList();
385 Statement catchBody = translateExpression(node.handler.body);
386 return new Try(next, catchParameters, catchBody);
387 };
388
389 NodeCallback visitLetMutable(cps_ir.LetMutable node) {
390 Variable variable = addMutableVariable(node.variable);
391 Expression value = getVariableUse(node.valueRef);
392 return (Statement next) => Assign.makeStatement(variable, value, next);
393 }
394
395 /************************** TAIL EXPRESSIONS **************************/
396 //
397 // Visit methods for tail expressions must return a statement directly
398 // (not a function like interior and call expressions).
399
400 Statement visitThrow(cps_ir.Throw node) {
401 Expression value = getVariableUse(node.valueRef);
402 return new Throw(value);
403 }
404
405 Statement visitUnreachable(cps_ir.Unreachable node) {
406 return new Unreachable();
407 }
408
409 Statement visitInvokeContinuation(cps_ir.InvokeContinuation node) {
410 // Invocations of the return continuation are translated to returns.
411 // Other continuation invocations are replaced with assignments of the
412 // arguments to formal parameter variables, followed by the body if
413 // the continuation is singly reference or a break if it is multiply
414 // referenced.
415 cps_ir.Continuation cont = node.continuation;
416 if (cont == returnContinuation) {
417 assert(node.argumentRefs.length == 1);
418 return new Return(getVariableUse(node.argumentRefs.single),
419 sourceInformation: node.sourceInformation);
420 } else {
421 List<Expression> arguments = translateArguments(node.argumentRefs);
422 return buildPhiAssignments(cont.parameters, arguments, () {
423 // Translate invocations of recursive and non-recursive
424 // continuations differently.
425 // * Non-recursive continuations
426 // - If there is one use, translate the continuation body
427 // inline at the invocation site.
428 // - If there are multiple uses, translate to Break.
429 // * Recursive continuations
430 // - There is a single non-recursive invocation. Translate
431 // the continuation body inline as a labeled loop at the
432 // invocation site.
433 // - Translate the recursive invocations to Continue.
434 if (cont.isRecursive) {
435 return node.isRecursive
436 ? new Continue(getLabel(cont))
437 : new WhileTrue(getLabel(cont), translateExpression(cont.body));
438 } else {
439 return cont.hasExactlyOneUse && !node.isEscapingTry
440 ? translateExpression(cont.body)
441 : new Break(getLabel(cont));
442 }
443 });
444 }
445 }
446
447 /// Translates a branch condition to a tree expression.
448 Expression translateCondition(cps_ir.Branch branch) {
449 Expression value = getVariableUse(branch.conditionRef,
450 sourceInformation: branch.sourceInformation);
451 if (branch.isStrictCheck) {
452 return new ApplyBuiltinOperator(
453 BuiltinOperator.StrictEq,
454 <Expression>[value, new Constant(new TrueConstantValue())],
455 branch.sourceInformation);
456 } else {
457 return value;
458 }
459 }
460
461 Statement visitBranch(cps_ir.Branch node) {
462 Expression condition = translateCondition(node);
463 Statement thenStatement, elseStatement;
464 cps_ir.Continuation cont = node.trueContinuation;
465 assert(cont.parameters.isEmpty);
466 thenStatement = cont.hasExactlyOneUse
467 ? translateExpression(cont.body)
468 : new Break(labels[cont]);
469 cont = node.falseContinuation;
470 assert(cont.parameters.isEmpty);
471 elseStatement = cont.hasExactlyOneUse
472 ? translateExpression(cont.body)
473 : new Break(labels[cont]);
474 return new If(
475 condition, thenStatement, elseStatement, node.sourceInformation);
476 }
477
478 /************************** PRIMITIVES **************************/
479 //
480 // Visit methods for primitives must return an expression.
481 //
482
483 Expression visitSetField(cps_ir.SetField node) {
484 return new SetField(getVariableUse(node.objectRef), node.field,
485 getVariableUse(node.valueRef), node.sourceInformation);
486 }
487
488 Expression visitInterceptor(cps_ir.Interceptor node) {
489 return new Interceptor(getVariableUse(node.inputRef),
490 node.interceptedClasses, node.sourceInformation);
491 }
492
493 Expression visitCreateInstance(cps_ir.CreateInstance node) {
494 return new CreateInstance(
495 node.classElement,
496 translateArguments(node.argumentRefs),
497 getVariableUseOrNull(node.typeInformationRef),
498 node.sourceInformation);
499 }
500
501 Expression visitGetField(cps_ir.GetField node) {
502 return new GetField(
503 getVariableUse(node.objectRef), node.field, node.sourceInformation,
504 objectIsNotNull: !node.object.type.isNullable);
505 }
506
507 Expression visitCreateBox(cps_ir.CreateBox node) {
508 return new CreateBox();
509 }
510
511 Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
512 return new CreateInvocationMirror(
513 node.selector, translateArguments(node.argumentRefs));
514 }
515
516 Expression visitGetMutable(cps_ir.GetMutable node) {
517 return getMutableVariableUse(node.variableRef, node.sourceInformation);
518 }
519
520 Expression visitSetMutable(cps_ir.SetMutable node) {
521 Variable variable = getMutableVariable(node.variable);
522 Expression value = getVariableUse(node.valueRef);
523 return new Assign(variable, value,
524 sourceInformation: node.sourceInformation);
525 }
526
527 Expression visitConstant(cps_ir.Constant node) {
528 return new Constant(node.value, sourceInformation: node.sourceInformation);
529 }
530
531 Expression visitLiteralList(cps_ir.LiteralList node) {
532 return new LiteralList(node.dartType, translateArguments(node.valueRefs));
533 }
534
535 Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
536 return new ReifyRuntimeType(
537 getVariableUse(node.valueRef), node.sourceInformation);
538 }
539
540 Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
541 return new ReadTypeVariable(
542 node.variable, getVariableUse(node.targetRef), node.sourceInformation);
543 }
544
545 Expression visitTypeExpression(cps_ir.TypeExpression node) {
546 return new TypeExpression(node.kind, node.dartType,
547 node.argumentRefs.map(getVariableUse).toList());
548 }
549
550 Expression visitTypeTest(cps_ir.TypeTest node) {
551 Expression value = getVariableUse(node.valueRef);
552 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
553 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true);
554 }
555
556 Expression visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
557 Expression value = getVariableUse(node.interceptorRef);
558 // TODO(sra): Move !! to cps_ir level.
559 return new Not(new Not(new GetTypeTestProperty(value, node.dartType)));
560 }
561
562 Expression visitGetStatic(cps_ir.GetStatic node) {
563 return new GetStatic(node.element, node.sourceInformation);
564 }
565
566 Expression visitSetStatic(cps_ir.SetStatic node) {
567 return new SetStatic(
568 node.element, getVariableUse(node.valueRef), node.sourceInformation);
569 }
570
571 Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
572 if (node.operator == BuiltinOperator.IsFalsy) {
573 return new Not(getVariableUse(node.argumentRefs.single));
574 }
575 return new ApplyBuiltinOperator(node.operator,
576 translateArguments(node.argumentRefs), node.sourceInformation);
577 }
578
579 Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
580 return new ApplyBuiltinMethod(node.method, getVariableUse(node.receiverRef),
581 translateArguments(node.argumentRefs),
582 receiverIsNotNull: !node.receiver.type.isNullable);
583 }
584
585 Expression visitGetLength(cps_ir.GetLength node) {
586 return new GetLength(getVariableUse(node.objectRef));
587 }
588
589 Expression visitGetIndex(cps_ir.GetIndex node) {
590 return new GetIndex(
591 getVariableUse(node.objectRef), getVariableUse(node.indexRef));
592 }
593
594 Expression visitSetIndex(cps_ir.SetIndex node) {
595 return new SetIndex(getVariableUse(node.objectRef),
596 getVariableUse(node.indexRef), getVariableUse(node.valueRef));
597 }
598
599 Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
600 List<Expression> arguments = translateArguments(node.argumentRefs);
601 return new InvokeStatic(
602 node.target, node.selector, arguments, node.sourceInformation);
603 }
604
605 List<Expression> insertReceiverArgument(
606 Expression receiver, List<Expression> arguments) {
607 return new List<Expression>.generate(
608 arguments.length + 1, (n) => n == 0 ? receiver : arguments[n - 1],
609 growable: false);
610 }
611
612 Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
613 switch (node.callingConvention) {
614 case cps_ir.CallingConvention.Normal:
615 InvokeMethod invoke = new InvokeMethod(
616 getVariableUse(node.receiverRef),
617 node.selector,
618 node.mask,
619 translateArguments(node.argumentRefs),
620 node.sourceInformation);
621 invoke.receiverIsNotNull = !node.receiver.type.isNullable;
622 return invoke;
623
624 case cps_ir.CallingConvention.Intercepted:
625 List<Expression> arguments = insertReceiverArgument(
626 getVariableUse(node.receiverRef),
627 translateArguments(node.argumentRefs));
628 InvokeMethod invoke = new InvokeMethod(
629 getVariableUse(node.interceptorRef),
630 node.selector,
631 node.mask,
632 arguments,
633 node.sourceInformation);
634 // Sometimes we know the Dart receiver is non-null because it has been
635 // refined, which implies that the JS receiver also can not be null at
636 // the use-site. Interceptors are not refined, so this information is
637 // not always available on the JS receiver.
638 // Also check the JS receiver's type, however, because sometimes we know
639 // an interceptor is non-null because it intercepts JSNull.
640 invoke.receiverIsNotNull =
641 !node.receiver.type.isNullable || !node.interceptor.type.isNullable;
642 return invoke;
643
644 case cps_ir.CallingConvention.DummyIntercepted:
645 List<Expression> arguments = insertReceiverArgument(
646 new Constant(new IntConstantValue(0)),
647 translateArguments(node.argumentRefs));
648 InvokeMethod invoke = new InvokeMethod(getVariableUse(node.receiverRef),
649 node.selector, node.mask, arguments, node.sourceInformation);
650 invoke.receiverIsNotNull = !node.receiver.type.isNullable;
651 return invoke;
652
653 case cps_ir.CallingConvention.OneShotIntercepted:
654 List<Expression> arguments = insertReceiverArgument(
655 getVariableUse(node.receiverRef),
656 translateArguments(node.argumentRefs));
657 return new OneShotInterceptor(
658 node.selector, node.mask, arguments, node.sourceInformation);
659 }
660 }
661
662 Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
663 if (node.interceptorRef != null) {
664 return new InvokeMethodDirectly(
665 getVariableUse(node.interceptorRef),
666 node.target,
667 node.selector,
668 insertReceiverArgument(getVariableUse(node.receiverRef),
669 translateArguments(node.argumentRefs)),
670 node.sourceInformation);
671 } else {
672 return new InvokeMethodDirectly(
673 getVariableUse(node.receiverRef),
674 node.target,
675 node.selector,
676 translateArguments(node.argumentRefs),
677 node.sourceInformation);
678 }
679 }
680
681 Expression visitTypeCast(cps_ir.TypeCast node) {
682 Expression value = getVariableUse(node.valueRef);
683 List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
684 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
685 }
686
687 Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
688 List<Expression> arguments = translateArguments(node.argumentRefs);
689 return new InvokeConstructor(node.dartType, node.target, node.selector,
690 arguments, node.sourceInformation);
691 }
692
693 visitForeignCode(cps_ir.ForeignCode node) {
694 List<Expression> arguments =
695 node.argumentRefs.map(getVariableUse).toList(growable: false);
696 List<bool> nullableArguments = node.argumentRefs
697 .map((argument) => argument.definition.type.isNullable)
698 .toList(growable: false);
699 if (node.codeTemplate.isExpression) {
700 return new ForeignExpression(
701 node.codeTemplate,
702 node.type,
703 arguments,
704 node.nativeBehavior,
705 nullableArguments,
706 node.dependency,
707 node.sourceInformation);
708 } else {
709 return (Statement next) {
710 assert(next is Unreachable); // We are not using the `next` statement.
711 return new ForeignStatement(
712 node.codeTemplate,
713 node.type,
714 arguments,
715 node.nativeBehavior,
716 nullableArguments,
717 node.dependency,
718 node.sourceInformation);
719 };
720 }
721 }
722
723 visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) {
724 // The CPS IR uses 'isNullCheck' because the semantics are important.
725 // In the Tree IR, syntax is more important, so the receiver check uses
726 // "useInvoke" to denote if an invocation should be emitted.
727 return new ReceiverCheck(
728 condition: getVariableUseOrNull(node.conditionRef),
729 value: getVariableUse(node.valueRef),
730 selector: node.selector,
731 useSelector: node.useSelector,
732 useInvoke: !node.isNullCheck,
733 next: next,
734 sourceInformation: node.sourceInformation);
735 };
736
737 Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) {
738 return new GetStatic.lazy(node.element, node.sourceInformation);
739 }
740
741 @override
742 NodeCallback visitYield(cps_ir.Yield node) {
743 return (Statement next) {
744 return new Yield(getVariableUse(node.inputRef), node.hasStar, next);
745 };
746 }
747
748 @override
749 Expression visitAwait(cps_ir.Await node) {
750 return new Await(getVariableUse(node.inputRef));
751 }
752
753 @override
754 visitRefinement(cps_ir.Refinement node) {
755 return (Statement next) => next; // Compile to nothing.
756 }
757
758 /********** UNUSED VISIT METHODS *************/
759
760 unexpectedNode(cps_ir.Node node) {
761 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node');
762 }
763
764 visitFunctionDefinition(cps_ir.FunctionDefinition node) {
765 unexpectedNode(node);
766 }
767
768 visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
769 visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
770 visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
771 visitRethrow(cps_ir.Rethrow node) => unexpectedNode(node);
772 visitBoundsCheck(cps_ir.BoundsCheck node) => unexpectedNode(node);
773 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698