Chromium Code Reviews| 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); |