| Index: pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| index 99fb09970f84bf7c94696154d51259456c526da4..000f61074513787bc6b6e779b8960bf013ff9a4f 100644
|
| --- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| +++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| @@ -62,6 +62,7 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
|
|
|
| ExecutableElement currentElement;
|
| +
|
| /// The parameter to be translated to 'this'. This can either be the receiver
|
| /// parameter, the interceptor parameter, or null if the method has neither.
|
| cps_ir.Parameter thisParameter;
|
| @@ -85,8 +86,8 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| VariableUse getMutableVariableUse(
|
| - cps_ir.Reference<cps_ir.MutableVariable> reference,
|
| - SourceInformation sourceInformation) {
|
| + cps_ir.Reference<cps_ir.MutableVariable> reference,
|
| + SourceInformation sourceInformation) {
|
| Variable variable = getMutableVariable(reference.definition);
|
| return new VariableUse(variable, sourceInformation: sourceInformation);
|
| }
|
| @@ -95,8 +96,8 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| /// primitives that have no reference and do not need a variable.
|
| Variable getVariable(cps_ir.Primitive primitive) {
|
| primitive = primitive.effectiveDefinition;
|
| - return primitive2variable.putIfAbsent(primitive,
|
| - () => new Variable(currentElement, primitive.hint));
|
| + return primitive2variable.putIfAbsent(
|
| + primitive, () => new Variable(currentElement, primitive.hint));
|
| }
|
|
|
| /// Obtains a reference to the tree Variable corresponding to the IR primitive
|
| @@ -104,7 +105,7 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| /// This increments the reference count for the given variable, so the
|
| /// returned expression must be used in the tree.
|
| Expression getVariableUse(cps_ir.Reference<cps_ir.Primitive> reference,
|
| - {SourceInformation sourceInformation}) {
|
| + {SourceInformation sourceInformation}) {
|
| cps_ir.Primitive prim = reference.definition.effectiveDefinition;
|
| if (prim is cps_ir.Constant && inlinedConstants.contains(prim)) {
|
| return new Constant(prim.value);
|
| @@ -112,12 +113,12 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| if (thisParameter != null && prim == thisParameter) {
|
| return new This();
|
| }
|
| - return new VariableUse(
|
| - getVariable(prim), sourceInformation: sourceInformation);
|
| + return new VariableUse(getVariable(prim),
|
| + sourceInformation: sourceInformation);
|
| }
|
|
|
| Expression getVariableUseOrNull(
|
| - cps_ir.Reference<cps_ir.Primitive> reference) {
|
| + cps_ir.Reference<cps_ir.Primitive> reference) {
|
| return reference == null ? null : getVariableUse(reference);
|
| }
|
|
|
| @@ -151,17 +152,15 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| /// The list will be typed as a list of [Expression] to allow inplace updates
|
| /// on the list during the rewrite phases.
|
| List<Expression> translateArguments(List<cps_ir.Reference> args) {
|
| - return new List<Expression>.generate(args.length,
|
| - (int index) => getVariableUse(args[index]),
|
| - growable: false);
|
| + return new List<Expression>.generate(
|
| + args.length, (int index) => getVariableUse(args[index]),
|
| + growable: false);
|
| }
|
|
|
| /// Simultaneously assigns each argument to the corresponding parameter,
|
| /// then continues at the statement created by [buildRest].
|
| - Statement buildPhiAssignments(
|
| - List<cps_ir.Parameter> parameters,
|
| - List<Expression> arguments,
|
| - Statement buildRest()) {
|
| + Statement buildPhiAssignments(List<cps_ir.Parameter> parameters,
|
| + List<Expression> arguments, Statement buildRest()) {
|
| assert(parameters.length == arguments.length);
|
| // We want a parallel assignment to all parameters simultaneously.
|
| // Since we do not have parallel assignments in dart_tree, we must linearize
|
| @@ -217,7 +216,8 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| // The temporary will then be used as right-hand side when the
|
| // assignment gets added.
|
| VariableUse source = assignmentSrc[i];
|
| - if (source.variable != phiTempVar) { // Only move to temporary once.
|
| + if (source.variable != phiTempVar) {
|
| + // Only move to temporary once.
|
| assignmentSrc[i] = new VariableUse(phiTempVar);
|
| addAssignment(phiTempVar, arg);
|
| }
|
| @@ -364,30 +364,28 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| // of the non-recursive continuation invocation.
|
| // See [visitInvokeContinuation] for the implementation.
|
| NodeCallback visitLetCont(cps_ir.LetCont node) => (Statement next) {
|
| - for (cps_ir.Continuation continuation in node.continuations) {
|
| - // This happens after the body of the LetCont has been translated.
|
| - // Labels are created on-demand if the continuation could not be inlined,
|
| - // so the existence of the label indicates if a labeled statement should
|
| - // be emitted.
|
| - Label label = labels[continuation];
|
| - if (label != null && !continuation.isRecursive) {
|
| - // Recursively build the body. We only do this for join continuations,
|
| - // so we should not risk overly deep recursion.
|
| - next = new LabeledStatement(
|
| - label,
|
| - next,
|
| - translateExpression(continuation.body));
|
| - }
|
| - }
|
| - return next;
|
| - };
|
| + for (cps_ir.Continuation continuation in node.continuations) {
|
| + // This happens after the body of the LetCont has been translated.
|
| + // Labels are created on-demand if the continuation could not be inlined,
|
| + // so the existence of the label indicates if a labeled statement should
|
| + // be emitted.
|
| + Label label = labels[continuation];
|
| + if (label != null && !continuation.isRecursive) {
|
| + // Recursively build the body. We only do this for join continuations,
|
| + // so we should not risk overly deep recursion.
|
| + next = new LabeledStatement(
|
| + label, next, translateExpression(continuation.body));
|
| + }
|
| + }
|
| + return next;
|
| + };
|
|
|
| NodeCallback visitLetHandler(cps_ir.LetHandler node) => (Statement next) {
|
| - List<Variable> catchParameters =
|
| - node.handler.parameters.map(getVariable).toList();
|
| - Statement catchBody = translateExpression(node.handler.body);
|
| - return new Try(next, catchParameters, catchBody);
|
| - };
|
| + List<Variable> catchParameters =
|
| + node.handler.parameters.map(getVariable).toList();
|
| + Statement catchBody = translateExpression(node.handler.body);
|
| + return new Try(next, catchParameters, catchBody);
|
| + };
|
|
|
| NodeCallback visitLetMutable(cps_ir.LetMutable node) {
|
| Variable variable = addMutableVariable(node.variable);
|
| @@ -419,40 +417,38 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| if (cont == returnContinuation) {
|
| assert(node.argumentRefs.length == 1);
|
| return new Return(getVariableUse(node.argumentRefs.single),
|
| - sourceInformation: node.sourceInformation);
|
| + sourceInformation: node.sourceInformation);
|
| } else {
|
| List<Expression> arguments = translateArguments(node.argumentRefs);
|
| - return buildPhiAssignments(cont.parameters, arguments,
|
| - () {
|
| - // Translate invocations of recursive and non-recursive
|
| - // continuations differently.
|
| - // * Non-recursive continuations
|
| - // - If there is one use, translate the continuation body
|
| - // inline at the invocation site.
|
| - // - If there are multiple uses, translate to Break.
|
| - // * Recursive continuations
|
| - // - There is a single non-recursive invocation. Translate
|
| - // the continuation body inline as a labeled loop at the
|
| - // invocation site.
|
| - // - Translate the recursive invocations to Continue.
|
| - if (cont.isRecursive) {
|
| - return node.isRecursive
|
| - ? new Continue(getLabel(cont))
|
| - : new WhileTrue(getLabel(cont),
|
| - translateExpression(cont.body));
|
| - } else {
|
| - return cont.hasExactlyOneUse && !node.isEscapingTry
|
| - ? translateExpression(cont.body)
|
| - : new Break(getLabel(cont));
|
| - }
|
| - });
|
| + return buildPhiAssignments(cont.parameters, arguments, () {
|
| + // Translate invocations of recursive and non-recursive
|
| + // continuations differently.
|
| + // * Non-recursive continuations
|
| + // - If there is one use, translate the continuation body
|
| + // inline at the invocation site.
|
| + // - If there are multiple uses, translate to Break.
|
| + // * Recursive continuations
|
| + // - There is a single non-recursive invocation. Translate
|
| + // the continuation body inline as a labeled loop at the
|
| + // invocation site.
|
| + // - Translate the recursive invocations to Continue.
|
| + if (cont.isRecursive) {
|
| + return node.isRecursive
|
| + ? new Continue(getLabel(cont))
|
| + : new WhileTrue(getLabel(cont), translateExpression(cont.body));
|
| + } else {
|
| + return cont.hasExactlyOneUse && !node.isEscapingTry
|
| + ? translateExpression(cont.body)
|
| + : new Break(getLabel(cont));
|
| + }
|
| + });
|
| }
|
| }
|
|
|
| /// Translates a branch condition to a tree expression.
|
| Expression translateCondition(cps_ir.Branch branch) {
|
| - Expression value = getVariableUse(
|
| - branch.conditionRef, sourceInformation: branch.sourceInformation);
|
| + Expression value = getVariableUse(branch.conditionRef,
|
| + sourceInformation: branch.sourceInformation);
|
| if (branch.isStrictCheck) {
|
| return new ApplyBuiltinOperator(
|
| BuiltinOperator.StrictEq,
|
| @@ -480,23 +476,19 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| condition, thenStatement, elseStatement, node.sourceInformation);
|
| }
|
|
|
| -
|
| /************************** PRIMITIVES **************************/
|
| //
|
| // Visit methods for primitives must return an expression.
|
| //
|
|
|
| Expression visitSetField(cps_ir.SetField node) {
|
| - return new SetField(getVariableUse(node.objectRef),
|
| - node.field,
|
| - getVariableUse(node.valueRef),
|
| - node.sourceInformation);
|
| + return new SetField(getVariableUse(node.objectRef), node.field,
|
| + getVariableUse(node.valueRef), node.sourceInformation);
|
| }
|
|
|
| Expression visitInterceptor(cps_ir.Interceptor node) {
|
| return new Interceptor(getVariableUse(node.inputRef),
|
| - node.interceptedClasses,
|
| - node.sourceInformation);
|
| + node.interceptedClasses, node.sourceInformation);
|
| }
|
|
|
| Expression visitCreateInstance(cps_ir.CreateInstance node) {
|
| @@ -508,8 +500,9 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| Expression visitGetField(cps_ir.GetField node) {
|
| - return new GetField(getVariableUse(node.objectRef), node.field,
|
| - node.sourceInformation, objectIsNotNull: !node.object.type.isNullable);
|
| + return new GetField(
|
| + getVariableUse(node.objectRef), node.field, node.sourceInformation,
|
| + objectIsNotNull: !node.object.type.isNullable);
|
| }
|
|
|
| Expression visitCreateBox(cps_ir.CreateBox node) {
|
| @@ -518,8 +511,7 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
|
|
| Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
|
| return new CreateInvocationMirror(
|
| - node.selector,
|
| - translateArguments(node.argumentRefs));
|
| + node.selector, translateArguments(node.argumentRefs));
|
| }
|
|
|
| Expression visitGetMutable(cps_ir.GetMutable node) {
|
| @@ -529,8 +521,8 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| Expression visitSetMutable(cps_ir.SetMutable node) {
|
| Variable variable = getMutableVariable(node.variable);
|
| Expression value = getVariableUse(node.valueRef);
|
| - return new Assign(
|
| - variable, value, sourceInformation: node.sourceInformation);
|
| + return new Assign(variable, value,
|
| + sourceInformation: node.sourceInformation);
|
| }
|
|
|
| Expression visitConstant(cps_ir.Constant node) {
|
| @@ -538,9 +530,7 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| Expression visitLiteralList(cps_ir.LiteralList node) {
|
| - return new LiteralList(
|
| - node.dartType,
|
| - translateArguments(node.valueRefs));
|
| + return new LiteralList(node.dartType, translateArguments(node.valueRefs));
|
| }
|
|
|
| Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
|
| @@ -550,15 +540,11 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
|
|
| Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
|
| return new ReadTypeVariable(
|
| - node.variable,
|
| - getVariableUse(node.targetRef),
|
| - node.sourceInformation);
|
| + node.variable, getVariableUse(node.targetRef), node.sourceInformation);
|
| }
|
|
|
| Expression visitTypeExpression(cps_ir.TypeExpression node) {
|
| - return new TypeExpression(
|
| - node.kind,
|
| - node.dartType,
|
| + return new TypeExpression(node.kind, node.dartType,
|
| node.argumentRefs.map(getVariableUse).toList());
|
| }
|
|
|
| @@ -580,24 +566,19 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
|
|
| Expression visitSetStatic(cps_ir.SetStatic node) {
|
| return new SetStatic(
|
| - node.element,
|
| - getVariableUse(node.valueRef),
|
| - node.sourceInformation);
|
| + node.element, getVariableUse(node.valueRef), node.sourceInformation);
|
| }
|
|
|
| Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
|
| if (node.operator == BuiltinOperator.IsFalsy) {
|
| return new Not(getVariableUse(node.argumentRefs.single));
|
| }
|
| - return new ApplyBuiltinOperator(
|
| - node.operator,
|
| - translateArguments(node.argumentRefs),
|
| - node.sourceInformation);
|
| + return new ApplyBuiltinOperator(node.operator,
|
| + translateArguments(node.argumentRefs), node.sourceInformation);
|
| }
|
|
|
| Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
|
| - return new ApplyBuiltinMethod(node.method,
|
| - getVariableUse(node.receiverRef),
|
| + return new ApplyBuiltinMethod(node.method, getVariableUse(node.receiverRef),
|
| translateArguments(node.argumentRefs),
|
| receiverIsNotNull: !node.receiver.type.isNullable);
|
| }
|
| @@ -607,26 +588,25 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| Expression visitGetIndex(cps_ir.GetIndex node) {
|
| - return new GetIndex(getVariableUse(node.objectRef),
|
| - getVariableUse(node.indexRef));
|
| + return new GetIndex(
|
| + getVariableUse(node.objectRef), getVariableUse(node.indexRef));
|
| }
|
|
|
| Expression visitSetIndex(cps_ir.SetIndex node) {
|
| return new SetIndex(getVariableUse(node.objectRef),
|
| - getVariableUse(node.indexRef),
|
| - getVariableUse(node.valueRef));
|
| + getVariableUse(node.indexRef), getVariableUse(node.valueRef));
|
| }
|
|
|
| Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
|
| List<Expression> arguments = translateArguments(node.argumentRefs);
|
| - return new InvokeStatic(node.target, node.selector, arguments,
|
| - node.sourceInformation);
|
| + return new InvokeStatic(
|
| + node.target, node.selector, arguments, node.sourceInformation);
|
| }
|
|
|
| - List<Expression> insertReceiverArgument(Expression receiver,
|
| - List<Expression> arguments) {
|
| - return new List<Expression>.generate(arguments.length + 1,
|
| - (n) => n == 0 ? receiver : arguments[n - 1],
|
| + List<Expression> insertReceiverArgument(
|
| + Expression receiver, List<Expression> arguments) {
|
| + return new List<Expression>.generate(
|
| + arguments.length + 1, (n) => n == 0 ? receiver : arguments[n - 1],
|
| growable: false);
|
| }
|
|
|
| @@ -659,20 +639,15 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| // Also check the JS receiver's type, however, because sometimes we know
|
| // an interceptor is non-null because it intercepts JSNull.
|
| invoke.receiverIsNotNull =
|
| - !node.receiver.type.isNullable ||
|
| - !node.interceptor.type.isNullable;
|
| + !node.receiver.type.isNullable || !node.interceptor.type.isNullable;
|
| return invoke;
|
|
|
| case cps_ir.CallingConvention.DummyIntercepted:
|
| List<Expression> arguments = insertReceiverArgument(
|
| new Constant(new IntConstantValue(0)),
|
| translateArguments(node.argumentRefs));
|
| - InvokeMethod invoke = new InvokeMethod(
|
| - getVariableUse(node.receiverRef),
|
| - node.selector,
|
| - node.mask,
|
| - arguments,
|
| - node.sourceInformation);
|
| + InvokeMethod invoke = new InvokeMethod(getVariableUse(node.receiverRef),
|
| + node.selector, node.mask, arguments, node.sourceInformation);
|
| invoke.receiverIsNotNull = !node.receiver.type.isNullable;
|
| return invoke;
|
|
|
| @@ -681,23 +656,22 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| getVariableUse(node.receiverRef),
|
| translateArguments(node.argumentRefs));
|
| return new OneShotInterceptor(
|
| - node.selector,
|
| - node.mask,
|
| - arguments,
|
| - node.sourceInformation);
|
| + node.selector, node.mask, arguments, node.sourceInformation);
|
| }
|
| }
|
|
|
| Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
|
| if (node.interceptorRef != null) {
|
| - return new InvokeMethodDirectly(getVariableUse(node.interceptorRef),
|
| + return new InvokeMethodDirectly(
|
| + getVariableUse(node.interceptorRef),
|
| node.target,
|
| node.selector,
|
| insertReceiverArgument(getVariableUse(node.receiverRef),
|
| translateArguments(node.argumentRefs)),
|
| node.sourceInformation);
|
| } else {
|
| - return new InvokeMethodDirectly(getVariableUse(node.receiverRef),
|
| + return new InvokeMethodDirectly(
|
| + getVariableUse(node.receiverRef),
|
| node.target,
|
| node.selector,
|
| translateArguments(node.argumentRefs),
|
| @@ -713,12 +687,8 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
|
|
| Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
|
| List<Expression> arguments = translateArguments(node.argumentRefs);
|
| - return new InvokeConstructor(
|
| - node.dartType,
|
| - node.target,
|
| - node.selector,
|
| - arguments,
|
| - node.sourceInformation);
|
| + return new InvokeConstructor(node.dartType, node.target, node.selector,
|
| + arguments, node.sourceInformation);
|
| }
|
|
|
| visitForeignCode(cps_ir.ForeignCode node) {
|
| @@ -752,18 +722,18 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) {
|
| - // The CPS IR uses 'isNullCheck' because the semantics are important.
|
| - // In the Tree IR, syntax is more important, so the receiver check uses
|
| - // "useInvoke" to denote if an invocation should be emitted.
|
| - return new ReceiverCheck(
|
| - condition: getVariableUseOrNull(node.conditionRef),
|
| - value: getVariableUse(node.valueRef),
|
| - selector: node.selector,
|
| - useSelector: node.useSelector,
|
| - useInvoke: !node.isNullCheck,
|
| - next: next,
|
| - sourceInformation: node.sourceInformation);
|
| - };
|
| + // The CPS IR uses 'isNullCheck' because the semantics are important.
|
| + // In the Tree IR, syntax is more important, so the receiver check uses
|
| + // "useInvoke" to denote if an invocation should be emitted.
|
| + return new ReceiverCheck(
|
| + condition: getVariableUseOrNull(node.conditionRef),
|
| + value: getVariableUse(node.valueRef),
|
| + selector: node.selector,
|
| + useSelector: node.useSelector,
|
| + useInvoke: !node.isNullCheck,
|
| + next: next,
|
| + sourceInformation: node.sourceInformation);
|
| + };
|
|
|
| Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) {
|
| return new GetStatic.lazy(node.element, node.sourceInformation);
|
| @@ -795,6 +765,7 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| visitFunctionDefinition(cps_ir.FunctionDefinition node) {
|
| unexpectedNode(node);
|
| }
|
| +
|
| visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
|
| visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
|
| visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
|
|
|