| Index: pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
|
| diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
|
| index 2b37c176b1c5e4c80d67e887ab929d4f10d7ca8c..7306262863c6460876e6dd666b5ecba077ea8ec7 100644
|
| --- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
|
| +++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
|
| @@ -84,9 +84,20 @@ class Label {
|
| }
|
|
|
| /**
|
| - * Variables are [Expression]s.
|
| + * A local variable in the tree IR.
|
| + *
|
| + * All tree IR variables are mutable, and may in Dart-mode be referenced inside
|
| + * nested functions.
|
| + *
|
| + * To use a variable as an expression, reference it from a [VariableUse], with
|
| + * one [VariableUse] per expression.
|
| + *
|
| + * [Variable]s are reference counted. The node constructors [VariableUse],
|
| + * [Assign], [FunctionDefinition], and [Try] automatically update the reference
|
| + * count for their variables, but when transforming the tree, the transformer
|
| + * is responsible for updating reference counts.
|
| */
|
| -class Variable extends Expression {
|
| +class Variable extends Node {
|
| /// Function that declares this variable.
|
| ExecutableElement host;
|
|
|
| @@ -94,20 +105,34 @@ class Variable extends Expression {
|
| /// Different variables may have the same entity. May be null.
|
| Entity element;
|
|
|
| + /// Number of places where this variable occurs in a [VariableUse].
|
| int readCount = 0;
|
|
|
| /// Number of places where this variable occurs as:
|
| /// - left-hand of an [Assign]
|
| /// - left-hand of a [FunctionDeclaration]
|
| /// - parameter in a [FunctionDefinition]
|
| + /// - catch parameter in a [Try]
|
| int writeCount = 0;
|
|
|
| Variable(this.host, this.element) {
|
| assert(host != null);
|
| }
|
| +}
|
| +
|
| +/// Read the value of a variable.
|
| +class VariableUse extends Expression {
|
| + Variable variable;
|
| +
|
| + /// Creates a use of [variable] and updates its `readCount`.
|
| + VariableUse(this.variable) {
|
| + variable.readCount++;
|
| + }
|
|
|
| - accept(ExpressionVisitor visitor) => visitor.visitVariable(this);
|
| - accept1(ExpressionVisitor1 visitor, arg) => visitor.visitVariable(this, arg);
|
| + accept(ExpressionVisitor visitor) => visitor.visitVariableUse(this);
|
| + accept1(ExpressionVisitor1 visitor, arg) {
|
| + return visitor.visitVariableUse(this, arg);
|
| + }
|
| }
|
|
|
| /**
|
| @@ -498,6 +523,7 @@ class Assign extends Statement {
|
| /// Variable declarations themselves are hoisted to function level.
|
| bool isDeclaration;
|
|
|
| + /// Creates an assignment to [variable] and updates its `writeCount`.
|
| Assign(this.variable, this.definition, this.next,
|
| { this.isDeclaration: false }) {
|
| variable.writeCount++;
|
| @@ -571,7 +597,11 @@ class Try extends Statement {
|
| Statement get next => null;
|
| void set next(Statement s) => throw 'UNREACHABLE';
|
|
|
| - Try(this.tryBody, this.catchParameters, this.catchBody);
|
| + Try(this.tryBody, this.catchParameters, this.catchBody) {
|
| + for (Variable variable in catchParameters) {
|
| + variable.writeCount++; // Being a catch parameter counts as a write.
|
| + }
|
| + }
|
|
|
| accept(StatementVisitor visitor) => visitor.visitTry(this);
|
| accept1(StatementVisitor1 visitor, arg) {
|
| @@ -621,8 +651,13 @@ class FunctionDefinition extends Node implements ExecutableDefinition {
|
| final List<ConstDeclaration> localConstants;
|
| final List<ConstantExpression> defaultParameterValues;
|
|
|
| + /// Creates a function definition and updates `writeCount` for [parameters].
|
| FunctionDefinition(this.element, this.parameters, this.body,
|
| - this.localConstants, this.defaultParameterValues);
|
| + this.localConstants, this.defaultParameterValues) {
|
| + for (Variable param in parameters) {
|
| + param.writeCount++; // Being a parameter counts as a write.
|
| + }
|
| + }
|
|
|
| /// Returns `true` if this function is abstract.
|
| ///
|
| @@ -719,7 +754,7 @@ class SetField extends Statement implements JsSpecificNode {
|
|
|
| abstract class ExpressionVisitor<E> {
|
| E visitExpression(Expression e) => e.accept(this);
|
| - E visitVariable(Variable node);
|
| + E visitVariableUse(VariableUse node);
|
| E visitInvokeStatic(InvokeStatic node);
|
| E visitInvokeMethod(InvokeMethod node);
|
| E visitInvokeMethodDirectly(InvokeMethodDirectly node);
|
| @@ -744,7 +779,7 @@ abstract class ExpressionVisitor<E> {
|
|
|
| abstract class ExpressionVisitor1<E, A> {
|
| E visitExpression(Expression e, A arg) => e.accept1(this, arg);
|
| - E visitVariable(Variable node, A arg);
|
| + E visitVariableUse(VariableUse node, A arg);
|
| E visitInvokeStatic(InvokeStatic node, A arg);
|
| E visitInvokeMethod(InvokeMethod node, A arg);
|
| E visitInvokeMethodDirectly(InvokeMethodDirectly node, A arg);
|
| @@ -813,11 +848,16 @@ abstract class Visitor1<S, E, A> implements ExpressionVisitor1<E, A>,
|
|
|
| class RecursiveVisitor extends Visitor {
|
| visitFunctionDefinition(FunctionDefinition node) {
|
| + node.parameters.forEach(visitVariable);
|
| visitStatement(node.body);
|
| }
|
|
|
| visitVariable(Variable node) {}
|
|
|
| + visitVariableUse(VariableUse node) {
|
| + visitVariable(node.variable);
|
| + }
|
| +
|
| visitInvokeStatic(InvokeStatic node) {
|
| node.arguments.forEach(visitExpression);
|
| }
|
|
|