| 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 324f45f2b3fde2cb330595186fed02b34b229ed7..a9d3c200940609d347f2526ded374a1d2abc698f 100644
|
| --- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| +++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
|
| @@ -9,6 +9,7 @@ import '../constants/values.dart';
|
| import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
|
| import '../elements/elements.dart';
|
| import 'package:js_ast/js_ast.dart' as js;
|
| +import '../js_backend/codegen/glue.dart';
|
|
|
| import 'tree_ir_nodes.dart';
|
|
|
| @@ -48,6 +49,7 @@ typedef Statement NodeCallback(Statement next);
|
| */
|
| class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| final InternalErrorFunction internalError;
|
| + final Glue glue;
|
|
|
| final Map<cps_ir.Primitive, Variable> primitive2variable =
|
| <cps_ir.Primitive, Variable>{};
|
| @@ -60,17 +62,12 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
|
|
|
| ExecutableElement currentElement;
|
| - /// The 'this' Parameter for currentElement or the enclosing method.
|
| + /// 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;
|
| cps_ir.Continuation returnContinuation;
|
|
|
| - Builder parent;
|
| -
|
| - Builder(this.internalError, [this.parent]);
|
| -
|
| - Builder createInnerBuilder() {
|
| - return new Builder(internalError, this);
|
| - }
|
| + Builder(this.internalError, this.glue);
|
|
|
| /// Variable used in [buildPhiAssignments] as a temporary when swapping
|
| /// variables.
|
| @@ -84,9 +81,6 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| }
|
|
|
| Variable getMutableVariable(cps_ir.MutableVariable mutableVariable) {
|
| - if (!mutable2variable.containsKey(mutableVariable)) {
|
| - return parent.getMutableVariable(mutableVariable)..isCaptured = true;
|
| - }
|
| return mutable2variable[mutableVariable];
|
| }
|
|
|
| @@ -128,20 +122,17 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| return labels.putIfAbsent(cont, () => new Label());
|
| }
|
|
|
| - Variable addFunctionParameter(cps_ir.Parameter parameter) {
|
| - return getVariable(parameter);
|
| - }
|
| -
|
| FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
|
| currentElement = node.element;
|
| - if (parent != null) {
|
| - // Local function's 'this' refers to enclosing method's 'this'
|
| - thisParameter = parent.thisParameter;
|
| + List<Variable> parameters = node.parameters.map(getVariable).toList();
|
| + if (node.interceptorParameter != null) {
|
| + parameters.insert(0, getVariable(node.receiverParameter));
|
| + thisParameter = glue.methodUsesReceiverArgument(node.element)
|
| + ? node.interceptorParameter
|
| + : node.receiverParameter;
|
| } else {
|
| - thisParameter = node.thisParameter;
|
| + thisParameter = node.receiverParameter;
|
| }
|
| - List<Variable> parameters =
|
| - node.parameters.map(addFunctionParameter).toList();
|
| returnContinuation = node.returnContinuation;
|
| phiTempVar = new Variable(node.element, null);
|
| Statement body = translateExpression(node.body);
|
| @@ -621,38 +612,86 @@ class Builder implements cps_ir.Visitor/*<NodeCallback|Node>*/ {
|
| 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],
|
| + growable: false);
|
| + }
|
| +
|
| Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
|
| - if (node.callingConvention == cps_ir.CallingConvention.OneShotIntercepted) {
|
| - List<Expression> arguments = new List.generate(
|
| - 1 + node.argumentRefs.length,
|
| - (n) => getVariableUse(n == 0 ? node.receiverRef : node.argumentRefs[n - 1]),
|
| - growable: false);
|
| - return new OneShotInterceptor(node.selector, node.mask, arguments,
|
| - node.sourceInformation);
|
| + switch (node.callingConvention) {
|
| + case cps_ir.CallingConvention.Normal:
|
| + InvokeMethod invoke = new InvokeMethod(
|
| + getVariableUse(node.receiverRef),
|
| + node.selector,
|
| + node.mask,
|
| + translateArguments(node.argumentRefs),
|
| + node.sourceInformation);
|
| + invoke.receiverIsNotNull = !node.receiver.type.isNullable;
|
| + return invoke;
|
| +
|
| + case cps_ir.CallingConvention.Intercepted:
|
| + List<Expression> arguments = insertReceiverArgument(
|
| + getVariableUse(node.receiverRef),
|
| + translateArguments(node.argumentRefs));
|
| + InvokeMethod invoke = new InvokeMethod(
|
| + getVariableUse(node.interceptorRef),
|
| + node.selector,
|
| + node.mask,
|
| + arguments,
|
| + node.sourceInformation);
|
| + // Sometimes we know the Dart receiver is non-null because it has been
|
| + // refined, which implies that the JS receiver also can not be null at
|
| + // the use-site. Interceptors are not refined, so this information is
|
| + // not always available on the JS receiver.
|
| + // 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;
|
| + 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);
|
| + invoke.receiverIsNotNull = !node.receiver.type.isNullable;
|
| + return invoke;
|
| +
|
| + case cps_ir.CallingConvention.OneShotIntercepted:
|
| + List<Expression> arguments = insertReceiverArgument(
|
| + getVariableUse(node.receiverRef),
|
| + translateArguments(node.argumentRefs));
|
| + return new OneShotInterceptor(
|
| + node.selector,
|
| + node.mask,
|
| + arguments,
|
| + node.sourceInformation);
|
| }
|
| - InvokeMethod invoke = new InvokeMethod(
|
| - getVariableUse(node.receiverRef),
|
| - node.selector,
|
| - node.mask,
|
| - translateArguments(node.argumentRefs),
|
| - node.sourceInformation);
|
| - // Sometimes we know the Dart receiver is non-null because it has been
|
| - // refined, which implies that the JS receiver also can not be null at the
|
| - // use-site. Interceptors are not refined, so this information is not
|
| - // always available on the JS receiver.
|
| - // Also check the JS receiver's type, however, because sometimes we know an
|
| - // interceptor is non-null because it intercepts JSNull.
|
| - invoke.receiverIsNotNull =
|
| - !node.dartReceiver.type.isNullable ||
|
| - !node.receiver.type.isNullable;
|
| - return invoke;
|
| }
|
|
|
| Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
|
| - Expression receiver = getVariableUse(node.receiverRef);
|
| - List<Expression> arguments = translateArguments(node.argumentRefs);
|
| - return new InvokeMethodDirectly(receiver, node.target,
|
| - node.selector, arguments, node.sourceInformation);
|
| + if (node.interceptorRef != null) {
|
| + 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),
|
| + node.target,
|
| + node.selector,
|
| + translateArguments(node.argumentRefs),
|
| + node.sourceInformation);
|
| + }
|
| }
|
|
|
| Expression visitTypeCast(cps_ir.TypeCast node) {
|
|
|