| 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;
|
| + }
|
| +
|
| +}
|
|
|