| Index: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| index b17cbd272de773800038ceece4948489c460400a..74142fa3da9bd549cfd2abdf526c72bcd0c43cec 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
|
| @@ -26,6 +26,9 @@ import '../ir/const_expression.dart';
|
| //
|
| // In contrast to the CPS-based IR, non-primitive expressions can be named and
|
| // arguments (to calls, primitives, and blocks) can be arbitrary expressions.
|
| +//
|
| +// Additionally, variables are considered in scope within inner functions;
|
| +// closure variables are thus handled directly instead of using ref cells.
|
|
|
| /**
|
| * The base class of all Tree nodes.
|
| @@ -82,13 +85,24 @@ class Label {
|
| * Variables are [Expression]s.
|
| */
|
| class Variable extends Expression {
|
| + /// Function that declares this variable.
|
| + FunctionDefinition host;
|
| +
|
| /// Element used for synthesizing a name for the variable.
|
| /// Different variables may have the same element. May be null.
|
| Element element;
|
|
|
| int readCount = 0;
|
|
|
| - Variable(this.element);
|
| + /// Number of places where this variable occurs as:
|
| + /// - left-hand of an [Assign]
|
| + /// - left-hand of a [FunctionDeclaration]
|
| + /// - parameter in a [FunctionDefinition]
|
| + int writeCount = 0;
|
| +
|
| + Variable(this.host, this.element) {
|
| + assert(host != null);
|
| + }
|
|
|
| accept(ExpressionVisitor visitor) => visitor.visitVariable(this);
|
| }
|
| @@ -140,7 +154,7 @@ class InvokeSuperMethod extends Expression implements Invoke {
|
|
|
| InvokeSuperMethod(this.selector, this.arguments) ;
|
|
|
| - accept(Visitor visitor) => visitor.visitInvokeSuperMethod(this);
|
| + accept(ExpressionVisitor visitor) => visitor.visitInvokeSuperMethod(this);
|
| }
|
|
|
| /**
|
| @@ -192,9 +206,9 @@ class This extends Expression {
|
| }
|
|
|
| class ReifyTypeVar extends Expression {
|
| - TypeVariableElement element;
|
| + TypeVariableElement typeVariable;
|
|
|
| - ReifyTypeVar(this.element);
|
| + ReifyTypeVar(this.typeVariable);
|
|
|
| accept(ExpressionVisitor visitor) => visitor.visitReifyTypeVar(this);
|
| }
|
| @@ -264,6 +278,33 @@ class Not extends Expression {
|
| accept(ExpressionVisitor visitor) => visitor.visitNot(this);
|
| }
|
|
|
| +class FunctionExpression extends Expression {
|
| + final FunctionDefinition definition;
|
| +
|
| + FunctionExpression(this.definition) {
|
| + assert(definition.element.functionSignature.type.returnType.treatAsDynamic);
|
| + }
|
| +
|
| + accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this);
|
| +}
|
| +
|
| +/// Declares a local function.
|
| +/// Used for functions that may not occur in expression context due to
|
| +/// being recursive or having a return type.
|
| +/// The [variable] must not occur as the left-hand side of an [Assign] or
|
| +/// any other [FunctionDeclaration].
|
| +class FunctionDeclaration extends Statement {
|
| + Variable variable;
|
| + final FunctionDefinition definition;
|
| + Statement next;
|
| +
|
| + FunctionDeclaration(this.variable, this.definition, this.next) {
|
| + ++variable.writeCount;
|
| + }
|
| +
|
| + accept(StatementVisitor visitor) => visitor.visitFunctionDeclaration(this);
|
| +}
|
| +
|
| /// A [LabeledStatement] or [WhileTrue] or [WhileCondition].
|
| abstract class JumpTarget extends Statement {
|
| Label get label;
|
| @@ -289,9 +330,6 @@ class LabeledStatement extends JumpTarget {
|
|
|
| /// A [WhileTrue] or [WhileCondition] loop.
|
| abstract class Loop extends JumpTarget {
|
| - /// When a [Continue] to a loop is executed, all update expressions are
|
| - /// evaluated right-to-left before control resumes at the head of the loop.
|
| - List<Expression> get updates;
|
| }
|
|
|
| /**
|
| @@ -300,7 +338,6 @@ abstract class Loop extends JumpTarget {
|
| class WhileTrue extends Loop {
|
| final Label label;
|
| Statement body;
|
| - final List<Expression> updates = <Expression>[];
|
|
|
| WhileTrue(this.label, this.body) {
|
| assert(label.binding == null);
|
| @@ -328,10 +365,9 @@ class WhileCondition extends Loop {
|
| Expression condition;
|
| Statement body;
|
| Statement next;
|
| - final List<Expression> updates;
|
|
|
| WhileCondition(this.label, this.condition, this.body,
|
| - this.next, this.updates) {
|
| + this.next) {
|
| assert(label.binding == null);
|
| label.binding = this;
|
| }
|
| @@ -389,7 +425,15 @@ class Assign extends Statement {
|
| final Variable variable;
|
| Expression definition;
|
|
|
| - Assign(this.variable, this.definition, this.next);
|
| + /// If true, this declares a new copy of the closure variable.
|
| + /// The consequences are similar to [ir.SetClosureVariable].
|
| + /// All uses of the variable must be nested inside the [next] statement.
|
| + bool isDeclaration;
|
| +
|
| + Assign(this.variable, this.definition, this.next,
|
| + { this.isDeclaration: false }) {
|
| + variable.writeCount++;
|
| + }
|
|
|
| bool get hasExactlyOneUse => variable.readCount == 1;
|
|
|
| @@ -440,11 +484,13 @@ class ExpressionStatement extends Statement {
|
| }
|
|
|
| class FunctionDefinition extends Node {
|
| + final FunctionElement element;
|
| final List<Variable> parameters;
|
| Statement body;
|
| final List<ConstDeclaration> localConstants;
|
|
|
| - FunctionDefinition(this.parameters, this.body, this.localConstants);
|
| + FunctionDefinition(this.element, this.parameters, this.body,
|
| + this.localConstants);
|
| }
|
|
|
| abstract class ExpressionVisitor<E> {
|
| @@ -464,6 +510,7 @@ abstract class ExpressionVisitor<E> {
|
| E visitLiteralList(LiteralList node);
|
| E visitLiteralMap(LiteralMap node);
|
| E visitTypeOperator(TypeOperator node);
|
| + E visitFunctionExpression(FunctionExpression node);
|
| }
|
|
|
| abstract class StatementVisitor<S> {
|
| @@ -476,6 +523,7 @@ abstract class StatementVisitor<S> {
|
| S visitIf(If node);
|
| S visitWhileTrue(WhileTrue node);
|
| S visitWhileCondition(WhileCondition node);
|
| + S visitFunctionDeclaration(FunctionDeclaration node);
|
| S visitExpressionStatement(ExpressionStatement node);
|
| }
|
|
|
| @@ -485,6 +533,120 @@ abstract class Visitor<S,E> implements ExpressionVisitor<E>,
|
| S visitStatement(Statement s) => s.accept(this);
|
| }
|
|
|
| +class RecursiveVisitor extends Visitor {
|
| + visitFunctionDefinition(FunctionDefinition node) {
|
| + visitStatement(node.body);
|
| + }
|
| +
|
| + visitVariable(Variable node) {}
|
| +
|
| + visitInvokeStatic(InvokeStatic node) {
|
| + node.arguments.forEach(visitExpression);
|
| + }
|
| +
|
| + visitInvokeMethod(InvokeMethod node) {
|
| + visitExpression(node.receiver);
|
| + node.arguments.forEach(visitExpression);
|
| + }
|
| +
|
| + visitInvokeSuperMethod(InvokeSuperMethod node) {
|
| + node.arguments.forEach(visitExpression);
|
| + }
|
| +
|
| + visitInvokeConstructor(InvokeConstructor node) {
|
| + node.arguments.forEach(visitExpression);
|
| + }
|
| +
|
| + visitConcatenateStrings(ConcatenateStrings node) {
|
| + node.arguments.forEach(visitExpression);
|
| + }
|
| +
|
| + visitConstant(Constant node) {}
|
| +
|
| + visitThis(This node) {}
|
| +
|
| + visitReifyTypeVar(ReifyTypeVar node) {}
|
| +
|
| + visitConditional(Conditional node) {
|
| + visitExpression(node.condition);
|
| + visitExpression(node.thenExpression);
|
| + visitExpression(node.elseExpression);
|
| + }
|
| +
|
| + visitLogicalOperator(LogicalOperator node) {
|
| + visitExpression(node.left);
|
| + visitExpression(node.right);
|
| + }
|
| +
|
| + visitNot(Not node) {
|
| + visitExpression(node.operand);
|
| + }
|
| +
|
| + visitLiteralList(LiteralList node) {
|
| + node.values.forEach(visitExpression);
|
| + }
|
| +
|
| + visitLiteralMap(LiteralMap node) {
|
| + for (int i=0; i<node.keys.length; i++) {
|
| + visitExpression(node.keys[i]);
|
| + visitExpression(node.values[i]);
|
| + }
|
| + }
|
| +
|
| + visitTypeOperator(TypeOperator node) {
|
| + visitExpression(node.receiver);
|
| + }
|
| +
|
| + visitFunctionExpression(FunctionExpression node) {
|
| + visitFunctionDefinition(node.definition);
|
| + }
|
| +
|
| + visitLabeledStatement(LabeledStatement node) {
|
| + visitStatement(node.body);
|
| + visitStatement(node.next);
|
| + }
|
| +
|
| + visitAssign(Assign node) {
|
| + visitExpression(node.definition);
|
| + visitVariable(node.variable);
|
| + visitStatement(node.next);
|
| + }
|
| +
|
| + visitReturn(Return node) {
|
| + visitExpression(node.value);
|
| + }
|
| +
|
| + visitBreak(Break node) {}
|
| +
|
| + visitContinue(Continue node) {}
|
| +
|
| + visitIf(If node) {
|
| + visitExpression(node.condition);
|
| + visitStatement(node.thenStatement);
|
| + visitStatement(node.elseStatement);
|
| + }
|
| +
|
| + visitWhileTrue(WhileTrue node) {
|
| + visitStatement(node.body);
|
| + }
|
| +
|
| + visitWhileCondition(WhileCondition node) {
|
| + visitExpression(node.condition);
|
| + visitStatement(node.body);
|
| + visitStatement(node.next);
|
| + }
|
| +
|
| + visitFunctionDeclaration(FunctionDeclaration node) {
|
| + visitFunctionDefinition(node.definition);
|
| + visitStatement(node.next);
|
| + }
|
| +
|
| + visitExpressionStatement(ExpressionStatement node) {
|
| + visitExpression(node.expression);
|
| + visitStatement(node.next);
|
| + }
|
| +}
|
| +
|
| /**
|
| * Builder translates from CPS-based IR to direct-style Tree.
|
| *
|
| @@ -524,6 +686,10 @@ class Builder extends ir.Visitor<Node> {
|
| final Map<Element, List<Variable>> element2variables =
|
| <Element,List<Variable>>{};
|
|
|
| + /// Like [element2variables], except for closure variables. Closure variables
|
| + /// are not subject to SSA, so at most one variable is used per element.
|
| + final Map<Element, Variable> element2closure = <Element, Variable>{};
|
| +
|
| // Continuations with more than one use are replaced with Tree labels. This
|
| // is the mapping from continuations to labels.
|
| final Map<ir.Continuation, Label> labels = <ir.Continuation, Label>{};
|
| @@ -531,11 +697,29 @@ class Builder extends ir.Visitor<Node> {
|
| FunctionDefinition function;
|
| ir.Continuation returnContinuation;
|
|
|
| + Builder parent;
|
| +
|
| + Builder(this.compiler);
|
| +
|
| + Builder.inner(Builder parent)
|
| + : this.parent = parent,
|
| + compiler = parent.compiler;
|
| +
|
| /// Variable used in [buildPhiAssignments] as a temporary when swapping
|
| /// variables.
|
| - final Variable tempVar = new Variable(null);
|
| + Variable phiTempVar;
|
|
|
| - Builder(this.compiler);
|
| + Variable getClosureVariable(Element element) {
|
| + if (element.enclosingElement != function.element) {
|
| + return parent.getClosureVariable(element);
|
| + }
|
| + Variable variable = element2closure[element];
|
| + if (variable == null) {
|
| + variable = new Variable(function, element);
|
| + element2closure[element] = variable;
|
| + }
|
| + return variable;
|
| + }
|
|
|
| /// Obtains the variable representing the given primitive. Returns null for
|
| /// primitives that have no reference and do not need a variable.
|
| @@ -543,13 +727,13 @@ class Builder extends ir.Visitor<Node> {
|
| if (primitive.registerIndex == null) {
|
| return null; // variable is unused
|
| }
|
| - List<Variable> variables = element2variables[primitive.element];
|
| + List<Variable> variables = element2variables[primitive.hint];
|
| if (variables == null) {
|
| variables = <Variable>[];
|
| - element2variables[primitive.element] = variables;
|
| + element2variables[primitive.hint] = variables;
|
| }
|
| while (variables.length <= primitive.registerIndex) {
|
| - variables.add(new Variable(primitive.element));
|
| + variables.add(new Variable(function, primitive.hint));
|
| }
|
| return variables[primitive.registerIndex];
|
| }
|
| @@ -652,9 +836,9 @@ class Builder extends ir.Visitor<Node> {
|
| // Cycle found; store argument in a temporary variable.
|
| // The temporary will then be used as right-hand side when the
|
| // assignment gets added.
|
| - if (assignmentSrc[i] != tempVar) { // Only move to temporary once.
|
| - assignmentSrc[i] = tempVar;
|
| - addAssignment(tempVar, arg);
|
| + if (assignmentSrc[i] != phiTempVar) { // Only move to temporary once.
|
| + assignmentSrc[i] = phiTempVar;
|
| + addAssignment(phiTempVar, arg);
|
| }
|
| return;
|
| }
|
| @@ -683,24 +867,40 @@ class Builder extends ir.Visitor<Node> {
|
| return first;
|
| }
|
|
|
| + visitNode(ir.Node node) => throw "Unhandled node: $node";
|
| +
|
| Expression visitFunctionDefinition(ir.FunctionDefinition node) {
|
| - returnContinuation = node.returnContinuation;
|
| List<Variable> parameters = <Variable>[];
|
| + function = new FunctionDefinition(node.element, parameters,
|
| + null, node.localConstants);
|
| + returnContinuation = node.returnContinuation;
|
| for (ir.Parameter p in node.parameters) {
|
| Variable parameter = getVariable(p);
|
| assert(parameter != null);
|
| + ++parameter.writeCount; // Being a parameter counts as a write.
|
| parameters.add(parameter);
|
| }
|
| - function = new FunctionDefinition(parameters, visit(node.body),
|
| - node.localConstants);
|
| + phiTempVar = new Variable(function, null);
|
| + function.body = visit(node.body);
|
| return null;
|
| }
|
|
|
| Statement visitLetPrim(ir.LetPrim node) {
|
| Variable variable = getVariable(node.primitive);
|
| - return variable == null
|
| - ? visit(node.body)
|
| - : new Assign(variable, visit(node.primitive), visit(node.body));
|
| +
|
| + // Don't translate unused primitives.
|
| + if (variable == null) return visit(node.body);
|
| +
|
| + Node definition = visit(node.primitive);
|
| +
|
| + // visitPrimitive returns a Statement without successor if it cannot occur
|
| + // in expression context (currently only the case for FunctionDeclarations).
|
| + if (definition is Statement) {
|
| + definition.next = visit(node.body);
|
| + return definition;
|
| + } else {
|
| + return new Assign(variable, definition, visit(node.body));
|
| + }
|
| }
|
|
|
| Statement visitLetCont(ir.LetCont node) {
|
| @@ -726,87 +926,69 @@ class Builder extends ir.Visitor<Node> {
|
| // Calls are translated to direct style.
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| Expression invoke = new InvokeStatic(node.target, node.selector, arguments);
|
| - ir.Continuation cont = node.continuation.definition;
|
| - if (cont == returnContinuation) {
|
| - return new Return(invoke);
|
| - } else {
|
| - assert(cont.hasExactlyOneUse);
|
| - assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, invoke,
|
| - () => visit(cont.body));
|
| - }
|
| + return continueWithExpression(node.continuation, invoke);
|
| }
|
|
|
| Statement visitInvokeMethod(ir.InvokeMethod node) {
|
| Expression receiver = getVariableReference(node.receiver);
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
|
| - ir.Continuation cont = node.continuation.definition;
|
| - if (cont == returnContinuation) {
|
| - return new Return(invoke);
|
| - } else {
|
| - assert(cont.hasExactlyOneUse);
|
| - assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, invoke,
|
| - () => visit(cont.body));
|
| - }
|
| + return continueWithExpression(node.continuation, invoke);
|
| }
|
|
|
| Statement visitInvokeSuperMethod(ir.InvokeSuperMethod node) {
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| Expression invoke = new InvokeSuperMethod(node.selector, arguments);
|
| - ir.Continuation cont = node.continuation.definition;
|
| - if (cont == returnContinuation) {
|
| - return new Return(invoke);
|
| - } else {
|
| - assert(cont.hasExactlyOneUse);
|
| - assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, invoke,
|
| - () => visit(cont.body));
|
| - }
|
| + return continueWithExpression(node.continuation, invoke);
|
| }
|
|
|
| Statement visitConcatenateStrings(ir.ConcatenateStrings node) {
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| Expression concat = new ConcatenateStrings(arguments);
|
| - ir.Continuation cont = node.continuation.definition;
|
| + return continueWithExpression(node.continuation, concat);
|
| + }
|
| +
|
| + Statement continueWithExpression(ir.Reference continuation,
|
| + Expression expression) {
|
| + ir.Continuation cont = continuation.definition;
|
| if (cont == returnContinuation) {
|
| - return new Return(concat);
|
| + return new Return(expression);
|
| } else {
|
| assert(cont.hasExactlyOneUse);
|
| assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, concat,
|
| + return buildContinuationAssignment(cont.parameters.single, expression,
|
| () => visit(cont.body));
|
| }
|
| }
|
|
|
| + Expression visitGetClosureVariable(ir.GetClosureVariable node) {
|
| + return getClosureVariable(node.variable);
|
| + }
|
| +
|
| + Statement visitSetClosureVariable(ir.SetClosureVariable node) {
|
| + Variable variable = getClosureVariable(node.variable);
|
| + Expression value = getVariableReference(node.value);
|
| + return new Assign(variable, value, visit(node.body),
|
| + isDeclaration: node.isDeclaration);
|
| + }
|
| +
|
| + Statement visitDeclareFunction(ir.DeclareFunction node) {
|
| + Variable variable = getClosureVariable(node.variable);
|
| + FunctionDefinition function = makeSubFunction(node.definition);
|
| + return new FunctionDeclaration(variable, function, visit(node.body));
|
| + }
|
| +
|
| Statement visitAsCast(ir.AsCast node) {
|
| Expression receiver = getVariableReference(node.receiver);
|
| Expression concat = new TypeOperator(receiver, node.type, "as");
|
| - ir.Continuation cont = node.continuation.definition;
|
| - if (cont == returnContinuation) {
|
| - return new Return(concat);
|
| - } else {
|
| - assert(cont.hasExactlyOneUse);
|
| - assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, concat,
|
| - () => visit(cont.body));
|
| - }
|
| + return continueWithExpression(node.continuation, concat);
|
| }
|
|
|
| Statement visitInvokeConstructor(ir.InvokeConstructor node) {
|
| List<Expression> arguments = translateArguments(node.arguments);
|
| Expression invoke =
|
| new InvokeConstructor(node.type, node.target, node.selector, arguments);
|
| - ir.Continuation cont = node.continuation.definition;
|
| - if (cont == returnContinuation) {
|
| - return new Return(invoke);
|
| - } else {
|
| - assert(cont.hasExactlyOneUse);
|
| - assert(cont.parameters.length == 1);
|
| - return buildContinuationAssignment(cont.parameters.single, invoke,
|
| - () => visit(cont.body));
|
| - }
|
| + return continueWithExpression(node.continuation, invoke);
|
| }
|
|
|
| Statement visitInvokeContinuation(ir.InvokeContinuation node) {
|
| @@ -870,7 +1052,7 @@ class Builder extends ir.Visitor<Node> {
|
| }
|
|
|
| Expression visitReifyTypeVar(ir.ReifyTypeVar node) {
|
| - return new ReifyTypeVar(node.element);
|
| + return new ReifyTypeVar(node.typeVariable);
|
| }
|
|
|
| Expression visitLiteralList(ir.LiteralList node) {
|
| @@ -886,6 +1068,23 @@ class Builder extends ir.Visitor<Node> {
|
| translateArguments(node.values));
|
| }
|
|
|
| + FunctionDefinition makeSubFunction(ir.FunctionDefinition function) {
|
| + return new Builder.inner(this).build(function);
|
| + }
|
| +
|
| + Node visitCreateFunction(ir.CreateFunction node) {
|
| + FunctionDefinition def = makeSubFunction(node.definition);
|
| + FunctionSignature signature = node.definition.element.functionSignature;
|
| + bool hasReturnType = !signature.type.returnType.treatAsDynamic;
|
| + if (hasReturnType) {
|
| + // This function cannot occur in expression context.
|
| + // The successor will be filled in by visitLetPrim.
|
| + return new FunctionDeclaration(getVariable(node), def, null);
|
| + } else {
|
| + return new FunctionExpression(def);
|
| + }
|
| + }
|
| +
|
| Expression visitIsCheck(ir.IsCheck node) {
|
| return new TypeOperator(getVariableReference(node.receiver),
|
| node.type,
|
| @@ -911,6 +1110,85 @@ class Builder extends ir.Visitor<Node> {
|
| }
|
| }
|
|
|
| +/// Eliminates redundant variables and assignments that occur immediately after
|
| +/// parameters are declared or after a function declaration.
|
| +///
|
| +/// These patterns arise when translating out of CPS where closure variables
|
| +/// live in a separate space. Since function parameters are IR primitives they
|
| +/// must be moved into a separate closure variable for inner functions to access
|
| +/// them. For example:
|
| +///
|
| +/// foo(x) {
|
| +/// let v1 = ref x in BODY
|
| +/// }
|
| +/// ==> (dart_tree Builder)
|
| +/// foo(x) {
|
| +/// var v1 = x;
|
| +/// BODY..
|
| +/// }
|
| +///
|
| +/// This phase attempts to merge v1 and x in the example above.
|
| +/// A similar pattern can occur for local function declarations that are used
|
| +/// from closures.
|
| +class CopyPropagateClosureVariables extends RecursiveVisitor {
|
| +
|
| + void rewrite(FunctionDefinition definition) {
|
| + visitFunctionDefinition(definition);
|
| + }
|
| +
|
| + /// Performs the rewrite:
|
| + ///
|
| + /// foo(x) { var v0 = x; S }
|
| + /// ==> (move v0 into parameter)
|
| + /// foo(v0) { S }
|
| + /// ==> (change the name of v0 to be x, so we preserve the parameter name)
|
| + /// foo(x) { S[v0\x] }
|
| + ///
|
| + /// Condition: x cannot be used anywhere else.
|
| + visitFunctionDefinition(FunctionDefinition definition) {
|
| + while (definition.body is Assign) {
|
| + Assign assign = definition.body;
|
| + if (assign.definition is! Variable) break;
|
| +
|
| + Variable rightHand = assign.definition;
|
| + if (rightHand.readCount != 1) break;
|
| +
|
| + int paramIndex = definition.parameters.indexOf(rightHand);
|
| + if (paramIndex == -1) break;
|
| +
|
| + // A variable may not occur as a parameter more than once.
|
| + if (definition.parameters.contains(assign.variable)) break;
|
| +
|
| + definition.parameters[paramIndex] = assign.variable;
|
| + assign.variable.element = rightHand.element;
|
| + definition.body = assign.next;
|
| + }
|
| +
|
| + visitStatement(definition.body); // Visit nested function definitions.
|
| + }
|
| +
|
| + /// Performs the rewrite:
|
| + ///
|
| + /// int v0() { S }
|
| + /// foo = v0;
|
| + /// ==>
|
| + /// int foo() { S }
|
| + ///
|
| + /// Condition: v0 cannot be used anywhere else.
|
| + visitFunctionDeclaration(FunctionDeclaration node) {
|
| + Statement next = node.next;
|
| + if (next is Assign &&
|
| + next.definition == node.variable &&
|
| + node.variable.readCount == 1 &&
|
| + next.variable.writeCount == 1) {
|
| + node.variable = next.variable;
|
| + node.next = next.next;
|
| + }
|
| + super.visitFunctionDeclaration(node);
|
| + }
|
| +
|
| +}
|
| +
|
| /**
|
| * Performs the following transformations on the tree:
|
| * - Assignment propagation
|
| @@ -1123,6 +1401,17 @@ class StatementRewriter extends Visitor<Statement, Expression> {
|
| return node;
|
| }
|
|
|
| + Expression visitFunctionExpression(FunctionExpression node) {
|
| + new StatementRewriter().rewrite(node.definition);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitFunctionDeclaration(FunctionDeclaration node) {
|
| + new StatementRewriter().rewrite(node.definition);
|
| + node.next = visitStatement(node.next);
|
| + return node;
|
| + }
|
| +
|
| Statement visitReturn(Return node) {
|
| node.value = visitExpression(node.value);
|
| return node;
|
| @@ -1303,6 +1592,7 @@ class StatementRewriter extends Visitor<Statement, Expression> {
|
| if (s is Assign && t is Assign && s.variable == t.variable) {
|
| Statement next = combineStatements(s.next, t.next);
|
| if (next != null) {
|
| + --t.variable.writeCount; // Two assignments become one.
|
| return new Assign(s.variable,
|
| combine(s.definition, t.definition),
|
| next);
|
| @@ -1466,7 +1756,7 @@ class StatementRewriter extends Visitor<Statement, Expression> {
|
| ///
|
| /// Note that the above pattern needs no iteration since nested ifs
|
| /// have been collapsed previously in the [StatementRewriter] phase.
|
| -class LoopRewriter extends StatementVisitor<Statement> {
|
| +class LoopRewriter extends RecursiveVisitor {
|
|
|
| Set<Label> usedContinueLabels = new Set<Label>();
|
|
|
| @@ -1481,11 +1771,13 @@ class LoopRewriter extends StatementVisitor<Statement> {
|
| }
|
|
|
| Statement visitAssign(Assign node) {
|
| + visitExpression(node.definition);
|
| node.next = visitStatement(node.next);
|
| return node;
|
| }
|
|
|
| Statement visitReturn(Return node) {
|
| + visitExpression(node.value);
|
| return node;
|
| }
|
|
|
| @@ -1499,6 +1791,7 @@ class LoopRewriter extends StatementVisitor<Statement> {
|
| }
|
|
|
| Statement visitIf(If node) {
|
| + visitExpression(node.condition);
|
| node.thenStatement = visitStatement(node.thenStatement);
|
| node.elseStatement = visitStatement(node.elseStatement);
|
| return node;
|
| @@ -1518,16 +1811,14 @@ class LoopRewriter extends StatementVisitor<Statement> {
|
| node.label,
|
| body.condition,
|
| body.thenStatement,
|
| - body.elseStatement,
|
| - node.updates);
|
| + body.elseStatement);
|
| } else if (!thenHasContinue && elseHasContinue) {
|
| node.label.binding = null;
|
| return new WhileCondition(
|
| node.label,
|
| new Not(body.condition),
|
| body.elseStatement,
|
| - body.thenStatement,
|
| - node.updates);
|
| + body.thenStatement);
|
| }
|
| } else {
|
| node.body = visitStatement(node.body);
|
| @@ -1538,28 +1829,28 @@ class LoopRewriter extends StatementVisitor<Statement> {
|
|
|
| Statement visitWhileCondition(WhileCondition node) {
|
| // Note: not reachable but the implementation is trivial
|
| + visitExpression(node.condition);
|
| node.body = visitStatement(node.body);
|
| node.next = visitStatement(node.next);
|
| return node;
|
| }
|
|
|
| Statement visitExpressionStatement(ExpressionStatement node) {
|
| + visitExpression(node.expression);
|
| node.next = visitStatement(node.next);
|
| - // for (;;) { ... E; continue* L ... }
|
| - // ==>
|
| - // for(;;E) { ... continue* L ... }
|
| - if (node.next is Continue) {
|
| - Continue jump = node.next;
|
| - if (jump.target.useCount == 1) {
|
| - Loop target = jump.target.binding;
|
| - target.updates.add(node.expression);
|
| - return jump; // Return the continue statement.
|
| - // NOTE: The pattern may reclick in an enclosing expression statement.
|
| - }
|
| - }
|
| return node;
|
| }
|
|
|
| + Statement visitFunctionDeclaration(FunctionDeclaration node) {
|
| + new LoopRewriter().rewrite(node.definition);
|
| + node.next = visitStatement(node.next);
|
| + return node;
|
| + }
|
| +
|
| + void visitFunctionExpression(FunctionExpression node) {
|
| + new LoopRewriter().rewrite(node.definition);
|
| + }
|
| +
|
| }
|
|
|
|
|
| @@ -1774,6 +2065,17 @@ class LogicalRewriter extends Visitor<Statement, Expression> {
|
| return node;
|
| }
|
|
|
| + Expression visitFunctionExpression(FunctionExpression node) {
|
| + new LogicalRewriter().rewrite(node.definition);
|
| + return node;
|
| + }
|
| +
|
| + Statement visitFunctionDeclaration(FunctionDeclaration node) {
|
| + new LogicalRewriter().rewrite(node.definition);
|
| + node.next = visitStatement(node.next);
|
| + return node;
|
| + }
|
| +
|
| Expression visitNot(Not node) {
|
| return toBoolean(makeCondition(node.operand, false, liftNots: false));
|
| }
|
| @@ -1992,3 +2294,4 @@ class LogicalRewriter extends Visitor<Statement, Expression> {
|
| }
|
| }
|
| }
|
| +
|
|
|