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); |