| Index: sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
|
| index b5d25d38dc0b29a301e28584601206582005625c..039bd847e24dc644afbe06e25382ac80428c4e7f 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
|
| @@ -49,12 +49,16 @@ abstract class Definition extends Node {
|
| }
|
| }
|
|
|
| -/// A pure expression that cannot throw or diverge.
|
| +/// An expression that cannot throw or diverge and has no side-effects.
|
| /// All primitives are named using the identity of the [Primitive] object.
|
| +///
|
| +/// Primitives may allocate objects, this is not considered side-effect here.
|
| +///
|
| +/// Although primitives may not mutate state, they may depend on state.
|
| abstract class Primitive extends Definition {
|
| /// The [VariableElement] or [ParameterElement] from which the primitive
|
| /// binding originated.
|
| - Element element;
|
| + Element hint;
|
|
|
| /// Register in which the variable binding this primitive can be allocated.
|
| /// Separate register spaces are used for primitives with different [element].
|
| @@ -65,8 +69,8 @@ abstract class Primitive extends Definition {
|
| ///
|
| /// Has no effect if this primitive already has a non-null [element].
|
| void useElementAsHint(Element hint) {
|
| - if (element == null) {
|
| - element = hint;
|
| + if (this.hint == null) {
|
| + this.hint = hint;
|
| }
|
| }
|
| }
|
| @@ -256,6 +260,88 @@ class ConcatenateStrings extends Expression {
|
| accept(Visitor visitor) => visitor.visitConcatenateStrings(this);
|
| }
|
|
|
| +/// Gets the value from a closure variable. The identity of the variable is
|
| +/// determined by an [Element].
|
| +///
|
| +/// Closure variables can be seen as ref cells that are not first-class values.
|
| +/// A [LetPrim] with a [GetClosureVariable] can then be seen as:
|
| +///
|
| +/// let prim p = ![variable] in [body]
|
| +///
|
| +class GetClosureVariable extends Primitive {
|
| + final Element variable;
|
| +
|
| + GetClosureVariable(this.variable) {
|
| + assert(variable != null);
|
| + }
|
| +
|
| + accept(Visitor visitor) => visitor.visitGetClosureVariable(this);
|
| +}
|
| +
|
| +/// Assign or declare a closure variable. The identity of the variable is
|
| +/// determined by an [Element].
|
| +///
|
| +/// Closure variables can be seen as ref cells that are not first-class values.
|
| +/// If [isDeclaration], this can seen as a let binding:
|
| +///
|
| +/// let [variable] = ref [value] in [body]
|
| +///
|
| +/// And otherwise, it can be seen as a dereferencing assignment:
|
| +///
|
| +/// { ![variable] := [value]; [body] }
|
| +///
|
| +/// Closure variables without a declaring [SetClosureVariable] are implicitly
|
| +/// declared at the entry to the [variable]'s enclosing function.
|
| +class SetClosureVariable extends Expression {
|
| + final Element variable;
|
| + final Reference value;
|
| + Expression body;
|
| +
|
| + /// If true, this declares a new copy of the closure variable. If so, all
|
| + /// uses of the closure variable must occur in the [body].
|
| + ///
|
| + /// There can be at most one declaration per closure variable. If there is no
|
| + /// declaration, only one copy exists (per function execution). It is best to
|
| + /// avoid declaring closure variables if it is not necessary.
|
| + final bool isDeclaration;
|
| +
|
| + SetClosureVariable(this.variable, Primitive value,
|
| + {this.isDeclaration : false })
|
| + : this.value = new Reference(value) {
|
| + assert(variable != null);
|
| + }
|
| +
|
| + accept(Visitor visitor) => visitor.visitSetClosureVariable(this);
|
| +
|
| + Expression plug(Expression expr) {
|
| + assert(body == null);
|
| + return body = expr;
|
| + }
|
| +}
|
| +
|
| +/// Create a potentially recursive function and store it in a closure variable.
|
| +/// The function can access itself using [GetClosureVariable] on [variable].
|
| +/// There must not exist a [SetClosureVariable] to [variable].
|
| +///
|
| +/// This can be seen as a let rec binding:
|
| +///
|
| +/// let rec [variable] = [definition] in [body]
|
| +///
|
| +class DeclareFunction extends Expression {
|
| + final Element variable;
|
| + final FunctionDefinition definition;
|
| + Expression body;
|
| +
|
| + DeclareFunction(this.variable, this.definition);
|
| +
|
| + Expression plug(Expression expr) {
|
| + assert(body == null);
|
| + return body = expr;
|
| + }
|
| +
|
| + accept(Visitor visitor) => visitor.visitDeclareFunction(this);
|
| +}
|
| +
|
| /// Invoke a continuation in tail position.
|
| class InvokeContinuation extends Expression {
|
| final Reference continuation;
|
| @@ -319,9 +405,9 @@ class This extends Primitive {
|
| /// Reify the given type variable as a [Type].
|
| /// This depends on the current binding of 'this'.
|
| class ReifyTypeVar extends Primitive {
|
| - final TypeVariableElement element;
|
| + final TypeVariableElement typeVariable;
|
|
|
| - ReifyTypeVar(this.element);
|
| + ReifyTypeVar(this.typeVariable);
|
|
|
| dart2js.Constant get constant => null;
|
|
|
| @@ -351,6 +437,15 @@ class LiteralMap extends Primitive {
|
| accept(Visitor visitor) => visitor.visitLiteralMap(this);
|
| }
|
|
|
| +/// Create a non-recursive function.
|
| +class CreateFunction extends Primitive {
|
| + final FunctionDefinition definition;
|
| +
|
| + CreateFunction(this.definition);
|
| +
|
| + accept(Visitor visitor) => visitor.visitCreateFunction(this);
|
| +}
|
| +
|
| class IsCheck extends Primitive {
|
| final Reference receiver;
|
| final DartType type;
|
| @@ -365,7 +460,7 @@ class IsCheck extends Primitive {
|
|
|
| class Parameter extends Primitive {
|
| Parameter(Element element) {
|
| - super.element = element;
|
| + super.hint = element;
|
| }
|
|
|
| accept(Visitor visitor) => visitor.visitParameter(this);
|
| @@ -391,13 +486,14 @@ class Continuation extends Definition {
|
| /// A function definition, consisting of parameters and a body. The parameters
|
| /// include a distinguished continuation parameter.
|
| class FunctionDefinition extends Node {
|
| + final FunctionElement element;
|
| final Continuation returnContinuation;
|
| final List<Parameter> parameters;
|
| final Expression body;
|
| final List<ConstDeclaration> localConstants;
|
|
|
| - FunctionDefinition(this.returnContinuation, this.parameters, this.body,
|
| - this.localConstants);
|
| + FunctionDefinition(this.element, this.returnContinuation,
|
| + this.parameters, this.body, this.localConstants);
|
|
|
| accept(Visitor visitor) => visitor.visitFunctionDefinition(this);
|
| }
|
| @@ -429,6 +525,8 @@ abstract class Visitor<T> {
|
| T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node);
|
| T visitBranch(Branch node) => visitExpression(node);
|
| T visitAsCast(AsCast node) => visitExpression(node);
|
| + T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node);
|
| + T visitDeclareFunction(DeclareFunction node) => visitExpression(node);
|
|
|
| // Definitions.
|
| T visitLiteralList(LiteralList node) => visitPrimitive(node);
|
| @@ -437,6 +535,8 @@ abstract class Visitor<T> {
|
| T visitConstant(Constant node) => visitPrimitive(node);
|
| T visitThis(This node) => visitPrimitive(node);
|
| T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node);
|
| + T visitCreateFunction(CreateFunction node) => visitPrimitive(node);
|
| + T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node);
|
| T visitParameter(Parameter node) => visitPrimitive(node);
|
| T visitContinuation(Continuation node) => visitDefinition(node);
|
|
|
| @@ -563,7 +663,12 @@ class SExpressionStringifier extends Visitor<String> {
|
| }
|
|
|
| String visitReifyTypeVar(ReifyTypeVar node) {
|
| - return '(ReifyTypeVar ${node.element.name})';
|
| + return '(ReifyTypeVar ${node.typeVariable.name})';
|
| + }
|
| +
|
| + String visitCreateFunction(CreateFunction node) {
|
| + String function = visit(node.definition);
|
| + return '(CreateFunction ${node.definition.element} $function)';
|
| }
|
|
|
| String visitParameter(Parameter node) {
|
| @@ -576,6 +681,22 @@ class SExpressionStringifier extends Visitor<String> {
|
| return '(Unexpected Continuation)';
|
| }
|
|
|
| + String visitGetClosureVariable(GetClosureVariable node) {
|
| + return '(GetClosureVariable ${node.variable.name})';
|
| + }
|
| +
|
| + String visitSetClosureVariable(SetClosureVariable node) {
|
| + String value = names[node.value.definition];
|
| + String body = visit(node.body);
|
| + return '(SetClosureVariable ${node.variable.name} $value $body)';
|
| + }
|
| +
|
| + String visitDeclareFunction(DeclareFunction node) {
|
| + String function = visit(node.definition);
|
| + String body = visit(node.body);
|
| + return '(DeclareFunction ${node.variable} = $function in $body)';
|
| + }
|
| +
|
| String visitIsTrue(IsTrue node) {
|
| String value = names[node.value.definition];
|
| return '(IsTrue $value)';
|
| @@ -624,15 +745,15 @@ class RegisterAllocator extends Visitor {
|
|
|
| void allocate(Primitive primitive) {
|
| if (primitive.registerIndex == null) {
|
| - primitive.registerIndex = getRegisterArray(primitive.element).makeIndex();
|
| + primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex();
|
| }
|
| }
|
|
|
| void release(Primitive primitive) {
|
| // Do not share indices for temporaries as this may obstruct inlining.
|
| - if (primitive.element == null) return;
|
| + if (primitive.hint == null) return;
|
| if (primitive.registerIndex != null) {
|
| - getRegisterArray(primitive.element).releaseIndex(primitive.registerIndex);
|
| + getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex);
|
| }
|
| }
|
|
|
| @@ -714,6 +835,23 @@ class RegisterAllocator extends Visitor {
|
| void visitReifyTypeVar(ReifyTypeVar node) {
|
| }
|
|
|
| + void visitCreateFunction(CreateFunction node) {
|
| + new RegisterAllocator().visit(node.definition);
|
| + }
|
| +
|
| + void visitGetClosureVariable(GetClosureVariable node) {
|
| + }
|
| +
|
| + void visitSetClosureVariable(SetClosureVariable node) {
|
| + visit(node.body);
|
| + visitReference(node.value);
|
| + }
|
| +
|
| + void visitDeclareFunction(DeclareFunction node) {
|
| + new RegisterAllocator().visit(node.definition);
|
| + visit(node.body);
|
| + }
|
| +
|
| void visitParameter(Parameter node) {
|
| throw "Parameters should not be visited by RegisterAllocator";
|
| }
|
|
|