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

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

Issue 846353002: Dart2dart: Support for-loop variables captured in loop body. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase 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
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 5c9da0f5390f60913e6effbc266e70271eabcffa..356043861b4a63411fe74f0ac94da00f462eec7c 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -179,32 +179,8 @@ abstract class IrBuilderMixin<N> {
}
}
-/// Shared state between IrBuilders of nested functions.
-class IrBuilderClosureState {
- /// Maps local variables to their corresponding [ClosureVariable] object.
- final Map<Local, ir.ClosureVariable> local2closure =
- <Local, ir.ClosureVariable>{};
-
- /// Maps functions to the list of closure variables declared in that function.
- final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures =
- <ExecutableElement, List<ir.ClosureVariable>>{};
-
- /// Returns the closure variables declared in the given function.
- List<ir.ClosureVariable> getClosureList(ExecutableElement element) {
- return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]);
- }
-
- /// 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);
- }
-}
-
/// Shared state between delimited IrBuilders within the same function.
-class IrBuilderSharedState {
+class IrBuilderDelimitedState {
final ConstantSystem constantSystem;
/// A stack of collectors for breaks.
@@ -221,14 +197,7 @@ 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);
+ IrBuilderDelimitedState(this.constantSystem, this.currentElement);
}
/// A factory for building the cps IR.
@@ -246,30 +215,56 @@ abstract class IrBuilder {
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]
+ ///
+ /// The free variables must subsequently be accessible using [buildLocalGet]
/// and [buildLocalSet].
- void _buildClosureEnvironmentSetup(ClosureEnvironment env);
+ void _enterClosureEnvironment(ClosureEnvironment env);
- /// Enter a scope that declares boxed variables. The boxed variables must
- /// subsequently be accessible using [buildLocalGet], [buildLocalSet], etc.
- void _buildClosureScopeSetup(ClosureScope scope);
+ /// Called when entering a function body or loop body.
+ ///
+ /// This is not called for for-loops, which instead use the methods
+ /// [_enterForLoopInitializer], [_enterForLoopBody], and [_enterForLoopUpdate]
+ /// due to their special scoping rules.
+ ///
+ /// The boxed variables declared in this scope must subsequently be available
+ /// using [buildLocalGet], [buildLocalSet], etc.
+ void _enterScope(ClosureScope scope);
+
+ /// Called before building the initializer of a for-loop.
+ ///
+ /// The loop variables will subsequently be declared using
+ /// [declareLocalVariable].
+ void _enterForLoopInitializer(ClosureScope scope,
+ List<LocalElement> loopVariables);
+
+ /// Called before building the body of a for-loop.
+ void _enterForLoopBody(ClosureScope scope,
+ List<LocalElement> loopVariables);
+
+ /// Called before building the update of a for-loop.
+ void _enterForLoopUpdate(ClosureScope scope,
+ List<LocalElement> loopVariables);
/// 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);
+ /// Returns the list of closure variables declared in the given function or
+ /// field initializer.
+ List<ir.ClosureVariable> _getDeclaredClosureVariables(ExecutableElement elm);
+
+ /// 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();
// 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>[];
- IrBuilderSharedState state;
-
- IrBuilderClosureState closure;
+ IrBuilderDelimitedState state;
/// A map from variable indexes to their values.
///
@@ -306,8 +301,7 @@ abstract class IrBuilder {
/// Initialize a new top-level IR builder.
void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
- state = new IrBuilderSharedState(constantSystem, currentElement);
- closure = new IrBuilderClosureState();
+ state = new IrBuilderDelimitedState(constantSystem, currentElement);
environment = new Environment.empty();
}
@@ -320,7 +314,6 @@ abstract class IrBuilder {
IrBuilder makeDelimitedBuilder() {
return _makeInstance()
..state = state
- ..closure = closure
..environment = new Environment.from(environment);
}
@@ -335,7 +328,6 @@ abstract class IrBuilder {
IrBuilder makeRecursiveBuilder() {
IrBuilder inner = _makeInstance()
..state = state
- ..closure = closure
..environment = new Environment.empty();
environment.index2variable.forEach(inner.createLocalParameter);
return inner;
@@ -344,8 +336,7 @@ abstract class IrBuilder {
/// Construct a builder for an inner function.
IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
return _makeInstance()
- ..state = new IrBuilderSharedState(state.constantSystem, currentElement)
- ..closure = closure
+ ..state = new IrBuilderDelimitedState(state.constantSystem, currentElement)
..environment = new Environment.empty();
}
@@ -353,14 +344,14 @@ abstract class IrBuilder {
void buildFieldInitializerHeader({ClosureScope closureScope}) {
- _buildClosureScopeSetup(closureScope);
+ _enterScope(closureScope);
}
void buildFunctionHeader(Iterable<ParameterElement> parameters,
{ClosureScope closureScope,
ClosureEnvironment closureEnvironment}) {
- _buildClosureEnvironmentSetup(closureEnvironment);
- _buildClosureScopeSetup(closureScope);
+ _enterClosureEnvironment(closureEnvironment);
+ _enterScope(closureScope);
parameters.forEach(_createFunctionParameter);
}
@@ -615,7 +606,8 @@ abstract class IrBuilder {
ir.RunnableBody body = makeRunnableBody();
return new ir.FunctionDefinition(
element, state.functionParameters, body,
- state.localConstants, defaults, closure.getClosureList(element));
+ state.localConstants, defaults,
+ _getDeclaredClosureVariables(element));
}
}
@@ -635,7 +627,7 @@ abstract class IrBuilder {
return new ir.ConstructorDefinition(
element, state.functionParameters, body, initializers,
state.localConstants, defaults,
- closure.getClosureList(element));
+ _getDeclaredClosureVariables(element));
}
/// Create a super invocation where the method name and the argument structure
@@ -870,12 +862,16 @@ abstract class IrBuilder {
/// 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.
+ ///
+ /// [loopVariables] is the list of variables declared in the for-loop
+ /// initializer.
void buildFor({SubbuildFunction buildInitializer,
SubbuildFunction buildCondition,
SubbuildFunction buildBody,
SubbuildFunction buildUpdate,
JumpTarget target,
- ClosureScope closureScope}) {
+ ClosureScope closureScope,
+ List<LocalElement> loopVariables}) {
assert(isOpen);
// For loops use four named continuations: the entry to the condition,
@@ -900,19 +896,7 @@ abstract 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);
- }
+ _enterForLoopInitializer(closureScope, loopVariables);
buildInitializer(this);
@@ -930,11 +914,7 @@ abstract class IrBuilder {
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);
- }
+ bodyBuilder._enterForLoopBody(closureScope, loopVariables);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
@@ -950,9 +930,7 @@ abstract class IrBuilder {
IrBuilder updateBuilder = hasContinues
? condBuilder.makeRecursiveBuilder()
: bodyBuilder;
- if (hasBoxedLoopVariables) {
- updateBuilder._migrateLoopVariables(closureScope);
- }
+ updateBuilder._enterForLoopUpdate(closureScope, loopVariables);
buildUpdate(updateBuilder);
// Create body entry and loop exit continuations and a branch to them.
@@ -1078,7 +1056,7 @@ abstract class IrBuilder {
state.continueCollectors.add(continueCollector);
IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
- bodyBuilder._buildClosureScopeSetup(closureScope);
+ bodyBuilder._enterScope(closureScope);
if (buildVariableDeclaration != null) {
buildVariableDeclaration(bodyBuilder);
}
@@ -1183,7 +1161,7 @@ abstract class IrBuilder {
state.continueCollectors.add(continueCollector);
IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
- bodyBuilder._buildClosureScopeSetup(closureScope);
+ bodyBuilder._enterScope(closureScope);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
assert(state.continueCollectors.last == continueCollector);
@@ -1434,17 +1412,6 @@ abstract class IrBuilder {
return joinContinuation.parameters.last;
}
- /// 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() {
- 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.
///
/// Given the environment length at the join point and a list of
@@ -1551,6 +1518,39 @@ abstract class IrBuilder {
}
}
+/// Shared state between DartIrBuilders within the same method.
+class DartIrBuilderSharedState {
+ /// Maps local variables to their corresponding [ClosureVariable] object.
+ final Map<Local, ir.ClosureVariable> local2closure =
+ <Local, ir.ClosureVariable>{};
+
+ /// Maps functions to the list of closure variables declared in that function.
+ final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures =
+ <ExecutableElement, List<ir.ClosureVariable>>{};
+
+ final ClosureVariableInfo closureVariables;
+
+ /// Returns the closure variables declared in the given function.
+ List<ir.ClosureVariable> getClosureList(ExecutableElement element) {
+ return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]);
+ }
+
+ /// 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);
+ }
+
+ /// Closure variables that should temporarily be treated as registers.
+ final Set<Local> registerizedClosureVariables = new Set<Local>();
+
+ DartIrBuilderSharedState(this.closureVariables) {
+ closureVariables.capturedVariables.forEach(makeClosureVariable);
+ }
+}
+
/// Dart-specific subclass of [IrBuilder].
///
/// Inner functions are represented by a [FunctionDefinition] with the
@@ -1559,38 +1559,80 @@ abstract class IrBuilder {
/// Captured variables are translated to ref cells (see [ClosureVariable])
/// using [GetClosureVariable] and [SetClosureVariable].
class DartIrBuilder extends IrBuilder {
- ClosureVariableInfo closureVariables;
+ final DartIrBuilderSharedState dartState;
- IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables);
- DartIrBuilder._blank(this.closureVariables);
+ IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState);
+ DartIrBuilder._blank(this.dartState);
DartIrBuilder(ConstantSystem constantSystem,
ExecutableElement currentElement,
- this.closureVariables) {
+ ClosureVariableInfo closureVariables)
+ : dartState = new DartIrBuilderSharedState(closureVariables) {
_init(constantSystem, currentElement);
- closureVariables.capturedVariables.forEach(closure.makeClosureVariable);
}
- /// True if [local] is stored in a [ClosureVariable].
+ /// True if [local] should currently be accessed from a [ClosureVariable].
bool isInClosureVariable(Local local) {
- return closure.local2closure.containsKey(local);
+ return dartState.local2closure.containsKey(local) &&
+ !dartState.registerizedClosureVariables.contains(local);
}
/// Gets the [ClosureVariable] containing the value of [local].
ir.ClosureVariable getClosureVariable(Local local) {
- return closure.local2closure[local];
+ return dartState.local2closure[local];
}
- void _buildClosureScopeSetup(ClosureScope scope) {
+ void _enterScope(ClosureScope scope) {
assert(scope == null);
}
- void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
+ void _enterClosureEnvironment(ClosureEnvironment env) {
assert(env == null);
}
- void _migrateLoopVariables(ClosureScope scope) {
+ void _enterForLoopInitializer(ClosureScope scope,
+ List<LocalElement> loopVariables) {
+ assert(scope == null);
+ for (LocalElement loopVariable in loopVariables) {
+ if (dartState.local2closure.containsKey(loopVariable)) {
+ // Temporarily keep the loop variable in a primitive.
+ // The loop variable will be added to environment when
+ // [declareLocalVariable] is called.
+ dartState.registerizedClosureVariables.add(loopVariable);
+ }
+ }
+ }
+
+ void _enterForLoopBody(ClosureScope scope,
+ List<LocalElement> loopVariables) {
assert(scope == null);
+ for (LocalElement loopVariable in loopVariables) {
+ if (dartState.local2closure.containsKey(loopVariable)) {
+ // Move from primitive into ClosureVariable.
+ dartState.registerizedClosureVariables.remove(loopVariable);
+ add(new ir.SetClosureVariable(getClosureVariable(loopVariable),
+ environment.lookup(loopVariable),
+ isDeclaration: true));
+ }
+ }
+ }
+
+ void _enterForLoopUpdate(ClosureScope scope,
+ List<LocalElement> loopVariables) {
+ assert(scope == null);
+ // Move captured loop variables back into the local environment.
+ // The update expression will use the values we put in the environment,
+ // and then the environments for the initializer and update will be
+ // joined at the head of the body.
+ for (LocalElement loopVariable in loopVariables) {
+ if (isInClosureVariable(loopVariable)) {
+ ir.ClosureVariable closureVariable = getClosureVariable(loopVariable);
+ ir.Primitive get = new ir.GetClosureVariable(closureVariable);
+ add(new ir.LetPrim(get));
+ environment.update(loopVariable, get);
+ dartState.registerizedClosureVariables.add(loopVariable);
+ }
+ }
}
void _createFunctionParameter(ParameterElement parameterElement) {
@@ -1669,7 +1711,29 @@ class DartIrBuilder extends IrBuilder {
return value;
}
+ List<ir.ClosureVariable> _getDeclaredClosureVariables(
+ ExecutableElement element) {
+ return dartState.getClosureList(element);
+ }
+
+ ir.Primitive buildThis() {
+ ir.Primitive thisPrim = new ir.This();
+ add(new ir.LetPrim(thisPrim));
+ return thisPrim;
+ }
+
+}
+
+/// State shared between JsIrBuilders within the same function.
+///
+/// Note that this is not shared between builders of nested functions.
+class JsIrBuilderSharedState {
+ /// 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;
}
/// JS-specific subclass of [IrBuilder].
@@ -1677,14 +1741,17 @@ class DartIrBuilder extends 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();
+ final JsIrBuilderSharedState jsState;
- JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) {
+ IrBuilder _makeInstance() => new JsIrBuilder._blank(jsState);
+ JsIrBuilder._blank(this.jsState);
+
+ JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement)
+ : jsState = new JsIrBuilderSharedState() {
_init(constantSystem, currentElement);
}
- void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
+ void _enterClosureEnvironment(ClosureEnvironment env) {
if (env == null) return;
// Obtain a reference to the function object (this).
@@ -1695,7 +1762,7 @@ class JsIrBuilder extends IrBuilder {
env.freeVariables.forEach((Local local, ClosureLocation location) {
if (location.isBox) {
// Boxed variables are loaded from their box on-demand.
- state.boxedVariables[local] = location;
+ jsState.boxedVariables[local] = location;
} else {
// Unboxed variables are loaded from the function object immediately.
// This includes BoxLocals which are themselves unboxed variables.
@@ -1708,7 +1775,7 @@ class JsIrBuilder extends IrBuilder {
// 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);
+ jsState.receiver = environment.lookup(env.thisLocal);
}
// If the function has a self-reference, use the value of `this`.
@@ -1717,16 +1784,16 @@ class JsIrBuilder extends IrBuilder {
}
}
- void _buildClosureScopeSetup(ClosureScope scope) {
+ void _enterScope(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));
+ assert(!jsState.boxedVariables.containsKey(local));
if (location.isBox) {
- state.boxedVariables[local] = location;
+ jsState.boxedVariables[local] = location;
}
});
}
@@ -1735,7 +1802,7 @@ class JsIrBuilder extends IrBuilder {
ir.Parameter parameter = new ir.Parameter(parameterElement);
_parameters.add(parameter);
state.functionParameters.add(parameter);
- ClosureLocation location = state.boxedVariables[parameterElement];
+ ClosureLocation location = jsState.boxedVariables[parameterElement];
if (location != null) {
add(new ir.SetField(environment.lookup(location.box),
location.field,
@@ -1751,7 +1818,7 @@ class JsIrBuilder extends IrBuilder {
if (initialValue == null) {
initialValue = buildNullLiteral();
}
- ClosureLocation location = state.boxedVariables[variableElement];
+ ClosureLocation location = jsState.boxedVariables[variableElement];
if (location != null) {
add(new ir.SetField(environment.lookup(location.box),
location.field,
@@ -1782,7 +1849,7 @@ class JsIrBuilder extends IrBuilder {
/// Create a read access of [local].
ir.Primitive buildLocalGet(LocalElement local) {
assert(isOpen);
- ClosureLocation location = state.boxedVariables[local];
+ ClosureLocation location = jsState.boxedVariables[local];
if (location != null) {
ir.Primitive result = new ir.GetField(environment.lookup(location.box),
location.field);
@@ -1797,7 +1864,7 @@ class JsIrBuilder extends IrBuilder {
/// 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];
+ ClosureLocation location = jsState.boxedVariables[local];
if (location != null) {
add(new ir.SetField(environment.lookup(location.box),
location.field,
@@ -1809,8 +1876,30 @@ class JsIrBuilder extends IrBuilder {
return value;
}
- void _migrateLoopVariables(ClosureScope scope) {
+ void _enterForLoopInitializer(ClosureScope scope,
+ List<LocalElement> loopVariables) {
+ if (scope == null) return;
+ // If there are no boxed loop variables, don't create the box here, let
+ // it be created inside the body instead.
+ if (scope.boxedLoopVariables.isEmpty) return;
+ _enterScope(scope);
+ }
+
+ void _enterForLoopBody(ClosureScope scope,
+ List<LocalElement> loopVariables) {
if (scope == null) return;
+ // If there are boxed loop variables, the box has already been created
+ // at the initializer.
+ if (!scope.boxedLoopVariables.isEmpty) return;
+ _enterScope(scope);
+ }
+
+ void _enterForLoopUpdate(ClosureScope scope,
+ List<LocalElement> loopVariables) {
+ if (scope == null) return;
+ // If there are no boxed loop variables, then the box is created inside the
+ // body, so there is no need to explicitly renew it.
+ if (scope.boxedLoopVariables.isEmpty) return;
ir.Primitive box = environment.lookup(scope.box);
ir.Primitive newBox = new ir.CreateBox();
newBox.useElementAsHint(scope.box);
@@ -1824,6 +1913,17 @@ class JsIrBuilder extends IrBuilder {
environment.update(scope.box, newBox);
}
+ List<ir.ClosureVariable> _getDeclaredClosureVariables(
+ ExecutableElement element) {
+ return <ir.ClosureVariable>[];
+ }
+
+ ir.Primitive buildThis() {
+ if (jsState.receiver != null) return jsState.receiver;
+ ir.Primitive thisPrim = new ir.This();
+ add(new ir.LetPrim(thisPrim));
+ return thisPrim;
+ }
}
@@ -1880,6 +1980,7 @@ class ClosureEnvironment {
}
/// Information about which variables are captured in a closure.
+///
/// This is used by the [DartIrBuilder] instead of [ClosureScope] and
/// [ClosureEnvironment].
abstract class ClosureVariableInfo {
« no previous file with comments | « pkg/analyzer2dart/lib/src/cps_generator.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