| Index: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| index 50e84bdfec263e44e83d33db2ab1904f3cc69187..f80d8d4a127add876af20edac72d2b71c857ad69 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
|
| @@ -123,12 +123,6 @@ abstract class InteriorExpression extends Expression implements InteriorNode {
|
| }
|
| }
|
|
|
| -/// An expression that passes a continuation to a call.
|
| -abstract class CallExpression extends Expression {
|
| - Reference<Continuation> get continuation;
|
| - Expression get next => continuation.definition.body;
|
| -}
|
| -
|
| /// An expression without a continuation or a subexpression body.
|
| ///
|
| /// These break straight-line control flow and can be thought of as ending a
|
| @@ -149,19 +143,21 @@ abstract class Definition<T extends Definition<T>> extends Node {
|
| bool get hasAtLeastOneUse => firstRef != null;
|
| bool get hasMultipleUses => !hasAtMostOneUse;
|
|
|
| - void substituteFor(Definition<T> other) {
|
| - if (other == this) return;
|
| - if (other.hasNoUses) return;
|
| - Reference<T> previous, current = other.firstRef;
|
| + void replaceUsesWith(Definition<T> newDefinition) {
|
| + if (newDefinition == this) return;
|
| + if (hasNoUses) return;
|
| + Reference<T> previous, current = firstRef;
|
| do {
|
| - current.definition = this;
|
| + current.definition = newDefinition;
|
| previous = current;
|
| current = current.next;
|
| } while (current != null);
|
| - previous.next = firstRef;
|
| - if (firstRef != null) firstRef.previous = previous;
|
| - firstRef = other.firstRef;
|
| - other.firstRef = null;
|
| + previous.next = newDefinition.firstRef;
|
| + if (newDefinition.firstRef != null) {
|
| + newDefinition.firstRef.previous = previous;
|
| + }
|
| + newDefinition.firstRef = firstRef;
|
| + firstRef = null;
|
| }
|
| }
|
|
|
| @@ -268,6 +264,37 @@ abstract class Primitive extends Variable<Primitive> {
|
| assert(hasNoUses);
|
| RemovalVisitor.remove(this);
|
| }
|
| +
|
| + /// Replaces this definition, both at the binding site and at all uses sites.
|
| + ///
|
| + /// This can be thought of as changing the definition of a `let` while
|
| + /// preserving the variable name:
|
| + ///
|
| + /// let x = OLD in BODY
|
| + /// ==>
|
| + /// let x = NEW in BODY
|
| + ///
|
| + void replaceWith(Primitive newDefinition) {
|
| + assert(this is! Parameter);
|
| + assert(newDefinition is! Parameter);
|
| + assert(newDefinition.parent == null);
|
| + replaceUsesWith(newDefinition);
|
| + destroy();
|
| + LetPrim let = parent;
|
| + let.primitive = newDefinition;
|
| + newDefinition.parent = let;
|
| + newDefinition.useElementAsHint(hint);
|
| + }
|
| +}
|
| +
|
| +/// A primitive that is generally not safe for elimination, but may be marked
|
| +/// as safe by type propagation
|
| +//
|
| +// TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this
|
| +// class.
|
| +abstract class UnsafePrimitive extends Primitive {
|
| + bool isSafeForElimination = false;
|
| + bool isSafeForReordering = false;
|
| }
|
|
|
| /// Operands to invocations and primitives are always variables. They point to
|
| @@ -435,35 +462,47 @@ class LetMutable extends InteriorExpression {
|
| /// Discussion:
|
| /// All information in the [selector] is technically redundant; it will likely
|
| /// be removed.
|
| -class InvokeStatic extends CallExpression {
|
| +class InvokeStatic extends UnsafePrimitive {
|
| final FunctionElement target;
|
| final Selector selector;
|
| final List<Reference<Primitive>> arguments;
|
| - final Reference<Continuation> continuation;
|
| final SourceInformation sourceInformation;
|
|
|
| InvokeStatic(this.target,
|
| this.selector,
|
| List<Primitive> args,
|
| - Continuation cont,
|
| [this.sourceInformation])
|
| - : arguments = _referenceList(args),
|
| - continuation = new Reference<Continuation>(cont);
|
| + : arguments = _referenceList(args);
|
|
|
| InvokeStatic.byReference(this.target,
|
| this.selector,
|
| this.arguments,
|
| - this.continuation,
|
| [this.sourceInformation]);
|
|
|
| accept(Visitor visitor) => visitor.visitInvokeStatic(this);
|
|
|
| void setParentPointers() {
|
| _setParentsOnList(arguments, this);
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| +enum CallingConvention {
|
| + /// JS receiver is the Dart receiver, there are no extra arguments.
|
| + ///
|
| + /// For example: `foo.bar$1(x)`
|
| + Normal,
|
| +
|
| + /// JS receiver is an interceptor, the first argument is the Dart receiver.
|
| + ///
|
| + /// For example: `getInterceptor(foo).bar$1(foo, x)`
|
| + Intercepted,
|
| +
|
| + /// JS receiver is the Dart receiver, the first argument is a dummy value.
|
| + ///
|
| + /// For example: `foo.bar$1(0, x)`
|
| + DummyIntercepted,
|
| +}
|
| +
|
| /// Invoke a method on an object.
|
| ///
|
| /// This includes getters, setters, operators, and index getter/setters.
|
| @@ -473,24 +512,30 @@ class InvokeStatic extends CallExpression {
|
| ///
|
| /// The [selector] records the names of named arguments. The value of named
|
| /// arguments occur at the end of the [arguments] list, in normalized order.
|
| -class InvokeMethod extends CallExpression {
|
| +class InvokeMethod extends UnsafePrimitive {
|
| Reference<Primitive> receiver;
|
| Selector selector;
|
| TypeMask mask;
|
| final List<Reference<Primitive>> arguments;
|
| - final Reference<Continuation> continuation;
|
| final SourceInformation sourceInformation;
|
|
|
| - /// If true, the [receiver] is intercepted and the actual receiver is in
|
| - /// the first argument. Otherwise, the [receiver] is the actual receiver.
|
| - ///
|
| - /// This flag is always false for non-intercepted selectors, but it may also
|
| - /// be false for intercepted selectors after dummy receiver optimization
|
| - /// (in this case the first argument is a dummy value).
|
| - ///
|
| - /// It is always false before the unsugaring pass, where interceptors have
|
| - /// not yet been introduced.
|
| - bool receiverIsIntercepted = false;
|
| + CallingConvention callingConvention = CallingConvention.Normal;
|
| +
|
| + Reference<Primitive> get dartReceiverReference {
|
| + return callingConvention == CallingConvention.Intercepted
|
| + ? arguments[0]
|
| + : receiver;
|
| + }
|
| +
|
| + Primitive get dartReceiver => dartReceiverReference.definition;
|
| +
|
| + Reference<Primitive> dartArgumentReference(int n) {
|
| + return callingConvention == CallingConvention.Normal
|
| + ? arguments[n]
|
| + : arguments[n + 1];
|
| + }
|
| +
|
| + Primitive dartArgument(int n) => dartArgumentReference(n).definition;
|
|
|
| /// If true, it is known that the receiver cannot be `null`.
|
| bool receiverIsNotNull = false;
|
| @@ -499,17 +544,14 @@ class InvokeMethod extends CallExpression {
|
| this.selector,
|
| this.mask,
|
| List<Primitive> arguments,
|
| - Continuation continuation,
|
| [this.sourceInformation])
|
| : this.receiver = new Reference<Primitive>(receiver),
|
| - this.arguments = _referenceList(arguments),
|
| - this.continuation = new Reference<Continuation>(continuation);
|
| + this.arguments = _referenceList(arguments);
|
|
|
| InvokeMethod.byReference(this.receiver,
|
| this.selector,
|
| this.mask,
|
| this.arguments,
|
| - this.continuation,
|
| this.sourceInformation);
|
|
|
| accept(Visitor visitor) => visitor.visitInvokeMethod(this);
|
| @@ -517,7 +559,6 @@ class InvokeMethod extends CallExpression {
|
| void setParentPointers() {
|
| receiver.parent = this;
|
| _setParentsOnList(arguments, this);
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -540,30 +581,44 @@ class InvokeMethod extends CallExpression {
|
| ///
|
| /// All optional arguments declared by [target] are passed in explicitly, and
|
| /// occur at the end of [arguments] list, in normalized order.
|
| -class InvokeMethodDirectly extends CallExpression {
|
| +class InvokeMethodDirectly extends UnsafePrimitive {
|
| Reference<Primitive> receiver;
|
| final FunctionElement target;
|
| final Selector selector;
|
| final List<Reference<Primitive>> arguments;
|
| - final Reference<Continuation> continuation;
|
| final SourceInformation sourceInformation;
|
|
|
| + CallingConvention callingConvention = CallingConvention.Normal;
|
| +
|
| + Reference<Primitive> get dartReceiverReference {
|
| + return callingConvention == CallingConvention.Intercepted
|
| + ? arguments[0]
|
| + : receiver;
|
| + }
|
| +
|
| + Primitive get dartReceiver => dartReceiverReference.definition;
|
| +
|
| + Reference<Primitive> dartArgumentReference(int n) {
|
| + return callingConvention == CallingConvention.Normal
|
| + ? arguments[n]
|
| + : arguments[n + 1];
|
| + }
|
| +
|
| + Primitive dartArgument(int n) => dartArgumentReference(n).definition;
|
| +
|
| InvokeMethodDirectly(Primitive receiver,
|
| this.target,
|
| this.selector,
|
| List<Primitive> arguments,
|
| - Continuation continuation,
|
| this.sourceInformation)
|
| : this.receiver = new Reference<Primitive>(receiver),
|
| - this.arguments = _referenceList(arguments),
|
| - this.continuation = new Reference<Continuation>(continuation);
|
| + this.arguments = _referenceList(arguments);
|
|
|
| accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
|
|
|
| void setParentPointers() {
|
| receiver.parent = this;
|
| _setParentsOnList(arguments, this);
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -582,11 +637,10 @@ class InvokeMethodDirectly extends CallExpression {
|
| ///
|
| /// Note that [InvokeConstructor] does it itself allocate an object.
|
| /// The invoked constructor will do that using [CreateInstance].
|
| -class InvokeConstructor extends CallExpression {
|
| +class InvokeConstructor extends UnsafePrimitive {
|
| final DartType dartType;
|
| final ConstructorElement target;
|
| final List<Reference<Primitive>> arguments;
|
| - final Reference<Continuation> continuation;
|
| final Selector selector;
|
| final SourceInformation sourceInformation;
|
|
|
| @@ -601,17 +655,14 @@ class InvokeConstructor extends CallExpression {
|
| this.target,
|
| this.selector,
|
| List<Primitive> args,
|
| - Continuation cont,
|
| this.sourceInformation,
|
| {this.allocationSiteType})
|
| - : arguments = _referenceList(args),
|
| - continuation = new Reference<Continuation>(cont);
|
| + : arguments = _referenceList(args);
|
|
|
| accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
|
|
|
| void setParentPointers() {
|
| _setParentsOnList(arguments, this);
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -719,26 +770,24 @@ class TypeTestViaFlag extends Primitive {
|
| /// [value], which is typically in scope in the continuation. However, it might
|
| /// simplify type propagation, since a better type can be computed for the
|
| /// continuation parameter without needing flow-sensitive analysis.
|
| -class TypeCast extends CallExpression {
|
| +class TypeCast extends UnsafePrimitive {
|
| Reference<Primitive> value;
|
| final DartType dartType;
|
|
|
| /// See the corresponding field on [TypeTest].
|
| final List<Reference<Primitive>> typeArguments;
|
| - final Reference<Continuation> continuation;
|
|
|
| TypeCast(Primitive value,
|
| this.dartType,
|
| - List<Primitive> typeArguments,
|
| - Continuation cont)
|
| + List<Primitive> typeArguments)
|
| : this.value = new Reference<Primitive>(value),
|
| - this.typeArguments = _referenceList(typeArguments),
|
| - this.continuation = new Reference<Continuation>(cont);
|
| + this.typeArguments = _referenceList(typeArguments);
|
|
|
| accept(Visitor visitor) => visitor.visitTypeCast(this);
|
|
|
| void setParentPointers() {
|
| value.parent = this;
|
| + _setParentsOnList(typeArguments, this);
|
| }
|
| }
|
|
|
| @@ -1126,22 +1175,15 @@ class SetStatic extends Primitive {
|
| ///
|
| /// If the field has not yet been initialized, its initializer is evaluated
|
| /// and assigned to the field.
|
| -///
|
| -/// [continuation] is then invoked with the value of the field as argument.
|
| -class GetLazyStatic extends CallExpression {
|
| +class GetLazyStatic extends UnsafePrimitive {
|
| final FieldElement element;
|
| - final Reference<Continuation> continuation;
|
| final SourceInformation sourceInformation;
|
|
|
| - GetLazyStatic(this.element,
|
| - Continuation continuation,
|
| - [this.sourceInformation])
|
| - : continuation = new Reference<Continuation>(continuation);
|
| + GetLazyStatic(this.element, [this.sourceInformation]);
|
|
|
| accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
|
|
|
| void setParentPointers() {
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -1303,24 +1345,21 @@ class CreateInvocationMirror extends Primitive {
|
| }
|
| }
|
|
|
| -class ForeignCode extends CallExpression {
|
| +class ForeignCode extends UnsafePrimitive {
|
| final js.Template codeTemplate;
|
| final TypeMask type;
|
| final List<Reference<Primitive>> arguments;
|
| final native.NativeBehavior nativeBehavior;
|
| final FunctionElement dependency;
|
| - final Reference<Continuation> continuation;
|
|
|
| ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments,
|
| - this.nativeBehavior, Continuation continuation, {this.dependency})
|
| - : this.arguments = _referenceList(arguments),
|
| - this.continuation = new Reference<Continuation>(continuation);
|
| + this.nativeBehavior, {this.dependency})
|
| + : this.arguments = _referenceList(arguments);
|
|
|
| accept(Visitor visitor) => visitor.visitForeignCode(this);
|
|
|
| void setParentPointers() {
|
| _setParentsOnList(arguments, this);
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -1576,13 +1615,11 @@ class TypeExpression extends Primitive {
|
| }
|
| }
|
|
|
| -class Await extends CallExpression {
|
| +class Await extends UnsafePrimitive {
|
| final Reference<Primitive> input;
|
| - final Reference<Continuation> continuation;
|
|
|
| - Await(Primitive input, Continuation continuation)
|
| - : this.input = new Reference<Primitive>(input),
|
| - this.continuation = new Reference<Continuation>(continuation);
|
| + Await(Primitive input)
|
| + : this.input = new Reference<Primitive>(input);
|
|
|
| @override
|
| accept(Visitor visitor) {
|
| @@ -1591,18 +1628,15 @@ class Await extends CallExpression {
|
|
|
| void setParentPointers() {
|
| input.parent = this;
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| -class Yield extends CallExpression {
|
| +class Yield extends UnsafePrimitive {
|
| final Reference<Primitive> input;
|
| - final Reference<Continuation> continuation;
|
| final bool hasStar;
|
|
|
| - Yield(Primitive input, this.hasStar, Continuation continuation)
|
| - : this.input = new Reference<Primitive>(input),
|
| - this.continuation = new Reference<Continuation>(continuation);
|
| + Yield(Primitive input, this.hasStar)
|
| + : this.input = new Reference<Primitive>(input);
|
|
|
| @override
|
| accept(Visitor visitor) {
|
| @@ -1611,7 +1645,6 @@ class Yield extends CallExpression {
|
|
|
| void setParentPointers() {
|
| input.parent = this;
|
| - continuation.parent = this;
|
| }
|
| }
|
|
|
| @@ -1760,7 +1793,6 @@ class DeepRecursiveVisitor implements Visitor {
|
| processInvokeStatic(InvokeStatic node) {}
|
| visitInvokeStatic(InvokeStatic node) {
|
| processInvokeStatic(node);
|
| - processReference(node.continuation);
|
| node.arguments.forEach(processReference);
|
| }
|
|
|
| @@ -1775,7 +1807,6 @@ class DeepRecursiveVisitor implements Visitor {
|
| visitInvokeMethod(InvokeMethod node) {
|
| processInvokeMethod(node);
|
| processReference(node.receiver);
|
| - processReference(node.continuation);
|
| node.arguments.forEach(processReference);
|
| }
|
|
|
| @@ -1783,14 +1814,12 @@ class DeepRecursiveVisitor implements Visitor {
|
| visitInvokeMethodDirectly(InvokeMethodDirectly node) {
|
| processInvokeMethodDirectly(node);
|
| processReference(node.receiver);
|
| - processReference(node.continuation);
|
| node.arguments.forEach(processReference);
|
| }
|
|
|
| processInvokeConstructor(InvokeConstructor node) {}
|
| visitInvokeConstructor(InvokeConstructor node) {
|
| processInvokeConstructor(node);
|
| - processReference(node.continuation);
|
| node.arguments.forEach(processReference);
|
| }
|
|
|
| @@ -1816,7 +1845,6 @@ class DeepRecursiveVisitor implements Visitor {
|
| processTypeCast(TypeCast node) {}
|
| visitTypeCast(TypeCast node) {
|
| processTypeCast(node);
|
| - processReference(node.continuation);
|
| processReference(node.value);
|
| node.typeArguments.forEach(processReference);
|
| }
|
| @@ -1845,7 +1873,6 @@ class DeepRecursiveVisitor implements Visitor {
|
| processGetLazyStatic(GetLazyStatic node) {}
|
| visitGetLazyStatic(GetLazyStatic node) {
|
| processGetLazyStatic(node);
|
| - processReference(node.continuation);
|
| }
|
|
|
| processLiteralList(LiteralList node) {}
|
| @@ -1972,9 +1999,6 @@ class DeepRecursiveVisitor implements Visitor {
|
| processForeignCode(ForeignCode node) {}
|
| visitForeignCode(ForeignCode node) {
|
| processForeignCode(node);
|
| - if (node.continuation != null) {
|
| - processReference(node.continuation);
|
| - }
|
| node.arguments.forEach(processReference);
|
| }
|
|
|
| @@ -1987,14 +2011,12 @@ class DeepRecursiveVisitor implements Visitor {
|
| visitAwait(Await node) {
|
| processAwait(node);
|
| processReference(node.input);
|
| - processReference(node.continuation);
|
| }
|
|
|
| processYield(Yield node) {}
|
| visitYield(Yield node) {
|
| processYield(node);
|
| processReference(node.input);
|
| - processReference(node.continuation);
|
| }
|
|
|
| processGetLength(GetLength node) {}
|
|
|