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

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

Issue 831133004: Use closure conversion in new dart2js backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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_visitor.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
index 8d4778116bf392758d3ccfaf88c401c9a8c3bb5c..5880c716b39df9133db756fee42834b2eab982a8 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
@@ -108,6 +108,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
with IrBuilderMixin<ast.Node> {
final Compiler compiler;
final SourceFile sourceFile;
+ ClosureClassMap closureMap;
// In SSA terms, join-point continuation parameters are the phis and the
// continuation invocation arguments are the corresponding phi inputs. To
@@ -131,6 +132,10 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
: super(elements);
+ /// True if using the JavaScript backend; we use this to determine how
+ /// closures should be translated.
+ bool get isJavaScriptBackend => compiler.backend is JavaScriptBackend;
+
/**
* Builds the [ir.ExecutableDefinition] for an executable element. In case the
* function uses features that cannot be expressed in the IR, this element
@@ -148,6 +153,58 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
});
}
+ Map mapValues(Map map, dynamic fn(dynamic)) {
+ Map result = {};
+ map.forEach((key,value) {
floitsch 2015/01/08 18:29:36 indentation and missing space.
asgerf 2015/01/12 13:15:43 Done.
+ result[key] = fn(value);
+ });
+ return result;
+ }
+
+ ClosureLocation getLocation(CapturedVariable v) {
+ if (v is BoxFieldElement) {
+ return new ClosureLocation(v.box, v);
+ } else {
+ return new ClosureLocation(null, v as ClosureFieldElement);
floitsch 2015/01/08 18:29:37 It's stupid but we avoid `as`. Just create a tempo
asgerf 2015/01/12 13:15:43 Done.
+ }
+ }
+
+ ClosureEnvironment getClosureEnvironment() {
+ if (closureMap == null) return null; // dart2dart does not use closureMap
floitsch 2015/01/08 18:29:37 Finish comment with ".".
asgerf 2015/01/12 13:15:43 Done.
+ if (closureMap.closureElement == null) return null;
+ return new ClosureEnvironment(
+ closureMap.closureElement,
+ closureMap.thisLocal,
+ mapValues(closureMap.freeVariableMap, getLocation));
+ }
+
+ ClosureScope getClosureScope(ast.Node node) {
floitsch 2015/01/08 18:29:36 Add lots of documentation. I wrote the closure.dar
asgerf 2015/01/12 13:15:43 Done.
+ if (closureMap == null) return null; // dart2dart does not use closureMap
floitsch 2015/01/08 18:29:37 ditto.
asgerf 2015/01/12 13:15:43 Done.
+ closurelib.ClosureScope scope = closureMap.capturingScopes[node];
+ if (scope == null) return null;
+ return new ClosureScope(scope.boxElement,
+ mapValues(scope.capturedVariables, getLocation),
+ scope.boxedLoopVariables);
+ }
+
+ IrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
+ if (isJavaScriptBackend) {
+ closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
+ element,
+ node,
+ elements);
+ return new JsIrBuilder(compiler.backend.constantSystem, element);
+ } else {
+ DetectClosureVariables closures = new DetectClosureVariables(elements);
+ if (!element.isSynthesized) {
+ closures.visit(node);
+ }
+ return new DartIrBuilder(compiler.backend.constantSystem,
+ element,
+ closures);
+ }
+ }
+
/// Returns a [ir.FieldDefinition] describing the initializer of [element].
/// Returns `null` if [element] has no initializer.
ir.FieldDefinition buildField(FieldElement element) {
@@ -160,14 +217,11 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
}
assert(fieldDefinition != null);
assert(elements[fieldDefinition] != null);
- DetectClosureVariables closureLocals =
- new DetectClosureVariables(elements);
- closureLocals.visit(fieldDefinition);
- IrBuilder builder = new IrBuilder(compiler.backend.constantSystem,
- element,
- closureLocals.usedFromClosure);
+ IrBuilder builder = makeIRBuilder(fieldDefinition, element);
+
return withBuilder(builder, () {
+ builder.beginField(closureScope: getClosureScope(fieldDefinition));
floitsch 2015/01/08 18:29:37 I would rename this call to something like buildFi
asgerf 2015/01/13 10:04:26 Everything in this class is already randomly prefi
ir.Primitive initializer;
if (fieldDefinition is ast.SendSet) {
ast.SendSet sendSet = fieldDefinition;
@@ -180,9 +234,12 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
ast.FunctionExpression node) {
FunctionSignature signature = element.functionSignature;
- signature.orderedForEachParameter((ParameterElement parameterElement) {
- irBuilder.createFunctionParameter(parameterElement);
- });
+ List<ParameterElement> parameters = [];
+ signature.orderedForEachParameter(parameters.add);
+
+ irBuilder.beginFunction(parameters,
floitsch 2015/01/08 18:29:37 ditto.
+ closureScope: getClosureScope(node),
+ closureEnvironment: getClosureEnvironment());
List<ConstantExpression> defaults = new List<ConstantExpression>();
signature.orderedOptionalParameters.forEach((ParameterElement element) {
@@ -212,7 +269,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
void tryAddInitializingFormal(ParameterElement parameterElement) {
if (parameterElement.isInitializingFormal) {
InitializingFormalElement initializingFormal = parameterElement;
- withBuilder(new IrBuilder.delimited(irBuilder), () {
+ withBuilder(irBuilder.makeDelimitedBuilder(), () {
ir.Primitive value = irBuilder.buildLocalGet(parameterElement);
result.add(irBuilder.makeFieldInitializer(
initializingFormal.fieldElement,
@@ -230,7 +287,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
if (initializer is ast.SendSet) {
// Field initializer.
FieldElement field = elements[initializer];
- withBuilder(new IrBuilder.delimited(irBuilder), () {
+ withBuilder(irBuilder.makeDelimitedBuilder(), () {
ir.Primitive value = visit(initializer.arguments.head);
ir.RunnableBody body = irBuilder.makeRunnableBody(value);
result.add(irBuilder.makeFieldInitializer(field, body));
@@ -244,7 +301,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
Selector selector = elements.getSelector(initializer);
List<ir.RunnableBody> arguments =
initializer.arguments.mapToList((ast.Node argument) {
- return withBuilder(new IrBuilder.delimited(irBuilder), () {
+ return withBuilder(irBuilder.makeDelimitedBuilder(), () {
ir.Primitive value = visit(argument);
return irBuilder.makeRunnableBody(value);
});
@@ -288,12 +345,6 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
if (!element.isSynthesized) {
assert(node != null);
assert(elements[node] != null);
-
- // TODO(karlklose): this information should be provided by resolution.
- DetectClosureVariables closureLocals =
- new DetectClosureVariables(elements);
- closureLocals.visit(node);
- usedFromClosure = closureLocals.usedFromClosure;
} else {
SynthesizedConstructorElementX constructor = element;
if (!constructor.isDefaultConstructor) {
@@ -303,9 +354,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
usedFromClosure = <Entity>[];
}
- IrBuilder builder = new IrBuilder(compiler.backend.constantSystem,
- element,
- usedFromClosure);
+ IrBuilder builder = makeIRBuilder(node, element);
return withBuilder(builder, () => _makeFunctionBody(element, node));
}
@@ -346,12 +395,12 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
}
visitFor(ast.For node) {
- // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop.
- if (node.initializer is ast.VariableDefinitions) {
+ // TODO(asgerf): Handle closure variables declared in a for-loop.
+ if (!isJavaScriptBackend && node.initializer is ast.VariableDefinitions) {
ast.VariableDefinitions definitions = node.initializer;
for (ast.Node definition in definitions.definitions.nodes) {
- Element element = elements[definition];
- if (irBuilder.isClosureVariable(element)) {
+ LocalElement element = elements[definition];
+ if ((irBuilder as DartIrBuilder).isInRefCell(element)) {
floitsch 2015/01/08 18:29:36 ditto: we don't use `as`. Just assign to a tempora
return giveup(definition, 'Closure variable in for loop initializer');
}
}
@@ -363,6 +412,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
buildCondition: subbuild(node.condition),
buildBody: subbuild(node.body),
buildUpdate: subbuildSequence(node.update),
+ closureScope: getClosureScope(node),
target: target);
}
@@ -379,7 +429,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
JumpTarget target = elements.getTargetDefinition(body);
JumpCollector jumps = new JumpCollector(target);
irBuilder.state.breakCollectors.add(jumps);
- IrBuilder innerBuilder = new IrBuilder.delimited(irBuilder);
+ IrBuilder innerBuilder = irBuilder.makeDelimitedBuilder();
withBuilder(innerBuilder, () {
visit(body);
});
@@ -420,7 +470,8 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
irBuilder.buildWhile(
buildCondition: subbuild(node.condition),
buildBody: subbuild(node.body),
- target: elements.getTargetDefinition(node));
+ target: elements.getTargetDefinition(node),
+ closureScope: getClosureScope(node));
}
visitForIn(ast.ForIn node) {
@@ -439,7 +490,8 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
variableElement: variableElement,
variableSelector: selector,
buildBody: subbuild(node.body),
- target: elements.getTargetDefinition(node));
+ target: elements.getTargetDefinition(node),
+ closureScope: getClosureScope(node));
}
ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
@@ -950,13 +1002,21 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
return irBuilder.buildConstantLiteral(constant);
}
- ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
- FunctionElement element = elements[node];
- assert(invariant(element, element.isImplementation));
+ /// Returns the backend-specific representation of an inner function.
+ Object makeSubFunction(ast.FunctionExpression node) {
+ if (isJavaScriptBackend) {
+ ClosureClassMap innerMap =
+ compiler.closureToClassMapper.getMappingForNestedFunction(node);
+ ClosureClassElement closureClass = innerMap.closureClassElement;
+ return closureClass;
+ } else {
+ FunctionElement element = elements[node];
+ assert(invariant(element, element.isImplementation));
- IrBuilder builder = new IrBuilder.innerFunction(irBuilder, element);
+ IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
- return withBuilder(builder, () => _makeFunctionBody(element, node));
+ return withBuilder(builder, () => _makeFunctionBody(element, node));
+ }
}
ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
@@ -965,7 +1025,7 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
visitFunctionDeclaration(ast.FunctionDeclaration node) {
LocalFunctionElement element = elements[node.function];
- ir.FunctionDefinition inner = makeSubFunction(node.function);
+ Object inner = makeSubFunction(node.function);
irBuilder.declareLocalFunction(element, inner);
}
@@ -994,19 +1054,17 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
/// Classifies local variables and local functions as 'closure variables'.
/// A closure variable is one that is accessed from an inner function nested
/// one or more levels inside the one that declares it.
-class DetectClosureVariables extends ast.Visitor {
+class DetectClosureVariables extends ast.Visitor
+ implements ClosureVariableInfo {
final TreeElements elements;
DetectClosureVariables(this.elements);
FunctionElement currentFunction;
bool insideInitializer = false;
- Set<Local> usedFromClosure = new Set<Local>();
- Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
-
- bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity);
+ Set<Local> capturedVariables = new Set<Local>();
floitsch 2015/01/08 18:29:37 nit: maybe go directly for a Setlet ?
void markAsClosureVariable(Local local) {
- usedFromClosure.add(local);
+ capturedVariables.add(local);
}
visit(ast.Node node) => node.accept(this);

Powered by Google App Engine
This is Rietveld 408576698