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

Unified Diff: sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart

Issue 366853007: dart2dart: Support for inner functions in new IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: SVN rebase Created 6 years, 6 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: sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
index b9f33613bac553f2eddd0fa523d6a63932859d21..c1f19ebcb66a481725eda7c28010bc54041f9d31 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
@@ -206,6 +206,9 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
final List<ConstDeclaration> localConstants;
+ FunctionElement currentFunction;
+ final DetectClosureVariables closureLocals;
+
/// Construct a top-level visitor.
IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile)
: returnContinuation = new ir.Continuation.retrn(),
@@ -215,6 +218,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
assignedVars = <ir.Primitive>[],
index2variable = <Element>[],
localConstants = <ConstDeclaration>[],
+ closureLocals = new DetectClosureVariables(elements),
super(elements, compiler) {
constantBuilder = new ConstExpBuilder(this);
}
@@ -233,6 +237,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
index2variable = new List<Element>.from(parent.index2variable),
constantBuilder = parent.constantBuilder,
localConstants = parent.localConstants,
+ currentFunction = parent.currentFunction,
+ closureLocals = parent.closureLocals,
super(parent.elements, parent.compiler);
/**
@@ -246,26 +252,37 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.FunctionDefinition buildFunctionInternal(FunctionElement element) {
assert(invariant(element, element.isImplementation));
+ currentFunction = element;
ast.FunctionExpression function = element.node;
assert(function != null);
assert(!function.modifiers.isExternal);
assert(elements[function] != null);
+ closureLocals.visit(function);
+
root = current = null;
FunctionSignature signature = element.functionSignature;
- signature.orderedForEachParameter((parameterElement) {
+ signature.orderedForEachParameter((ParameterElement parameterElement) {
+ // TODO(asgerf): Handle parameters with default values. (Use a ConstExp)
+ if (parameterElement.initializer != null) {
+ giveup(parameterElement.node, 'Function parameter with default value');
+ }
ir.Parameter parameter = new ir.Parameter(parameterElement);
parameters.add(parameter);
- variableIndex[parameterElement] = assignedVars.length;
- assignedVars.add(parameter);
- index2variable.add(parameterElement);
+ if (isClosureVariable(parameterElement)) {
+ add(new ir.SetClosureVariable(parameterElement, parameter));
+ } else {
+ variableIndex[parameterElement] = assignedVars.length;
+ assignedVars.add(parameter);
+ index2variable.add(parameterElement);
+ }
});
visit(function.body);
ensureReturn(function);
- return new ir.FunctionDefinition(returnContinuation, parameters, root,
- localConstants);
+ return new ir.FunctionDefinition(element, returnContinuation, parameters,
+ root, localConstants);
}
ConstantSystem get constantSystem => compiler.backend.constantSystem;
@@ -515,6 +532,17 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Primitive visitFor(ast.For node) {
assert(isOpen);
+ // TODO(asgerf): Handle closure variables declared in a for-loop.
+ if (node.initializer is ast.VariableDefinitions) {
+ ast.VariableDefinitions definitions = node.initializer;
+ for (ast.Node definition in definitions.definitions.nodes) {
+ Element element = elements[definition];
+ if (isClosureVariable(element)) {
+ return giveup(definition, 'Closure variable in for loop initializer');
+ }
+ }
+ }
+
// For loops use three named continuations: the entry to the condition,
// the entry to the body, and the loop exit (break). The CPS translation
// of [[for (initializer; condition; update) body; successor]] is:
@@ -731,27 +759,29 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
} else {
for (ast.Node definition in node.definitions.nodes) {
Element element = elements[definition];
+ ir.Primitive initialValue;
// Definitions are either SendSets if there is an initializer, or
// Identifiers if there is no initializer.
if (definition is ast.SendSet) {
assert(!definition.arguments.isEmpty);
assert(definition.arguments.tail.isEmpty);
- ir.Primitive initialValue = visit(definition.arguments.head);
- // In case a primitive was introduced for the initializer expression,
- // use this variable element to help derive a good name for it.
- initialValue.useElementAsHint(element);
- variableIndex[element] = assignedVars.length;
- assignedVars.add(initialValue);
- index2variable.add(element);
+ initialValue = visit(definition.arguments.head);
} else {
assert(definition is ast.Identifier);
// The initial value is null.
// TODO(kmillikin): Consider pooling constants.
- ir.Constant constant = makePrimConst(constantSystem.createNull());
- constant.useElementAsHint(element);
- add(new ir.LetPrim(constant));
+ initialValue = makePrimConst(constantSystem.createNull());
+ add(new ir.LetPrim(initialValue));
+ }
+ if (isClosureVariable(element)) {
+ add(new ir.SetClosureVariable(element, initialValue,
+ isDeclaration: true));
+ } else {
+ // In case a primitive was introduced for the initializer expression,
+ // use this variable element to help derive a good name for it.
+ initialValue.useElementAsHint(element);
variableIndex[element] = assignedVars.length;
- assignedVars.add(constant);
+ assignedVars.add(initialValue);
index2variable.add(element);
}
}
@@ -959,6 +989,14 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
return visit(node.expression);
}
+ ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) {
+ ir.Parameter v = new ir.Parameter(null);
+ ir.Continuation k = new ir.Continuation([v]);
+ ir.Expression expression = build(k);
+ add(new ir.LetCont(k, expression));
+ return v;
+ }
+
ir.Primitive translateClosureCall(ir.Primitive receiver,
Selector closureSelector,
ast.NodeList arguments) {
@@ -968,12 +1006,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
closureSelector.argumentCount,
closureSelector.namedArguments);
List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.Expression invoke =
- new ir.InvokeMethod(receiver, namedCallSelector, k, args);
- add(new ir.LetCont(k, invoke));
- return v;
+ return continueWithExpression(
+ (k) => new ir.InvokeMethod(receiver, namedCallSelector, k, args));
}
ir.Primitive visitClosureSend(ast.Send node) {
@@ -982,6 +1016,9 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Primitive closureTarget;
if (element == null) {
closureTarget = visit(node.selector);
+ } else if (isClosureVariable(element)) {
+ closureTarget = new ir.GetClosureVariable(element);
+ add(new ir.LetPrim(closureTarget));
} else {
assert(Elements.isLocal(element));
closureTarget = lookupLocal(element);
@@ -1020,12 +1057,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
for (ast.Node n in node.arguments) {
arguments.add(visit(n));
}
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.Expression invoke =
- createDynamicInvoke(node, selector, receiver, k, arguments);
- add(new ir.LetCont(k, invoke));
- return v;
+ return continueWithExpression(
+ (k) => createDynamicInvoke(node, selector, receiver, k, arguments));
}
_GetterElements translateGetter(ast.Send node, Selector selector) {
@@ -1035,17 +1068,17 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
ir.Primitive index;
if (Elements.isErroneousElement(element)) {
- giveup(node, 'Erroneous element on GetterSend');
- return null;
+ return giveup(node, 'Erroneous element on GetterSend');
}
if (element != null && element.isConst) {
// Reference to constant local, top-level or static field
-
result = translateConstant(node);
+ } else if (isClosureVariable(element)) {
+ result = new ir.GetClosureVariable(element);
+ add(new ir.LetPrim(result));
} else if (Elements.isLocal(element)) {
// Reference to local variable
-
result = lookupLocal(element);
} else if (element == null ||
Elements.isInstanceField(element) ||
@@ -1064,31 +1097,20 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
arguments.add(index);
}
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
assert(selector.kind == SelectorKind.GETTER ||
selector.kind == SelectorKind.INDEX);
- ir.Expression invoke =
- createDynamicInvoke(node, selector, receiver, k, arguments);
- add(new ir.LetCont(k, invoke));
- result = v;
- } else if (element.isField || element.isGetter ||
- // Access to a static field or getter (non-static case handled above).
- // Even if there is only a setter, we compile as if it was a getter,
- // so the vm can fail at runtime.
-
- element.isSetter) {
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
+ result = continueWithExpression(
+ (k) => createDynamicInvoke(node, selector, receiver, k, arguments));
+ } else if (element.isField || element.isGetter || element.isSetter) {
+ // Access to a static field or getter (non-static case handled above).
+ // Even if there is only a setter, we compile as if it was a getter,
+ // so the vm can fail at runtime.
assert(selector.kind == SelectorKind.GETTER ||
selector.kind == SelectorKind.SETTER);
- ir.Expression invoke =
- new ir.InvokeStatic(element, selector, k, []);
- add(new ir.LetCont(k, invoke));
- result = v;
+ result = continueWithExpression(
+ (k) => new ir.InvokeStatic(element, selector, k, []));
} else if (Elements.isStaticOrTopLevelFunction(element)) {
// Convert a top-level or static function to a function object.
-
result = translateConstant(node);
} else {
throw "Unexpected SendSet getter: $node, $element";
@@ -1254,11 +1276,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
if (type.isMalformed) return giveup(node, "Malformed type for as");
ir.Primitive receiver = visit(node.receiver);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.AsCast asCast = new ir.AsCast(receiver, type, k);
- add(new ir.LetCont(k, asCast));
- return v;
+ return continueWithExpression(
+ (k) => new ir.AsCast(receiver, type, k));
}
return giveup(node);
}
@@ -1285,12 +1304,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
// TODO(lry): support default arguments, need support for locals.
List<ir.Definition> arguments = node.arguments.mapToList(visit,
growable:false);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.Expression invoke =
- new ir.InvokeStatic(element, selector, k, arguments);
- add(new ir.LetCont(k, invoke));
- return v;
+ return continueWithExpression(
+ (k) => new ir.InvokeStatic(element, selector, k, arguments));
}
ir.Primitive visitSuperSend(ast.Send node) {
@@ -1311,8 +1326,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
// If the user is trying to invoke the type literal or variable,
// it must be treated as a function call.
if (node.argumentsNode != null) {
- // TODO(sigurdm): Change this to match proposed semantics of issue #19725.
- return visitDynamicSend(node);
+ // TODO(sigurdm): Handle this to match proposed semantics of issue #19725.
+ return giveup(node, 'Type literal invoked as function');
}
DartType type = elements.getTypeLiteralType(node);
@@ -1325,6 +1340,13 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
}
}
+ /// True if [element] is a local variable, local function, or parameter that
+ /// is accessed from an inner function. Recursive self-references in a local
+ /// function count as closure accesses.
+ bool isClosureVariable(Element element) {
+ return closureLocals.isClosureVariable(element);
+ }
+
ir.Primitive visitSendSet(ast.SendSet node) {
assert(isOpen);
Element element = elements[node];
@@ -1386,33 +1408,29 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
}
// Set the value
- if (Elements.isLocal(element)) {
+ if (isClosureVariable(element)) {
+ add(new ir.SetClosureVariable(element, valueToStore));
+ } else if (Elements.isLocal(element)) {
valueToStore.useElementAsHint(element);
assignedVars[variableIndex[element]] = valueToStore;
} else if (Elements.isStaticOrTopLevel(element)) {
assert(element.isField || element.isSetter);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
Selector selector = elements.getSelector(node);
- ir.InvokeStatic invoke =
- new ir.InvokeStatic(element, selector, k, [valueToStore]);
- add(new ir.LetCont(k, invoke));
+ continueWithExpression(
+ (k) => new ir.InvokeStatic(element, selector, k, [valueToStore]));
} else {
if (element != null && Elements.isUnresolved(element)) {
return giveup(node, 'SendSet: non-local, non-static, unresolved');
}
// Setter or index-setter invocation
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
Selector selector = elements.getSelector(node);
assert(selector.kind == SelectorKind.SETTER ||
selector.kind == SelectorKind.INDEX);
List<ir.Definition> arguments = selector.isIndexSet
? [index, valueToStore]
: [valueToStore];
- ir.Expression invoke =
- createDynamicInvoke(node, selector, receiver, k, arguments);
- add(new ir.LetCont(k, invoke));
+ continueWithExpression(
+ (k) => createDynamicInvoke(node, selector, receiver, k, arguments));
}
if (node.isPostfix) {
@@ -1437,24 +1455,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
GenericType type = elements.getType(node);
List<ir.Primitive> args =
node.send.arguments.mapToList(visit, growable:false);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.InvokeConstructor invoke =
- new ir.InvokeConstructor(type, element,selector, k, args);
- add(new ir.LetCont(k, invoke));
- return v;
+ return continueWithExpression(
+ (k) => new ir.InvokeConstructor(type, element,selector, k, args));
}
ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
assert(isOpen);
ir.Primitive first = visit(node.first);
ir.Primitive second = visit(node.second);
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.ConcatenateStrings concat =
- new ir.ConcatenateStrings(k, [first, second]);
- add(new ir.LetCont(k, concat));
- return v;
+ return continueWithExpression(
+ (k) => new ir.ConcatenateStrings(k, [first, second]));
}
ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
@@ -1467,11 +1477,8 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
arguments.add(visit(part.expression));
arguments.add(visitLiteralString(part.string));
}
- ir.Parameter v = new ir.Parameter(null);
- ir.Continuation k = new ir.Continuation([v]);
- ir.ConcatenateStrings concat = new ir.ConcatenateStrings(k, arguments);
- add(new ir.LetCont(k, concat));
- return v;
+ return continueWithExpression(
+ (k) => new ir.ConcatenateStrings(k, arguments));
}
ir.Primitive translateConstant(ast.Node node, [Constant value]) {
@@ -1484,9 +1491,38 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
return primitive;
}
+ ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
+ return new IrBuilder(elements, compiler, sourceFile)
+ .buildFunctionInternal(elements[node]);
+ }
+
+ ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
+ FunctionElement element = elements[node];
+ ir.FunctionDefinition inner = makeSubFunction(node);
+ ir.CreateFunction prim = new ir.CreateFunction(inner);
+ add(new ir.LetPrim(prim));
+ return prim;
+ }
+
+ ir.Primitive visitFunctionDeclaration(ast.FunctionDeclaration node) {
+ FunctionElement element = elements[node.function];
+ ir.FunctionDefinition inner = makeSubFunction(node.function);
+ if (isClosureVariable(element)) {
+ add(new ir.DeclareFunction(element, inner));
+ } else {
+ ir.CreateFunction prim = new ir.CreateFunction(inner);
+ add(new ir.LetPrim(prim));
+ variableIndex[element] = assignedVars.length;
+ assignedVars.add(prim);
+ index2variable.add(element);
+ prim.useElementAsHint(element);
+ }
+ return null;
+ }
+
static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
- ir.Primitive giveup(ast.Node node, [String reason]) {
+ dynamic giveup(ast.Node node, [String reason]) {
throw ABORT_IRNODE_BUILDER;
}
@@ -1662,3 +1698,45 @@ class ConstExpBuilder extends ast.Visitor<ConstExp> {
}
}
+
+/// 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 {
+ final TreeElements elements;
+ DetectClosureVariables(this.elements);
+
+ FunctionElement currentFunction;
+ Set<Element> usedFromClosure = new Set<Element>();
+ Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
+
+ bool isClosureVariable(Element element) => usedFromClosure.contains(element);
+
+ void markAsClosureVariable(Element element) {
+ usedFromClosure.add(element);
+ }
+
+ visit(ast.Node node) => node.accept(this);
+
+ visitNode(ast.Node node) {
+ node.visitChildren(this);
+ }
+
+ visitSend(ast.Send node) {
+ Element element = elements[node];
+ if (Elements.isLocal(element) &&
+ !element.isConst &&
+ element.enclosingElement != currentFunction) {
+ markAsClosureVariable(element);
+ }
+ node.visitChildren(this);
+ }
+
+ visitFunctionExpression(ast.FunctionExpression node) {
+ FunctionElement oldFunction = currentFunction;
+ currentFunction = elements[node];
+ visit(node.body);
+ currentFunction = oldFunction;
+ }
+
+}

Powered by Google App Engine
This is Rietveld 408576698