Chromium Code Reviews| Index: lib/compiler/implementation/closure.dart |
| diff --git a/lib/compiler/implementation/closure.dart b/lib/compiler/implementation/closure.dart |
| index 565421adc72dcf0da5acd93510b0f9866f158208..4a80dc4e22d9004574fa2eab9f3b66bb0507697d 100644 |
| --- a/lib/compiler/implementation/closure.dart |
| +++ b/lib/compiler/implementation/closure.dart |
| @@ -18,7 +18,8 @@ class ClosureTask extends CompilerTask { |
| String get name => "Closure Simplifier"; |
| - ClosureClassMap computeClosureToClassMapping(FunctionExpression node, |
| + ClosureClassMap computeClosureToClassMapping(Element element, |
| + Expression node, |
| TreeElements elements) { |
| return measure(() { |
| ClosureClassMap cached = closureMappingCache[node]; |
| @@ -26,9 +27,16 @@ class ClosureTask extends CompilerTask { |
| ClosureTranslator translator = |
| new ClosureTranslator(compiler, elements, closureMappingCache); |
| + |
| // The translator will store the computed closure-mappings inside the |
| - // cache. One for given method and one for each nested closure. |
| - translator.translate(node); |
| + // cache. One for given node and one for each nested closure. |
| + if (node is FunctionExpression) { |
| + translator.translateFunction(element, node); |
| + } else { |
| + // Must be the lazy initializer of a static. |
| + assert(node is SendSet); |
| + translator.translateLazyInitializer(element, node); |
| + } |
| assert(closureMappingCache[node] != null); |
| return closureMappingCache[node]; |
| }); |
| @@ -113,7 +121,7 @@ class ClosureScope { |
| class ClosureClassMap { |
| // The closure's element before any translation. Will be null for methods. |
| - final FunctionElement closureElement; |
| + final Element closureElement; |
| // The closureClassElement will be null for methods that are not local |
| // closures. |
| final ClassElement closureClassElement; |
| @@ -170,7 +178,7 @@ class ClosureTranslator extends AbstractVisitor { |
| // will update this mapping. |
| Map<Element, Element> capturedVariableMapping; |
| // List of encountered closures. |
| - List<FunctionExpression> closures; |
| + List<Expression> closures; |
| // The variables that have been declared in the current scope. |
| List<Element> scopeVariables; |
| @@ -179,8 +187,8 @@ class ClosureTranslator extends AbstractVisitor { |
| // non-mutated variables. |
| Set<Element> mutatedVariables; |
| - FunctionElement outermostFunctionElement; |
| - FunctionElement currentFunctionElement; |
| + Element outermostElement; |
| + Element currentElement; |
| // The closureData of the currentFunctionElement. |
| ClosureClassMap closureData; |
| @@ -189,11 +197,11 @@ class ClosureTranslator extends AbstractVisitor { |
| ClosureTranslator(this.compiler, this.elements, this.closureMappingCache) |
| : capturedVariableMapping = new Map<Element, Element>(), |
| - closures = <FunctionExpression>[], |
| + closures = <Expression>[], |
| mutatedVariables = new Set<Element>(); |
| - void translate(Node node) { |
| - visit(node); |
| + void translateFunction(Element element, FunctionExpression node) { |
|
kasperl
2012/09/10 13:44:29
So here you're ignoring the element you're passed
floitsch
2012/10/09 16:06:44
Done.
|
| + visit(node); // [visitFunctionExpression] will call [visitInvokable]. |
| // When variables need to be boxed their [capturedVariableMapping] is |
| // updated, but we delay updating the similar freeVariableMapping in the |
| // closure datas that capture these variables. |
| @@ -201,12 +209,18 @@ class ClosureTranslator extends AbstractVisitor { |
| updateClosures(); |
| } |
| + void translateLazyInitializer(Element element, SendSet node) { |
| + assert(node.assignmentOperator.source == const SourceString("=")); |
| + Expression initialValue = node.argumentsNode.nodes.head; |
| + visitInvokable(element, node, () { visit(initialValue); }); |
| + } |
| + |
| // This function runs through all of the existing closures and updates their |
| // free variables to the boxed value. It also adds the field-elements to the |
| // class representing the closure. At the same time it fills the |
| // [capturedFieldMapping]. |
| void updateClosures() { |
| - for (FunctionExpression closure in closures) { |
| + for (Expression closure in closures) { |
| // The captured variables that need to be stored in a field of the closure |
| // class. |
| Set<Element> fieldCaptures = new Set<Element>(); |
| @@ -260,8 +274,8 @@ class ClosureTranslator extends AbstractVisitor { |
| // parameters, and type parameters are declared in the class, not |
| // the factory. |
| if (insideClosure && |
| - element.enclosingElement != currentFunctionElement && |
| - element != currentFunctionElement) { |
| + element.enclosingElement != currentElement && |
| + element != currentElement) { |
| assert(closureData.freeVariableMapping[element] == null || |
| closureData.freeVariableMapping[element] == element); |
| closureData.freeVariableMapping[element] = element; |
| @@ -374,10 +388,10 @@ class ClosureTranslator extends AbstractVisitor { |
| } |
| } |
| - if (outermostFunctionElement.isInstanceMember() |
| - || outermostFunctionElement.isGenerativeConstructor()) { |
| + if (outermostElement.isInstanceMember() |
| + || outermostElement.isGenerativeConstructor()) { |
| if (hasTypeVariable(type)) useLocal(closureData.thisElement); |
| - } else if (outermostFunctionElement.isFactoryConstructor()) { |
| + } else if (outermostElement.isFactoryConstructor()) { |
| analyzeTypeVariables(type); |
| } |
| @@ -400,7 +414,7 @@ class ClosureTranslator extends AbstractVisitor { |
| // TODO(floitsch): construct better box names. |
| SourceString boxName = |
| new SourceString("box_${closureFieldCounter++}"); |
| - box = new BoxElement(boxName, currentFunctionElement); |
| + box = new BoxElement(boxName, currentElement); |
| } |
| // TODO(floitsch): construct better boxed names. |
| String elementName = element.name.slowToString(); |
| @@ -507,25 +521,18 @@ class ClosureTranslator extends AbstractVisitor { |
| callElement, thisElement); |
| } |
| - visitFunctionExpression(FunctionExpression node) { |
| - Element element = elements[node]; |
| - if (element.isParameter()) { |
| - // TODO(ahe): This is a hack. This method should *not* call |
| - // visitChildren. |
| - return node.name.accept(this); |
| - } |
| - |
| + void visitInvokable(Element element, Expression node, void visitChildren()) { |
| bool oldInsideClosure = insideClosure; |
| - FunctionElement oldFunctionElement = currentFunctionElement; |
| + Element oldFunctionElement = currentElement; |
| ClosureClassMap oldClosureData = closureData; |
| - insideClosure = outermostFunctionElement != null; |
| - currentFunctionElement = element; |
| + insideClosure = outermostElement != null; |
| + currentElement = element; |
| if (insideClosure) { |
| closures.add(node); |
| closureData = globalizeClosure(node, element); |
| } else { |
| - outermostFunctionElement = element; |
| + outermostElement = element; |
| Element thisElement = null; |
| if (element.isInstanceMember() || element.isGenerativeConstructor()) { |
| thisElement = new ThisElement(element); |
| @@ -547,22 +554,16 @@ class ClosureTranslator extends AbstractVisitor { |
| declareLocal(element); |
| } |
| - if (currentFunctionElement.isFactoryConstructor()) { |
| + if (currentElement.isFactoryConstructor()) { |
| // Declare the type parameters in the scope. Generative |
| // constructors just use 'this'. |
| - ClassElement cls = currentFunctionElement.enclosingElement; |
| + ClassElement cls = currentElement.enclosingElement; |
| cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| declareLocal(typeVariable.element); |
| }); |
| } |
| - // TODO(ahe): This is problematic. The backend should not repeat |
| - // the work of the resolver. It is the resolver's job to create |
| - // parameters, etc. Other phases should only visit statements. |
| - // TODO(floitsch): we avoid visiting the initializers on purpose so that |
| - // we get an error-message later in the builder. |
| - if (node.parameters !== null) node.parameters.accept(this); |
| - if (node.body !== null) node.body.accept(this); |
| + visitChildren(); |
| }); |
| @@ -572,7 +573,7 @@ class ClosureTranslator extends AbstractVisitor { |
| // Restore old values. |
| insideClosure = oldInsideClosure; |
| closureData = oldClosureData; |
| - currentFunctionElement = oldFunctionElement; |
| + currentElement = oldFunctionElement; |
| // Mark all free variables as captured and use them in the outer function. |
| List<Element> freeVariables = |
| @@ -588,6 +589,26 @@ class ClosureTranslator extends AbstractVisitor { |
| } |
| } |
| + visitFunctionExpression(FunctionExpression node) { |
| + Element element = elements[node]; |
| + |
| + if (element.isParameter()) { |
| + // TODO(ahe): This is a hack. This method should *not* call |
| + // visitChildren. |
| + return node.name.accept(this); |
| + } |
| + |
| + visitInvokable(element, node, () { |
| + // TODO(ahe): This is problematic. The backend should not repeat |
| + // the work of the resolver. It is the resolver's job to create |
| + // parameters, etc. Other phases should only visit statements. |
| + // TODO(floitsch): we avoid visiting the initializers on purpose so that |
| + // we get an error-message later in the builder. |
| + if (node.parameters !== null) node.parameters.accept(this); |
| + if (node.body !== null) node.body.accept(this); |
| + }); |
| + } |
| + |
| visitFunctionDeclaration(FunctionDeclaration node) { |
| node.visitChildren(this); |
| declareLocal(elements[node]); |