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

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

Issue 831133004: Use closure conversion in new dart2js backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Removed redundant null-check Created 5 years, 11 months 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/closure.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.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_builder.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index 541c68f2bc4fd457d47e8f1db7e8a87b3ed866b1..4f42e9de31ca6fb4696ea978f5e9d0f230125035 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -15,6 +15,9 @@ import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator;
import '../universe/universe.dart' show SelectorKind;
import 'cps_ir_nodes.dart' as ir;
import '../elements/modelx.dart' show SynthesizedConstructorElementX;
+import '../closure.dart';
+import '../closure.dart' as closurelib;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
part 'cps_ir_builder_visitor.dart';
@@ -24,18 +27,18 @@ part 'cps_ir_builder_visitor.dart';
/// [ir.Primitive] that is their value. Parameters and locals are
/// assigned indexes which can be used to refer to them.
class Environment {
- /// A map from elements to their environment index.
- final Map<Element, int> variable2index;
+ /// A map from locals to their environment index.
+ final Map<Local, int> variable2index;
/// A reverse map from environment indexes to the variable.
- final List<Element> index2variable;
+ final List<Local> index2variable;
/// A map from environment indexes to their value.
final List<ir.Primitive> index2value;
Environment.empty()
- : variable2index = <Element, int>{},
- index2variable = <Element>[],
+ : variable2index = <Local, int>{},
+ index2variable = <Local>[],
index2value = <ir.Primitive>[];
/// Construct an environment that is a copy of another one.
@@ -43,14 +46,14 @@ class Environment {
/// The mapping from elements to indexes is shared, not copied.
Environment.from(Environment other)
: variable2index = other.variable2index,
- index2variable = new List<Element>.from(other.index2variable),
+ index2variable = new List<Local>.from(other.index2variable),
index2value = new List<ir.Primitive>.from(other.index2value);
get length => index2variable.length;
ir.Primitive operator [](int index) => index2value[index];
- void extend(Element element, ir.Primitive value) {
+ void extend(Local element, ir.Primitive value) {
// Assert that the name is not already in the environment. `null` is used
// as the name of anonymous variables. Because the variable2index map is
// shared, `null` can already occur. This is safe because such variables
@@ -64,14 +67,13 @@ class Environment {
index2value.add(value);
}
- ir.Primitive lookup(Element element) {
- assert(!element.isConst);
+ ir.Primitive lookup(Local element) {
assert(invariant(element, variable2index.containsKey(element),
message: "Unknown variable: $element."));
return index2value[variable2index[element]];
}
- void update(Element element, ir.Primitive value) {
+ void update(Local element, ir.Primitive value) {
index2value[variable2index[element]] = value;
}
@@ -82,7 +84,7 @@ class Environment {
assert(other.length >= length);
for (int i = 0; i < length; ++i) {
// An index maps to the same variable in both environments.
- Element variable = index2variable[i];
+ Local variable = index2variable[i];
if (variable != other.index2variable[i]) return false;
// The variable maps to the same index in both environments.
@@ -179,8 +181,6 @@ abstract class IrBuilderMixin<N> {
/// Shared state between IrBuilders of nested functions.
class IrBuilderClosureState {
- final Iterable<Entity> closureLocals;
-
/// Maps local variables to their corresponding [ClosureVariable] object.
final Map<Local, ir.ClosureVariable> local2closure =
<Local, ir.ClosureVariable>{};
@@ -194,13 +194,12 @@ class IrBuilderClosureState {
return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]);
}
- IrBuilderClosureState(this.closureLocals) {
- for (Local local in closureLocals) {
- ExecutableElement context = local.executableContext;
- ir.ClosureVariable variable = new ir.ClosureVariable(context, local);
- local2closure[local] = variable;
- getClosureList(context).add(variable);
- }
+ /// Creates a closure variable for the given local.
+ void makeClosureVariable(Local local) {
+ ir.ClosureVariable variable =
+ new ir.ClosureVariable(local.executableContext, local);
+ local2closure[local] = variable;
+ getClosureList(local.executableContext).add(variable);
}
}
@@ -222,21 +221,60 @@ class IrBuilderSharedState {
final List<ir.Definition> functionParameters = <ir.Definition>[];
+ /// Maps boxed locals to their location. These locals are not part of
+ /// the environment.
+ final Map<Local, ClosureLocation> boxedVariables = {};
+
+ /// If non-null, this refers to the receiver (`this`) in the enclosing method.
+ ir.Primitive receiver;
+
IrBuilderSharedState(this.constantSystem, this.currentElement);
}
/// A factory for building the cps IR.
-class IrBuilder {
+///
+/// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured
+/// variables in different ways.
+abstract class IrBuilder {
+ IrBuilder _makeInstance();
+
+ void declareLocalVariable(LocalVariableElement element,
+ {ir.Primitive initialValue});
+ void declareLocalFunction(LocalFunctionElement element, Object function);
+ ir.Primitive buildFunctionExpression(Object function);
+ ir.Primitive buildLocalGet(LocalElement element);
+ ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value);
+
+ /// Called when entering a nested function with free variables.
+ /// The free variables should subsequently be accessible using [buildLocalGet]
+ /// and [buildLocalSet].
+ void _buildClosureEnvironmentSetup(ClosureEnvironment env);
+
+ /// Enter a scope that declares boxed variables. The boxed variables must
+ /// subsequently be accessible using [buildLocalGet], [buildLocalSet], etc.
+ void _buildClosureScopeSetup(ClosureScope scope);
+
+ /// Add the given function parameter to the IR, and bind it in the environment
+ /// or put it in its box, if necessary.
+ void _createFunctionParameter(ParameterElement parameterElement);
+
+ /// Called before the update expression of a for-loop. A new box should be
+ /// created for [scope] and the values from the old box should be copied over.
+ void _migrateLoopVariables(ClosureScope scope);
+
// TODO(johnniwinther): Make these field final and remove the default values
// when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin.
final List<ir.Parameter> _parameters = <ir.Parameter>[];
- final IrBuilderSharedState state;
+ IrBuilderSharedState state;
- final IrBuilderClosureState closure;
+ IrBuilderClosureState closure;
/// A map from variable indexes to their values.
+ ///
+ /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not
+ /// in the map; look up their [BoxLocal] instead.
Environment environment;
// The IR builder maintains a context, which is an expression with a hole in
@@ -266,12 +304,12 @@ class IrBuilder {
ir.Expression _root = null;
ir.Expression _current = null;
- IrBuilder(ConstantSystem constantSystem,
- ExecutableElement currentElement,
- Iterable<Entity> closureLocals)
- : this.state = new IrBuilderSharedState(constantSystem, currentElement),
- this.closure = new IrBuilderClosureState(closureLocals),
- this.environment = new Environment.empty();
+ /// Initialize a new top-level IR builder.
+ void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
+ state = new IrBuilderSharedState(constantSystem, currentElement);
+ closure = new IrBuilderClosureState();
+ environment = new Environment.empty();
+ }
/// Construct a delimited visitor for visiting a subtree.
///
@@ -279,10 +317,12 @@ class IrBuilder {
/// local variables to their values, which is initially a copy of the parent
/// environment. It has its own context for building an IR expression, so
/// the built expression is not plugged into the parent's context.
- IrBuilder.delimited(IrBuilder parent)
- : this.state = parent.state,
- this.closure = parent.closure,
- this.environment = new Environment.from(parent.environment);
+ IrBuilder makeDelimitedBuilder() {
+ return _makeInstance()
+ ..state = state
+ ..closure = closure
+ ..environment = new Environment.from(environment);
+ }
/// Construct a visitor for a recursive continuation.
///
@@ -292,101 +332,53 @@ class IrBuilder {
/// recursive invocations will be passed values for all the local variables,
/// which may be eliminated later if they are redundant---if they take on
/// the same value at all invocation sites.
- IrBuilder.recursive(IrBuilder parent)
- : this.state = parent.state,
- this.closure = parent.closure,
- this.environment = new Environment.empty() {
- parent.environment.index2variable.forEach(createLocalParameter);
+ IrBuilder makeRecursiveBuilder() {
+ IrBuilder inner = _makeInstance()
+ ..state = state
+ ..closure = closure
+ ..environment = new Environment.empty();
+ environment.index2variable.forEach(inner.createLocalParameter);
+ return inner;
}
/// Construct a builder for an inner function.
- IrBuilder.innerFunction(IrBuilder parent,
- ExecutableElement currentElement)
- : this.state = new IrBuilderSharedState(parent.state.constantSystem,
- currentElement),
- this.closure = parent.closure,
- this.environment = new Environment.empty();
-
+ IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
+ return _makeInstance()
+ ..state = new IrBuilderSharedState(state.constantSystem, currentElement)
+ ..closure = closure
+ ..environment = new Environment.empty();
+ }
bool get isOpen => _root == null || _current != null;
- /// True if [element] is a local variable, local function, or parameter that
- /// is accessed from an inner function. Recursive self-references in a local
- /// function count as closure accesses.
- ///
- /// If `true`, [element] is a [LocalElement].
- bool isClosureVariable(Element element) {
- return closure.closureLocals.contains(element);
- }
- /// Returns the [ClosureVariable] corresponding to the given variable.
- /// Returns `null` for non-closure variables.
- ir.ClosureVariable getClosureVariable(LocalElement element) {
- return closure.local2closure[element];
+ void buildFieldInitializerHeader({ClosureScope closureScope}) {
+ _buildClosureScopeSetup(closureScope);
}
- /// Adds the given parameter to the function currently being built.
- void createFunctionParameter(ParameterElement parameterElement) {
- if (isClosureVariable(parameterElement)) {
- state.functionParameters.add(getClosureVariable(parameterElement));
- } else {
- state.functionParameters.add(createLocalParameter(parameterElement));
- }
+ void buildFunctionHeader(Iterable<ParameterElement> parameters,
+ {ClosureScope closureScope,
+ ClosureEnvironment closureEnvironment}) {
+ _buildClosureEnvironmentSetup(closureEnvironment);
+ _buildClosureScopeSetup(closureScope);
+ parameters.forEach(_createFunctionParameter);
}
- /// Create a parameter for [parameterElement] and add it to the current
- /// environment.
- ir.Parameter createLocalParameter(LocalElement parameterElement) {
- ir.Parameter parameter = new ir.Parameter(parameterElement);
+ /// Creates a parameter for [local] and adds it to the current environment.
+ ir.Parameter createLocalParameter(Local local) {
+ ir.Parameter parameter = new ir.Parameter(local);
_parameters.add(parameter);
- environment.extend(parameterElement, parameter);
+ environment.extend(local, parameter);
return parameter;
}
- /// Add the constant [variableElement] to the environment with [value] as its
+ /// Adds the constant [variableElement] to the environment with [value] as its
/// constant value.
void declareLocalConstant(LocalVariableElement variableElement,
ConstantExpression value) {
state.localConstants.add(new ConstDeclaration(variableElement, value));
}
- /// Add [variableElement] to the environment with [initialValue] as its
- /// initial value.
- void declareLocalVariable(LocalVariableElement variableElement,
- {ir.Primitive initialValue}) {
- assert(isOpen);
- if (initialValue == null) {
- // TODO(kmillikin): Consider pooling constants.
- // The initial value is null.
- initialValue = buildNullLiteral();
- }
- if (isClosureVariable(variableElement)) {
- add(new ir.SetClosureVariable(getClosureVariable(variableElement),
- initialValue,
- isDeclaration: true));
- } else {
- // In case a primitive was introduced for the initializer expression,
- // use this variable element to help derive a good name for it.
- initialValue.useElementAsHint(variableElement);
- environment.extend(variableElement, initialValue);
- }
- }
-
- /// Add [functionElement] to the environment with provided [definition].
- void declareLocalFunction(LocalFunctionElement functionElement,
- ir.FunctionDefinition definition) {
- assert(isOpen);
- if (isClosureVariable(functionElement)) {
- ir.ClosureVariable variable = getClosureVariable(functionElement);
- add(new ir.DeclareFunction(variable, definition));
- } else {
- ir.CreateFunction prim = new ir.CreateFunction(definition);
- add(new ir.LetPrim(prim));
- environment.extend(functionElement, prim);
- prim.useElementAsHint(functionElement);
- }
- }
-
// Plug an expression into the 'hole' in the context being accumulated. The
// empty context (just a hole) is represented by root (and current) being
// null. Since the hole in the current context is filled by this function,
@@ -522,8 +514,8 @@ class IrBuilder {
assert(isOpen);
// The then and else expressions are delimited.
- IrBuilder thenBuilder = new IrBuilder.delimited(this);
- IrBuilder elseBuilder = new IrBuilder.delimited(this);
+ IrBuilder thenBuilder = makeDelimitedBuilder();
+ IrBuilder elseBuilder = makeDelimitedBuilder();
ir.Primitive thenValue = buildThenExpression(thenBuilder);
ir.Primitive elseValue = buildElseExpression(elseBuilder);
@@ -561,13 +553,6 @@ class IrBuilder {
}
- /// Create a function expression from [definition].
- ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
- ir.CreateFunction prim = new ir.CreateFunction(definition);
- add(new ir.LetPrim(prim));
- return prim;
- }
-
/**
* Add an explicit `return null` for functions that don't have a return
* statement on each branch. This includes functions with an empty body,
@@ -766,44 +751,12 @@ class IrBuilder {
(k) => new ir.ConcatenateStrings(k, arguments));
}
- /// Create a read access of [local].
- ir.Primitive buildLocalGet(LocalElement local) {
- assert(isOpen);
- if (isClosureVariable(local)) {
- ir.Primitive result =
- new ir.GetClosureVariable(getClosureVariable(local));
- add(new ir.LetPrim(result));
- return result;
- } else {
- return environment.lookup(local);
- }
- }
-
- /// Create a write access to [local] with the provided [value].
- ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
- assert(isOpen);
- if (isClosureVariable(local)) {
- add(new ir.SetClosureVariable(getClosureVariable(local), value));
- } else {
- value.useElementAsHint(local);
- environment.update(local, value);
- }
- return value;
- }
-
/// Create an invocation of [local] where the argument structure is defined
/// by [selector] and the argument values are defined by [arguments].
ir.Primitive buildLocalInvocation(LocalElement local,
Selector selector,
List<ir.Definition> arguments) {
- ir.Primitive receiver;
- if (isClosureVariable(local)) {
- receiver = new ir.GetClosureVariable(getClosureVariable(local));
- add(new ir.LetPrim(receiver));
- } else {
- receiver = environment.lookup(local);
- }
- return _buildInvokeCall(receiver, selector, arguments);
+ return _buildInvokeCall(buildLocalGet(local), selector, arguments);
}
/// Create an invocation of the [functionExpression] where the argument
@@ -829,8 +782,8 @@ class IrBuilder {
assert(isOpen);
// The then and else parts are delimited.
- IrBuilder thenBuilder = new IrBuilder.delimited(this);
- IrBuilder elseBuilder = new IrBuilder.delimited(this);
+ IrBuilder thenBuilder = makeDelimitedBuilder();
+ IrBuilder elseBuilder = makeDelimitedBuilder();
buildThenPart(thenBuilder);
buildElsePart(elseBuilder);
@@ -913,11 +866,16 @@ class IrBuilder {
///
/// The jump [target] is used to identify which `break` and `continue`
/// statements that have this `for` statement as their target.
+ ///
+ /// The [closureScope] identifies variables that should be boxed in this loop.
+ /// This includes variables declared inside the body of the loop as well as
+ /// in the for-loop initializer.
void buildFor({SubbuildFunction buildInitializer,
SubbuildFunction buildCondition,
SubbuildFunction buildBody,
SubbuildFunction buildUpdate,
- JumpTarget target}) {
+ JumpTarget target,
+ ClosureScope closureScope}) {
assert(isOpen);
// For loops use four named continuations: the entry to the condition,
@@ -942,9 +900,23 @@ class IrBuilder {
// invocation of the continue continuation (i.e., no continues in the
// body), the continue continuation is inlined in the body.
+ // If the variables declared in the initializer must be boxed, we must
+ // create the box before entering the loop and renew the box at the end
+ // of the loop.
+ bool hasBoxedLoopVariables = closureScope != null &&
+ !closureScope.boxedLoopVariables.isEmpty;
+
+ // If a variable declared in the initializer must be boxed, we should
+ // create the box before initializing these variables.
+ // Otherwise, it is best to create the box inside the body so we don't have
+ // to create a box before the loop AND at the end of the loop.
+ if (hasBoxedLoopVariables) {
+ _buildClosureScopeSetup(closureScope);
+ }
+
buildInitializer(this);
- IrBuilder condBuilder = new IrBuilder.recursive(this);
+ IrBuilder condBuilder = makeRecursiveBuilder();
ir.Primitive condition = buildCondition(condBuilder);
if (condition == null) {
// If the condition is empty then the body is entered unconditionally.
@@ -956,7 +928,14 @@ class IrBuilder {
state.breakCollectors.add(breakCollector);
state.continueCollectors.add(continueCollector);
- IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
+ IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+
+ // If we did not yet create a box for the boxed variables, we must create it
+ // here. This saves us from
+ if (!hasBoxedLoopVariables) {
+ bodyBuilder._buildClosureScopeSetup(closureScope);
+ }
+
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
assert(state.continueCollectors.last == continueCollector);
@@ -969,8 +948,11 @@ class IrBuilder {
// is instead placed just outside the body of the body continuation.
bool hasContinues = !continueCollector.isEmpty;
IrBuilder updateBuilder = hasContinues
- ? new IrBuilder.recursive(condBuilder)
+ ? condBuilder.makeRecursiveBuilder()
: bodyBuilder;
+ if (hasBoxedLoopVariables) {
+ updateBuilder._migrateLoopVariables(closureScope);
+ }
buildUpdate(updateBuilder);
// Create body entry and loop exit continuations and a branch to them.
@@ -1056,21 +1038,22 @@ class IrBuilder {
Element variableElement,
Selector variableSelector,
SubbuildFunction buildBody,
- JumpTarget target}) {
+ JumpTarget target,
+ ClosureScope closureScope}) {
// The for-in loop
//
// for (a in e) s;
//
// Is compiled analogously to:
//
- // a = e.iterator;
- // while (a.moveNext()) {
- // var n0 = a.current;
+ // it = e.iterator;
+ // while (it.moveNext()) {
+ // var a = it.current;
// s;
// }
// The condition and body are delimited.
- IrBuilder condBuilder = new IrBuilder.recursive(this);
+ IrBuilder condBuilder = makeRecursiveBuilder();
ir.Primitive expressionReceiver = buildExpression(this);
List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
@@ -1094,7 +1077,8 @@ class IrBuilder {
state.breakCollectors.add(breakCollector);
state.continueCollectors.add(continueCollector);
- IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
+ IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ bodyBuilder._buildClosureScopeSetup(closureScope);
if (buildVariableDeclaration != null) {
buildVariableDeclaration(bodyBuilder);
}
@@ -1170,7 +1154,8 @@ class IrBuilder {
/// statements that have this `while` statement as their target.
void buildWhile({SubbuildFunction buildCondition,
SubbuildFunction buildBody,
- JumpTarget target}) {
+ JumpTarget target,
+ ClosureScope closureScope}) {
assert(isOpen);
// While loops use four named continuations: the entry to the body, the
// loop exit, the loop back edge (continue), and the loop exit (break).
@@ -1189,7 +1174,7 @@ class IrBuilder {
// statement occurs in the exit continuation).
// The condition and body are delimited.
- IrBuilder condBuilder = new IrBuilder.recursive(this);
+ IrBuilder condBuilder = makeRecursiveBuilder();
ir.Primitive condition = buildCondition(condBuilder);
JumpCollector breakCollector = new JumpCollector(target);
@@ -1197,7 +1182,8 @@ class IrBuilder {
state.breakCollectors.add(breakCollector);
state.continueCollectors.add(continueCollector);
- IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
+ IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ bodyBuilder._buildClosureScopeSetup(closureScope);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
assert(state.continueCollectors.last == continueCollector);
@@ -1375,18 +1361,18 @@ class IrBuilder {
// The translation must convert both e0 and e1 to booleans and handle
// local variable assignments in e1.
- IrBuilder rightBuilder = new IrBuilder.delimited(this);
+ IrBuilder rightBuilder = makeDelimitedBuilder();
ir.Primitive rightValue = buildRightValue(rightBuilder);
// A dummy empty target for the branch on the left subexpression branch.
// This enables using the same infrastructure for join-point continuations
// as in visitIf and visitConditional. It will hold a definition of the
// appropriate constant and an invocation of the join-point continuation.
- IrBuilder emptyBuilder = new IrBuilder.delimited(this);
+ IrBuilder emptyBuilder = makeDelimitedBuilder();
// Dummy empty targets for right true and right false. They hold
// definitions of the appropriate constant and an invocation of the
// join-point continuation.
- IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder);
- IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder);
+ IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
+ IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
// If we don't evaluate the right subexpression, the value of the whole
// expression is this constant.
@@ -1448,12 +1434,15 @@ class IrBuilder {
return joinContinuation.parameters.last;
}
- /// Creates an access to `this`.
+ /// Creates an access to the receiver from the current (or enclosing) method.
+ ///
+ /// If inside a closure class, [buildThis] will redirect access through
+ /// closure fields in order to access the receiver from the enclosing method.
ir.Primitive buildThis() {
- assert(isOpen);
- ir.Primitive result = new ir.This();
- add(new ir.LetPrim(result));
- return result;
+ if (state.receiver != null) return state.receiver;
+ ir.Primitive thisPrim = new ir.This();
+ add(new ir.LetPrim(thisPrim));
+ return thisPrim;
}
/// Create a non-recursive join-point continuation.
@@ -1561,3 +1550,336 @@ class IrBuilder {
return join;
}
}
+
+/// Dart-specific subclass of [IrBuilder].
+///
+/// Inner functions are represented by a [FunctionDefinition] with the
+/// IR for the inner function nested inside.
+///
+/// Captured variables are translated to ref cells (see [ClosureVariable])
+/// using [GetClosureVariable] and [SetClosureVariable].
+class DartIrBuilder extends IrBuilder {
+ ClosureVariableInfo closureVariables;
+
+ IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables);
+ DartIrBuilder._blank(this.closureVariables);
+
+ DartIrBuilder(ConstantSystem constantSystem,
+ ExecutableElement currentElement,
+ this.closureVariables) {
+ _init(constantSystem, currentElement);
+ closureVariables.capturedVariables.forEach(closure.makeClosureVariable);
+ }
+
+ /// True if [local] is stored in a [ClosureVariable].
+ bool isInClosureVariable(Local local) {
+ return closure.local2closure.containsKey(local);
+ }
+
+ /// Gets the [ClosureVariable] containing the value of [local].
+ ir.ClosureVariable getClosureVariable(Local local) {
+ return closure.local2closure[local];
+ }
+
+ void _buildClosureScopeSetup(ClosureScope scope) {
+ assert(scope == null);
+ }
+
+ void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
+ assert(env == null);
+ }
+
+ void _migrateLoopVariables(ClosureScope scope) {
+ assert(scope == null);
+ }
+
+ void _createFunctionParameter(ParameterElement parameterElement) {
+ ir.Parameter parameter = new ir.Parameter(parameterElement);
+ _parameters.add(parameter);
+ if (isInClosureVariable(parameterElement)) {
+ state.functionParameters.add(getClosureVariable(parameterElement));
+ } else {
+ state.functionParameters.add(parameter);
+ environment.extend(parameterElement, parameter);
+ }
+ }
+
+ void declareLocalVariable(LocalVariableElement variableElement,
+ {ir.Primitive initialValue}) {
+ assert(isOpen);
+ if (initialValue == null) {
+ initialValue = buildNullLiteral();
+ }
+ if (isInClosureVariable(variableElement)) {
+ add(new ir.SetClosureVariable(getClosureVariable(variableElement),
+ initialValue,
+ isDeclaration: true));
+ } else {
+ initialValue.useElementAsHint(variableElement);
+ environment.extend(variableElement, initialValue);
+ }
+ }
+
+ /// Add [functionElement] to the environment with provided [definition].
+ void declareLocalFunction(LocalFunctionElement functionElement,
+ ir.FunctionDefinition definition) {
+ assert(isOpen);
+ if (isInClosureVariable(functionElement)) {
+ ir.ClosureVariable variable = getClosureVariable(functionElement);
+ add(new ir.DeclareFunction(variable, definition));
+ } else {
+ ir.CreateFunction prim = new ir.CreateFunction(definition);
+ add(new ir.LetPrim(prim));
+ environment.extend(functionElement, prim);
+ prim.useElementAsHint(functionElement);
+ }
+ }
+
+ /// Create a function expression from [definition].
+ ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
+ ir.CreateFunction prim = new ir.CreateFunction(definition);
+ add(new ir.LetPrim(prim));
+ return prim;
+ }
+
+ /// Create a read access of [local].
+ ir.Primitive buildLocalGet(LocalElement local) {
+ assert(isOpen);
+ if (isInClosureVariable(local)) {
+ ir.Primitive result = new ir.GetClosureVariable(getClosureVariable(local));
+ result.useElementAsHint(local);
+ add(new ir.LetPrim(result));
+ return result;
+ } else {
+ return environment.lookup(local);
+ }
+ }
+
+ /// Create a write access to [local] with the provided [value].
+ ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
+ assert(isOpen);
+ if (isInClosureVariable(local)) {
+ add(new ir.SetClosureVariable(getClosureVariable(local), value));
+ } else {
+ value.useElementAsHint(local);
+ environment.update(local, value);
+ }
+ return value;
+ }
+
+
+}
+
+/// JS-specific subclass of [IrBuilder].
+///
+/// Inner functions are represented by a [ClosureClassElement], and captured
+/// variables are boxed as necessary using [CreateBox], [GetField], [SetField].
+class JsIrBuilder extends IrBuilder {
+ IrBuilder _makeInstance() => new JsIrBuilder._blank();
+ JsIrBuilder._blank();
+
+ JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) {
+ _init(constantSystem, currentElement);
+ }
+
+ void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
+ if (env == null) return;
+
+ // Obtain a reference to the function object (this).
+ ir.Primitive thisPrim = new ir.This();
+ add(new ir.LetPrim(thisPrim));
+
+ // Obtain access to the free variables.
+ env.freeVariables.forEach((Local local, ClosureLocation location) {
+ if (location.isBox) {
+ // Boxed variables are loaded from their box on-demand.
+ state.boxedVariables[local] = location;
+ } else {
+ // Unboxed variables are loaded from the function object immediately.
+ // This includes BoxLocals which are themselves unboxed variables.
+ ir.Primitive load = new ir.GetField(thisPrim, location.field);
+ add(new ir.LetPrim(load));
+ environment.extend(local, load);
+ }
+ });
+
+ // If the function captures a reference to the receiver from the
+ // enclosing method, remember which primitive refers to the receiver object.
+ if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) {
+ state.receiver = environment.lookup(env.thisLocal);
+ }
+
+ // If the function has a self-reference, use the value of `this`.
+ if (env.selfReference != null) {
+ environment.extend(env.selfReference, thisPrim);
+ }
+ }
+
+ void _buildClosureScopeSetup(ClosureScope scope) {
+ if (scope == null) return;
+ ir.CreateBox boxPrim = new ir.CreateBox();
+ add(new ir.LetPrim(boxPrim));
+ environment.extend(scope.box, boxPrim);
+ boxPrim.useElementAsHint(scope.box);
+ scope.capturedVariables.forEach((Local local, ClosureLocation location) {
+ assert(!state.boxedVariables.containsKey(local));
+ if (location.isBox) {
+ state.boxedVariables[local] = location;
+ }
+ });
+ }
+
+ void _createFunctionParameter(ParameterElement parameterElement) {
+ ir.Parameter parameter = new ir.Parameter(parameterElement);
+ _parameters.add(parameter);
+ state.functionParameters.add(parameter);
+ ClosureLocation location = state.boxedVariables[parameterElement];
+ if (location != null) {
+ add(new ir.SetField(environment.lookup(location.box),
+ location.field,
+ parameter));
+ } else {
+ environment.extend(parameterElement, parameter);
+ }
+ }
+
+ void declareLocalVariable(LocalElement variableElement,
+ {ir.Primitive initialValue}) {
+ assert(isOpen);
+ if (initialValue == null) {
+ initialValue = buildNullLiteral();
+ }
+ ClosureLocation location = state.boxedVariables[variableElement];
+ if (location != null) {
+ add(new ir.SetField(environment.lookup(location.box),
+ location.field,
+ initialValue));
+ } else {
+ initialValue.useElementAsHint(variableElement);
+ environment.extend(variableElement, initialValue);
+ }
+ }
+
+ /// Add [functionElement] to the environment with provided [definition].
+ void declareLocalFunction(LocalFunctionElement functionElement,
+ ClosureClassElement classElement) {
+ ir.Primitive closure = buildFunctionExpression(classElement);
+ declareLocalVariable(functionElement, initialValue: closure);
+ }
+
+ ir.Primitive buildFunctionExpression(ClosureClassElement classElement) {
+ List<ir.Primitive> arguments = <ir.Primitive>[];
+ for (ClosureFieldElement field in classElement.closureFields) {
+ arguments.add(environment.lookup(field.local));
+ }
+ ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments);
+ add(new ir.LetPrim(closure));
+ return closure;
+ }
+
+ /// Create a read access of [local].
+ ir.Primitive buildLocalGet(LocalElement local) {
+ assert(isOpen);
+ ClosureLocation location = state.boxedVariables[local];
+ if (location != null) {
+ ir.Primitive result = new ir.GetField(environment.lookup(location.box),
+ location.field);
+ result.useElementAsHint(local);
+ add(new ir.LetPrim(result));
+ return result;
+ } else {
+ return environment.lookup(local);
+ }
+ }
+
+ /// Create a write access to [local] with the provided [value].
+ ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
+ assert(isOpen);
+ ClosureLocation location = state.boxedVariables[local];
+ if (location != null) {
+ add(new ir.SetField(environment.lookup(location.box),
+ location.field,
+ value));
+ } else {
+ value.useElementAsHint(local);
+ environment.update(local, value);
+ }
+ return value;
+ }
+
+ void _migrateLoopVariables(ClosureScope scope) {
+ if (scope == null) return;
+ ir.Primitive box = environment.lookup(scope.box);
+ ir.Primitive newBox = new ir.CreateBox();
+ newBox.useElementAsHint(scope.box);
+ add(new ir.LetPrim(newBox));
+ for (VariableElement loopVar in scope.boxedLoopVariables) {
+ ClosureLocation location = scope.capturedVariables[loopVar];
+ ir.Primitive get = new ir.GetField(box, location.field);
+ add(new ir.LetPrim(get));
+ add(new ir.SetField(newBox, location.field, get));
+ }
+ environment.update(scope.box, newBox);
+ }
+
+}
+
+
+/// Location of a variable relative to a given closure.
+class ClosureLocation {
+ /// If not `null`, this location is [box].[field].
+ /// The location of [box] can be obtained separately from an
+ /// enclosing [ClosureEnvironment] or [ClosureScope].
+ /// If `null`, then the location is [field] on the enclosing function object.
+ final BoxLocal box;
+
+ /// The field in which the variable is stored.
+ final Entity field;
+
+ bool get isBox => box != null;
+
+ ClosureLocation(this.box, this.field);
+}
+
+/// Introduces a new box and binds local variables to this box.
+///
+/// A [ClosureScope] may exist for each function and for each loop.
+/// Generally, one may pass `null` to the [IrBuilder] instead of a
+/// [ClosureScope] when a given scope has no boxed variables.
+class ClosureScope {
+ /// This box is now in scope and [capturedVariables] may use it.
+ final BoxLocal box;
+
+ /// Maps [LocalElement]s to their location.
+ final Map<Local, ClosureLocation> capturedVariables;
+
+ /// If this is the scope of a for-loop, [boxedLoopVariables] is the list
+ /// of boxed variables that are declared in the initializer.
+ final List<VariableElement> boxedLoopVariables;
+
+ ClosureScope(this.box, this.capturedVariables, this.boxedLoopVariables);
+}
+
+/// Environment passed when building a nested function, describing how
+/// to access variables from the enclosing scope.
+class ClosureEnvironment {
+ /// References to this local should be treated as recursive self-reference.
+ /// (This is *not* in [freeVariables]).
+ final LocalFunctionElement selfReference;
+
+ /// If non-null, [thisLocal] has an entry in [freeVariables] describing where
+ /// to find the captured value of `this`.
+ final ThisLocal thisLocal;
+
+ /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location.
+ final Map<Local, ClosureLocation> freeVariables;
+
+ ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables);
+}
+
+/// Information about which variables are captured in a closure.
+/// This is used by the [DartIrBuilder] instead of [ClosureScope] and
+/// [ClosureEnvironment].
+abstract class ClosureVariableInfo {
+ Iterable<Local> get capturedVariables;
+}
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698