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"; |
} |