Index: lib/compiler/implementation/ssa/builder.dart |
=================================================================== |
--- lib/compiler/implementation/ssa/builder.dart (revision 14321) |
+++ lib/compiler/implementation/ssa/builder.dart (working copy) |
@@ -322,15 +322,21 @@ |
* If the scope (function or loop) [node] has captured variables then this |
* method creates a box and sets up the redirections. |
*/ |
- void enterScope(Node node) { |
+ void enterScope(Node node, Element element) { |
// See if any variable in the top-scope of the function is captured. If yes |
// we need to create a box-object. |
ClosureScope scopeData = closureData.capturingScopes[node]; |
if (scopeData != null) { |
- // The scope has captured variables. Create a box. |
- // TODO(floitsch): Clean up this hack. Should we create a box-object by |
- // just creating an empty object literal? |
- HInstruction box = createBox(); |
+ HInstruction box; |
+ // The scope has captured variables. |
+ if (element != null && element.isGenerativeConstructorBody()) { |
+ // The box is passed as a parameter to a generative |
+ // constructor body. |
+ box = new HParameterValue(scopeData.boxElement); |
+ builder.add(box); |
+ } else { |
+ box = createBox(); |
+ } |
// Add the box to the known locals. |
directLocals[scopeData.boxElement] = box; |
// Make sure that accesses to the boxed locals go into the box. We also |
@@ -398,7 +404,7 @@ |
}); |
} |
- enterScope(node); |
+ enterScope(node, element); |
// If the freeVariableMapping is not empty, then this function was a |
// nested closure that captures variables. Redirect the captured |
@@ -610,7 +616,7 @@ |
// redirections already now. This way the initializer can write its |
// values into the box. |
// For other loops the box will be created when entering the body. |
- enterScope(node); |
+ enterScope(node, null); |
} |
} |
@@ -641,7 +647,7 @@ |
// If there are no declared boxed loop variables then we did not create the |
// box before the initializer and we have to create the box now. |
if (!scopeData.hasBoxedLoopVariables()) { |
- enterScope(node); |
+ enterScope(node, null); |
} |
} |
@@ -1170,16 +1176,17 @@ |
compiler.enqueuer.resolution.getCachedElements(constructor); |
ClosureClassMap oldClosureData = localsHandler.closureData; |
+ Node node = constructor.parseNode(compiler); |
localsHandler.closureData = |
compiler.closureToClassMapper.computeClosureToClassMapping( |
- constructor, constructor.parseNode(compiler), elements); |
+ constructor, node, elements); |
params.orderedForEachParameter((Element parameterElement) { |
if (elements.isParameterChecked(parameterElement)) { |
addParameterCheckInstruction(parameterElement); |
} |
}); |
- |
+ localsHandler.enterScope(node, constructor); |
buildInitializers(constructor, constructors, fieldValues); |
localsHandler.closureData = oldClosureData; |
elements = oldElements; |
@@ -1369,6 +1376,11 @@ |
FunctionSignature functionSignature = body.computeSignature(compiler); |
int arity = functionSignature.parameterCount; |
functionSignature.orderedForEachParameter((parameter) { |
+ // TODO(ngeoffray): No need to pass the parameters that are |
+ // captured and stored in a box. Because this information is |
+ // not trivial to get in codegen.dart, we just pass the |
+ // parameters anyway. We need to update both codegen.dart and |
+ // builder.dart on how parameters are being passed. |
bodyCallInputs.add(localsHandler.readLocal(parameter)); |
}); |
@@ -1387,6 +1399,13 @@ |
} |
}); |
+ // If there are locals that escape (ie used in closures), we |
+ // pass the box to the constructor. |
+ ClosureScope scopeData = parameterClosureData.capturingScopes[node]; |
+ if (scopeData != null) { |
+ bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); |
+ } |
+ |
// TODO(ahe): The constructor name is statically resolved. See |
// SsaCodeGenerator.visitInvokeDynamicMethod. Is there a cleaner |
// way to do this? |