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

Unified Diff: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart

Issue 1537663002: dart2js: Initial implementation of inlining. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebaseline test expectations and fix a bug (typo). Created 5 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_fragment.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 02b963eb6b3231088104bb2d22cc68af3c6c179b..8999b560ac409ab9ed3bfebc9346aa88dbe8a664 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -4,6 +4,7 @@
library dart2js.ir_nodes;
import 'dart:collection';
+import 'cps_fragment.dart' show CpsFragment;
import '../constants/values.dart' as values;
import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
import '../elements/elements.dart';
@@ -203,18 +204,7 @@ class EffectiveUseIterable extends IterableBase<Reference<Primitive>> {
///
/// All primitives except [Parameter] must be bound by a [LetPrim].
abstract class Primitive extends Variable<Primitive> {
- /// The [VariableElement] or [ParameterElement] from which the primitive
- /// binding originated.
- Entity hint;
-
- /// Use the given element as a hint for naming this primitive.
- ///
- /// Has no effect if this primitive already has a non-null [element].
- void useElementAsHint(Entity hint) {
- if (this.hint == null) {
- this.hint = hint;
- }
- }
+ Primitive() : super(null);
/// True if this primitive has a value that can be used by other expressions.
bool get hasValue;
@@ -295,6 +285,23 @@ abstract class Primitive extends Variable<Primitive> {
newDefinition.parent = let;
newDefinition.useElementAsHint(hint);
}
+
+ /// Replaces this definition with a CPS fragment (a term with a hole in it),
+ /// given the value to replace the uses of the definition with.
+ ///
+ /// This can be thought of as substituting:
+ ///
+ /// let x = OLD in BODY
+ /// ==>
+ /// FRAGMENT[BODY{newPrimitive/x}]
+ void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) {
+ assert(this is! Parameter);
+ replaceUsesWith(newPrimitive);
+ destroy();
+ LetPrim let = parent;
+ fragment.insertBelow(let);
+ let.remove();
+ }
}
/// A primitive that is generally not safe for elimination, but may be marked
@@ -464,6 +471,43 @@ class LetMutable extends InteriorExpression {
}
}
+enum CallingConvention {
+ /// JS receiver is the Dart receiver, there are no extra arguments.
+ ///
+ /// This includes cases (e.g., static functions, constructors) where there
+ /// is no receiver.
+ ///
+ /// 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,
+
+ /// JS receiver is the Dart receiver, there are no extra arguments.
+ ///
+ /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
+ OneShotIntercepted,
+}
+
+/// Base class of function invocations.
+///
+/// This class defines the common interface of function invocations.
+abstract class InvocationPrimitive extends UnsafePrimitive {
+ Reference<Primitive> get receiver => null;
+ List<Reference<Primitive>> get arguments;
+ SourceInformation get sourceInformation;
+
+ Reference<Primitive> get dartReceiverReference => null;
+ CallingConvention get callingConvention => CallingConvention.Normal;
+}
+
/// Invoke a static function.
///
/// All optional arguments declared by [target] are passed in explicitly, and
@@ -472,7 +516,7 @@ class LetMutable extends InteriorExpression {
/// Discussion:
/// All information in the [selector] is technically redundant; it will likely
/// be removed.
-class InvokeStatic extends UnsafePrimitive {
+class InvokeStatic extends InvocationPrimitive {
final FunctionElement target;
final Selector selector;
final List<Reference<Primitive>> arguments;
@@ -498,28 +542,6 @@ class InvokeStatic extends UnsafePrimitive {
}
}
-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,
-
- /// JS receiver is the Dart receiver, there are no extra arguments.
- ///
- /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
- OneShotIntercepted,
-}
-
/// Invoke a method on an object.
///
/// This includes getters, setters, operators, and index getter/setters.
@@ -529,7 +551,7 @@ enum CallingConvention {
///
/// 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 UnsafePrimitive {
+class InvokeMethod extends InvocationPrimitive {
Reference<Primitive> receiver;
Selector selector;
TypeMask mask;
@@ -606,7 +628,7 @@ class InvokeMethod extends UnsafePrimitive {
///
/// All optional arguments declared by [target] are passed in explicitly, and
/// occur at the end of [arguments] list, in normalized order.
-class InvokeMethodDirectly extends UnsafePrimitive {
+class InvokeMethodDirectly extends InvocationPrimitive {
Reference<Primitive> receiver;
final FunctionElement target;
final Selector selector;
@@ -664,7 +686,7 @@ class InvokeMethodDirectly extends UnsafePrimitive {
///
/// Note that [InvokeConstructor] does it itself allocate an object.
/// The invoked constructor will do that using [CreateInstance].
-class InvokeConstructor extends UnsafePrimitive {
+class InvokeConstructor extends InvocationPrimitive {
final DartType dartType;
final ConstructorElement target;
final List<Reference<Primitive>> arguments;
@@ -1688,13 +1710,24 @@ abstract class Variable<T extends Variable<T>> extends Definition<T> {
///
/// Is `null` until initialized by type propagation.
TypeMask type;
+
+ /// The [VariableElement] or [ParameterElement] from which the variable
+ /// binding originated.
+ Entity hint;
+
+ Variable(this.hint);
+
+ /// Use the given element as a hint for naming this primitive.
+ ///
+ /// Has no effect if this primitive already has a non-null [element].
+ void useElementAsHint(Entity hint) {
+ this.hint ??= hint;
+ }
}
/// Identifies a mutable variable.
class MutableVariable extends Variable<MutableVariable> {
- Entity hint;
-
- MutableVariable(this.hint);
+ MutableVariable(Entity hint) : super(hint);
accept(Visitor v) => v.visitMutableVariable(this);
@@ -1874,23 +1907,23 @@ abstract class Visitor<T> {
T visitLetHandler(LetHandler node);
T visitLetMutable(LetMutable node);
T visitInvokeContinuation(InvokeContinuation node);
+ T visitThrow(Throw node);
+ T visitRethrow(Rethrow node);
+ T visitBranch(Branch node);
+ T visitUnreachable(Unreachable node);
+
+ // Definitions.
T visitInvokeStatic(InvokeStatic node);
T visitInvokeMethod(InvokeMethod node);
T visitInvokeMethodDirectly(InvokeMethodDirectly node);
T visitInvokeConstructor(InvokeConstructor node);
- T visitThrow(Throw node);
- T visitRethrow(Rethrow node);
- T visitBranch(Branch node);
T visitTypeCast(TypeCast node);
T visitSetMutable(SetMutable node);
T visitSetStatic(SetStatic node);
- T visitGetLazyStatic(GetLazyStatic node);
T visitSetField(SetField node);
- T visitUnreachable(Unreachable node);
+ T visitGetLazyStatic(GetLazyStatic node);
T visitAwait(Await node);
T visitYield(Yield node);
-
- // Definitions.
T visitLiteralList(LiteralList node);
T visitLiteralMap(LiteralMap node);
T visitConstant(Constant node);
@@ -2392,3 +2425,373 @@ class RemovalVisitor extends TrampolineRecursiveVisitor {
(new RemovalVisitor()).visit(node);
}
}
+
+/// A visitor to copy instances of [Definition] or its subclasses, except for
+/// instances of [Continuation].
+///
+/// The visitor maintains a map from original definitions to their copies.
+/// When the [copy] method is called for a non-Continuation definition,
+/// a copy is created, added to the map and returned as the result. Copying a
+/// definition assumes that the definitions of all references have already
+/// been copied by the same visitor.
+class DefinitionCopyingVisitor extends Visitor<Definition> {
+ Map<Definition, Definition> _copies = <Definition, Definition>{};
+
+ /// Put a copy into the map.
+ ///
+ /// This method should be used instead of directly adding copies to the map.
+ Definition putCopy(Definition original, Definition copy) {
+ if (copy is Variable) {
+ Variable originalVariable = original;
+ copy.type = originalVariable.type;
+ copy.hint = originalVariable.hint;
+ }
+ return _copies[original] = copy;
+ }
+
+ /// Get the copy of a [Reference]'s definition from the map.
+ Definition getCopy(Reference reference) => _copies[reference.definition];
+
+ /// Map a list of [Reference]s to the list of their definition's copies.
+ List<Definition> getList(List<Reference> list) => list.map(getCopy).toList();
+
+ /// Copy a non-[Continuation] [Definition].
+ Definition copy(Definition node) {
+ assert (node is! Continuation);
+ return putCopy(node, visit(node));
+ }
+
+ Definition visit(Node node) => node.accept(this);
+
+ Definition visitFunctionDefinition(FunctionDefinition node) {}
+ Definition visitLetPrim(LetPrim node) {}
+ Definition visitLetCont(LetCont node) {}
+ Definition visitLetHandler(LetHandler node) {}
+ Definition visitLetMutable(LetMutable node) {}
+ Definition visitInvokeContinuation(InvokeContinuation node) {}
+ Definition visitThrow(Throw node) {}
+ Definition visitRethrow(Rethrow node) {}
+ Definition visitBranch(Branch node) {}
+ Definition visitUnreachable(Unreachable node) {}
+ Definition visitContinuation(Continuation node) {}
+
+ Definition visitInvokeStatic(InvokeStatic node) {
+ return new InvokeStatic(node.target, node.selector, getList(node.arguments),
+ node.sourceInformation);
+ }
+
+ Definition visitInvokeMethod(InvokeMethod node) {
+ return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask,
+ getList(node.arguments),
+ node.sourceInformation);
+ }
+
+ Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+ return new InvokeMethodDirectly(getCopy(node.receiver), node.target,
+ node.selector,
+ getList(node.arguments),
+ node.sourceInformation);
+ }
+
+ Definition visitInvokeConstructor(InvokeConstructor node) {
+ return new InvokeConstructor(node.dartType, node.target, node.selector,
+ getList(node.arguments),
+ node.sourceInformation);
+ }
+
+ Definition visitTypeCast(TypeCast node) {
+ return new TypeCast(getCopy(node.value), node.dartType,
+ getList(node.typeArguments));
+ }
+
+ Definition visitSetMutable(SetMutable node) {
+ return new SetMutable(getCopy(node.variable), getCopy(node.value));
+ }
+
+ Definition visitSetStatic(SetStatic node) {
+ return new SetStatic(node.element, getCopy(node.value),
+ node.sourceInformation);
+ }
+
+ Definition visitSetField(SetField node) {
+ return new SetField(getCopy(node.object), node.field, getCopy(node.value));
+ }
+
+ Definition visitGetLazyStatic(GetLazyStatic node) {
+ return new GetLazyStatic(node.element, node.sourceInformation);
+ }
+
+ Definition visitAwait(Await node) {
+ return new Await(getCopy(node.input));
+ }
+
+ Definition visitYield(Yield node) {
+ return new Yield(getCopy(node.input), node.hasStar);
+ }
+
+ Definition visitLiteralList(LiteralList node) {
+ return new LiteralList(node.dartType, getList(node.values));
+ }
+
+ Definition visitLiteralMap(LiteralMap node) {
+ List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) {
+ return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value));
+ }).toList();
+ return new LiteralMap(node.dartType, entries);
+ }
+
+ Definition visitConstant(Constant node) {
+ return new Constant(node.value, sourceInformation: node.sourceInformation);
+ }
+
+ Definition visitGetMutable(GetMutable node) {
+ return new GetMutable(getCopy(node.variable));
+ }
+
+ Definition visitParameter(Parameter node) {
+ return new Parameter(node.hint);
+ }
+
+ Definition visitMutableVariable(MutableVariable node) {
+ return new MutableVariable(node.hint);
+ }
+
+ Definition visitGetStatic(GetStatic node) {
+ return new GetStatic(node.element, node.sourceInformation);
+ }
+
+ Definition visitInterceptor(Interceptor node) {
+ return new Interceptor(getCopy(node.input), node.sourceInformation)
+ ..interceptedClasses.addAll(node.interceptedClasses);
+ }
+
+ Definition visitCreateInstance(CreateInstance node) {
+ return new CreateInstance(node.classElement, getList(node.arguments),
+ getList(node.typeInformation),
+ node.sourceInformation);
+ }
+
+ Definition visitGetField(GetField node) {
+ return new GetField(getCopy(node.object), node.field);
+ }
+
+ Definition visitCreateBox(CreateBox node) {
+ return new CreateBox();
+ }
+
+ Definition visitReifyRuntimeType(ReifyRuntimeType node) {
+ return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation);
+ }
+
+ Definition visitReadTypeVariable(ReadTypeVariable node) {
+ return new ReadTypeVariable(node.variable, getCopy(node.target),
+ node.sourceInformation);
+ }
+
+ Definition visitTypeExpression(TypeExpression node) {
+ return new TypeExpression(node.dartType, getList(node.arguments));
+ }
+
+ Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
+ return new CreateInvocationMirror(node.selector, getList(node.arguments));
+ }
+
+ Definition visitTypeTest(TypeTest node) {
+ return new TypeTest(getCopy(node.value), node.dartType,
+ getList(node.typeArguments));
+ }
+
+ Definition visitTypeTestViaFlag(TypeTestViaFlag node) {
+ return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType);
+ }
+
+ Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
+ return new ApplyBuiltinOperator(node.operator, getList(node.arguments),
+ node.sourceInformation);
+ }
+
+ Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
+ return new ApplyBuiltinMethod(node.method, getCopy(node.receiver),
+ getList(node.arguments),
+ node.sourceInformation,
+ receiverIsNotNull: node.receiverIsNotNull);
+ }
+
+ Definition visitGetLength(GetLength node) {
+ return new GetLength(getCopy(node.object));
+ }
+
+ Definition visitGetIndex(GetIndex node) {
+ return new GetIndex(getCopy(node.object), getCopy(node.index));
+ }
+
+ Definition visitSetIndex(SetIndex node) {
+ return new SetIndex(getCopy(node.object), getCopy(node.index),
+ getCopy(node.value));
+ }
+
+ Definition visitRefinement(Refinement node) {
+ return new Refinement(getCopy(node.value), node.refineType);
+ }
+
+ Definition visitBoundsCheck(BoundsCheck node) {
+ if (node.hasNoChecks) {
+ return new BoundsCheck.noCheck(getCopy(node.object),
+ node.sourceInformation);
+ } else {
+ return new BoundsCheck(getCopy(node.object), getCopy(node.index),
+ getCopy(node.length),
+ node.checks,
+ node.sourceInformation);
+ }
+ }
+
+ Definition visitNullCheck(NullCheck node) {
+ return new NullCheck(getCopy(node.value), node.sourceInformation);
+ }
+
+ Definition visitForeignCode(ForeignCode node) {
+ return new ForeignCode(node.codeTemplate, node.type,
+ getList(node.arguments),
+ node.nativeBehavior,
+ dependency: node.dependency);
+ }
+}
+
+/// A trampolining visitor to copy [FunctionDefinition]s.
+class CopyingVisitor extends TrampolineRecursiveVisitor {
+ // The visitor maintains a map from original continuations to their copies.
+ Map<Continuation, Continuation> _copies = <Continuation, Continuation>{};
+
+ // The visitor uses an auxiliary visitor to copy definitions.
+ DefinitionCopyingVisitor _definitions = new DefinitionCopyingVisitor();
+
+ // While copying a block, the state of the visitor is a 'linked list' of
+ // the expressions in the block's body, with a pointer to the last element
+ // of the list.
+ Expression _first = null;
+ Expression _current = null;
+
+ void plug(Expression body) {
+ if (_first == null) {
+ _first = body;
+ } else {
+ assert(_current != null);
+ InteriorExpression interior = _current;
+ interior.body = body;
+ }
+ _current = body;
+ }
+
+ // Continuations are added to the visitor's stack to be visited after copying
+ // the current block is finished. The stack action saves the current block,
+ // copies the continuation's body, sets the body on the copy of the
+ // continuation, and restores the current block.
+ //
+ // Note that continuations are added to the copy map before the stack action
+ // to visit them is performed.
+ void push(Continuation cont) {
+ assert(!cont.isReturnContinuation);
+ _stack.add(() {
+ Expression savedFirst = _first;
+ _first = _current = null;
+ _processBlock(cont.body);
+ _copies[cont].body = _first;
+ _first = savedFirst;
+ _current = null;
+ });
+ }
+
+ FunctionDefinition copy(FunctionDefinition node) {
+ assert(_first == null && _current == null);
+ _first = _current = null;
+ // Definitions are copied where they are bound, before processing
+ // expressions in the scope of their binding.
+ Parameter thisParameter = node.thisParameter == null
+ ? null
+ : _definitions.copy(node.thisParameter);
+ List<Parameter> parameters =
+ node.parameters.map(_definitions.copy).toList();
+ // Though the return continuation's parameter does not have any uses,
+ // we still make a proper copy to ensure that hints, type, etc. are
+ // copied.
+ Parameter returnParameter =
+ _definitions.copy(node.returnContinuation.parameters.first);
+ Continuation returnContinuation = _copies[node.returnContinuation] =
+ new Continuation([returnParameter]);
+
+ visit(node.body);
+ FunctionDefinition copy = new FunctionDefinition(node.element,
+ thisParameter,
+ parameters,
+ returnContinuation,
+ _first);
+ _first = _current = null;
+ return copy;
+ }
+
+ Node visit(Node node) => node.accept(this);
+
+ Expression traverseLetCont(LetCont node) {
+ // Continuations are copied where they are bound, before processing
+ // expressions in the scope of their binding.
+ List<Continuation> continuations = node.continuations.map((Continuation c) {
+ push(c);
+ return _copies[c] =
+ new Continuation(c.parameters.map(_definitions.copy).toList());
+ }).toList();
+ plug(new LetCont.many(continuations, null));
+ return node.body;
+ }
+
+ Expression traverseLetHandler(LetHandler node) {
+ // Continuations are copied where they are bound, before processing
+ // expressions in the scope of their binding.
+ push(node.handler);
+ Continuation handler = _copies[node.handler] =
+ new Continuation(node.handler.parameters.map(_definitions.copy)
+ .toList());
+ plug(new LetHandler(handler, null));
+ return node.body;
+ }
+
+ Expression traverseLetPrim(LetPrim node) {
+ plug(new LetPrim(_definitions.copy(node.primitive)));
+ return node.body;
+ }
+
+ Expression traverseLetMutable(LetMutable node) {
+ plug(new LetMutable(_definitions.copy(node.variable),
+ _definitions.getCopy(node.value)));
+ return node.body;
+ }
+
+ // Tail expressions do not have references, so we do not need to map them
+ // to their copies.
+ visitInvokeContinuation(InvokeContinuation node) {
+ plug(new InvokeContinuation(_copies[node.continuation.definition],
+ _definitions.getList(node.arguments),
+ isRecursive: node.isRecursive,
+ isEscapingTry: node.isEscapingTry,
+ sourceInformation: node.sourceInformation));
+ }
+
+ Node visitThrow(Throw node) {
+ plug(new Throw(_definitions.getCopy(node.value)));
+ }
+
+ Node visitRethrow(Rethrow node) {
+ plug(new Rethrow());
+ }
+
+ Node visitBranch(Branch node) {
+ plug(new Branch.loose(_definitions.getCopy(node.condition),
+ _copies[node.trueContinuation.definition],
+ _copies[node.falseContinuation.definition])
+ ..isStrictCheck = node.isStrictCheck);
+ }
+
+ Node visitUnreachable(Unreachable node) {
+ plug(new Unreachable());
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_fragment.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698