Index: pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
deleted file mode 100644 |
index 4ea9bebb5900e8c8b9236a5ab003c9ac7846253d..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
+++ /dev/null |
@@ -1,954 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-// IrNodes are kept in a separate library to have precise control over their |
-// dependencies on other parts of the system. |
-library dart2js.ir_nodes; |
- |
-import '../constants/expressions.dart'; |
-import '../constants/values.dart' as values show ConstantValue; |
-import '../dart2jslib.dart' as dart2js show invariant; |
-import '../elements/elements.dart'; |
-import '../universe/universe.dart' show Selector, SelectorKind; |
-import '../dart_types.dart' show DartType, GenericType; |
- |
-abstract class Node { |
- static int hashCount = 0; |
- final int hashCode = hashCount = (hashCount + 1) & 0x3fffffff; |
- |
- /// A pointer to the parent node. Is null until set by optimization passes. |
- Node parent; |
- |
- accept(Visitor visitor); |
-} |
- |
-abstract class Expression extends Node { |
- Expression plug(Expression expr) => throw 'impossible'; |
-} |
- |
-/// The base class of things that variables can refer to: primitives, |
-/// continuations, function and continuation parameters, etc. |
-abstract class Definition extends Node { |
- // The head of a linked-list of occurrences, in no particular order. |
- Reference firstRef = null; |
- |
- bool get hasAtMostOneUse => firstRef == null || firstRef.next == null; |
- bool get hasExactlyOneUse => firstRef != null && firstRef.next == null; |
- bool get hasAtLeastOneUse => firstRef != null; |
- bool get hasMultipleUses => !hasAtMostOneUse; |
- |
- void substituteFor(Definition other) { |
- if (other.firstRef == null) return; |
- Reference previous, current = other.firstRef; |
- do { |
- current.definition = this; |
- previous = current; |
- current = current.next; |
- } while (current != null); |
- previous.next = firstRef; |
- if (firstRef != null) firstRef.previous = previous; |
- firstRef = other.firstRef; |
- } |
-} |
- |
-/// An expression that cannot throw or diverge and has no side-effects. |
-/// All primitives are named using the identity of the [Primitive] object. |
-/// |
-/// Primitives may allocate objects, this is not considered side-effect here. |
-/// |
-/// Although primitives may not mutate state, they may depend on state. |
-abstract class Primitive extends Definition { |
- /// The [VariableElement] or [ParameterElement] from which the primitive |
- /// binding originated. |
- Element hint; |
- |
- /// Register in which the variable binding this primitive can be allocated. |
- /// Separate register spaces are used for primitives with different [element]. |
- /// Assigned by [RegisterAllocator], is null before that phase. |
- int registerIndex; |
- |
- /// Use the given element as a hint for naming this primitive. |
- /// |
- /// Has no effect if this primitive already has a non-null [element]. |
- void useElementAsHint(Element hint) { |
- if (this.hint == null) { |
- this.hint = hint; |
- } |
- } |
-} |
- |
-/// Operands to invocations and primitives are always variables. They point to |
-/// their definition and are doubly-linked into a list of occurrences. |
-class Reference { |
- Definition definition; |
- Reference previous = null; |
- Reference next = null; |
- |
- /// A pointer to the parent node. Is null until set by optimization passes. |
- Node parent; |
- |
- Reference(this.definition) { |
- next = definition.firstRef; |
- if (next != null) next.previous = this; |
- definition.firstRef = this; |
- } |
- |
- /// Unlinks this reference from the list of occurrences. |
- void unlink() { |
- if (previous == null) { |
- assert(definition.firstRef == this); |
- definition.firstRef = next; |
- } else { |
- previous.next = next; |
- } |
- if (next != null) next.previous = previous; |
- } |
-} |
- |
-/// Binding a value (primitive or constant): 'let val x = V in E'. The bound |
-/// value is in scope in the body. |
-/// During one-pass construction a LetVal with an empty body is used to |
-/// represent one-level context 'let val x = V in []'. |
-class LetPrim extends Expression implements InteriorNode { |
- final Primitive primitive; |
- Expression body = null; |
- |
- LetPrim(this.primitive); |
- |
- Expression plug(Expression expr) { |
- assert(body == null); |
- return body = expr; |
- } |
- |
- accept(Visitor visitor) => visitor.visitLetPrim(this); |
-} |
- |
- |
-/// Binding a continuation: 'let cont k(v) = E in E'. The bound continuation |
-/// is in scope in the body and the continuation parameter is in scope in the |
-/// continuation body. |
-/// During one-pass construction a LetCont with an empty continuation body is |
-/// used to represent the one-level context 'let cont k(v) = [] in E'. |
-class LetCont extends Expression implements InteriorNode { |
- Continuation continuation; |
- Expression body; |
- |
- LetCont(this.continuation, this.body); |
- |
- Expression plug(Expression expr) { |
- assert(continuation != null && continuation.body == null); |
- return continuation.body = expr; |
- } |
- |
- accept(Visitor visitor) => visitor.visitLetCont(this); |
-} |
- |
-abstract class Invoke { |
- Selector get selector; |
- List<Reference> get arguments; |
-} |
- |
-/// Represents a node with a child node, which can be accessed through the |
-/// `body` member. A typical usage is when removing a node from the CPS graph: |
-/// |
-/// Node child = node.body; |
-/// InteriorNode parent = node.parent; |
-/// |
-/// child.parent = parent; |
-/// parent.body = child; |
-abstract class InteriorNode implements Node { |
- Expression body; |
-} |
- |
-/// Invoke a static function or static field getter/setter. |
-class InvokeStatic extends Expression implements Invoke { |
- /// [FunctionElement] or [FieldElement]. |
- final Entity target; |
- |
- /** |
- * The selector encodes how the function is invoked: number of positional |
- * arguments, names used in named arguments. This information is required |
- * to build the [StaticCallSiteTypeInformation] for the inference graph. |
- */ |
- final Selector selector; |
- |
- final Reference continuation; |
- final List<Reference> arguments; |
- |
- InvokeStatic(this.target, this.selector, Continuation cont, |
- List<Definition> args) |
- : continuation = new Reference(cont), |
- arguments = _referenceList(args) { |
- assert(target is ErroneousElement || selector.name == target.name); |
- } |
- |
- accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
-} |
- |
-/// Invoke a method, operator, getter, setter, or index getter/setter. |
-/// Converting a method to a function object is treated as a getter invocation. |
-class InvokeMethod extends Expression implements Invoke { |
- final Reference receiver; |
- final Selector selector; |
- final Reference continuation; |
- final List<Reference> arguments; |
- |
- InvokeMethod(Definition receiver, |
- this.selector, |
- Continuation cont, |
- List<Definition> args) |
- : receiver = new Reference(receiver), |
- continuation = new Reference(cont), |
- arguments = _referenceList(args) { |
- assert(selector != null); |
- assert(selector.kind == SelectorKind.CALL || |
- selector.kind == SelectorKind.OPERATOR || |
- (selector.kind == SelectorKind.GETTER && arguments.isEmpty) || |
- (selector.kind == SelectorKind.SETTER && arguments.length == 1) || |
- (selector.kind == SelectorKind.INDEX && arguments.length == 1) || |
- (selector.kind == SelectorKind.INDEX && arguments.length == 2)); |
- } |
- |
- accept(Visitor visitor) => visitor.visitInvokeMethod(this); |
-} |
- |
-/// Invoke a method, operator, getter, setter, or index getter/setter from the |
-/// super class in tail position. |
-class InvokeSuperMethod extends Expression implements Invoke { |
- final Selector selector; |
- final Reference continuation; |
- final List<Reference> arguments; |
- |
- InvokeSuperMethod(this.selector, |
- Continuation cont, |
- List<Definition> args) |
- : continuation = new Reference(cont), |
- arguments = _referenceList(args) { |
- assert(selector != null); |
- assert(selector.kind == SelectorKind.CALL || |
- selector.kind == SelectorKind.OPERATOR || |
- (selector.kind == SelectorKind.GETTER && arguments.isEmpty) || |
- (selector.kind == SelectorKind.SETTER && arguments.length == 1) || |
- (selector.kind == SelectorKind.INDEX && arguments.length == 1) || |
- (selector.kind == SelectorKind.INDEX && arguments.length == 2)); |
- } |
- |
- accept(Visitor visitor) => visitor.visitInvokeSuperMethod(this); |
-} |
- |
-/// Non-const call to a constructor. The [target] may be a generative |
-/// constructor, factory, or redirecting factory. |
-class InvokeConstructor extends Expression implements Invoke { |
- final DartType type; |
- final FunctionElement target; |
- final Reference continuation; |
- final List<Reference> arguments; |
- final Selector selector; |
- |
- /// The class being instantiated. This is the same as `target.enclosingClass` |
- /// and `type.element`. |
- ClassElement get targetClass => target.enclosingElement; |
- |
- /// True if this is an invocation of a factory constructor. |
- bool get isFactory => target.isFactoryConstructor; |
- |
- InvokeConstructor(this.type, |
- this.target, |
- this.selector, |
- Continuation cont, |
- List<Definition> args) |
- : continuation = new Reference(cont), |
- arguments = _referenceList(args) { |
- assert(dart2js.invariant(target, |
- target.isErroneous || target.isConstructor, |
- message: "Constructor invocation target is not a constructor: " |
- "$target.")); |
- assert(dart2js.invariant(target, |
- target.isErroneous || |
- type.isDynamic || |
- type.element == target.enclosingClass.declaration, |
- message: "Constructor invocation type ${type} does not match enclosing " |
- "class of target ${target}.")); |
- } |
- |
- accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
-} |
- |
-/// "as" casts and "is" checks. |
-// We might want to turn "is"-checks into a [Primitive] as it can never diverge. |
-// But then we need to special-case for is-checks with an erroneous .type as |
-// these will throw. |
-class TypeOperator extends Expression { |
- final Reference receiver; |
- final DartType type; |
- final Reference continuation; |
- // TODO(johnniwinther): Use `Operator` class to encapsule the operator type. |
- final bool isTypeTest; |
- |
- TypeOperator(Primitive receiver, |
- this.type, |
- Continuation cont, |
- {bool this.isTypeTest}) |
- : this.receiver = new Reference(receiver), |
- this.continuation = new Reference(cont) { |
- assert(isTypeTest != null); |
- } |
- |
- bool get isTypeCast => !isTypeTest; |
- |
- accept(Visitor visitor) => visitor.visitTypeOperator(this); |
-} |
- |
-/// Invoke [toString] on each argument and concatenate the results. |
-class ConcatenateStrings extends Expression { |
- final Reference continuation; |
- final List<Reference> arguments; |
- |
- ConcatenateStrings(Continuation cont, List<Definition> args) |
- : continuation = new Reference(cont), |
- arguments = _referenceList(args); |
- |
- accept(Visitor visitor) => visitor.visitConcatenateStrings(this); |
-} |
- |
-/// Gets the value from a closure variable. The identity of the variable is |
-/// determined by a [Local]. |
-/// |
-/// Closure variables can be seen as ref cells that are not first-class values. |
-/// A [LetPrim] with a [GetClosureVariable] can then be seen as: |
-/// |
-/// let prim p = ![variable] in [body] |
-/// |
-class GetClosureVariable extends Primitive { |
- final Local variable; |
- |
- GetClosureVariable(this.variable) { |
- assert(variable != null); |
- } |
- |
- accept(Visitor visitor) => visitor.visitGetClosureVariable(this); |
-} |
- |
-/// Assign or declare a closure variable. The identity of the variable is |
-/// determined by a [Local]. |
-/// |
-/// Closure variables can be seen as ref cells that are not first-class values. |
-/// If [isDeclaration], this can seen as a let binding: |
-/// |
-/// let [variable] = ref [value] in [body] |
-/// |
-/// And otherwise, it can be seen as a dereferencing assignment: |
-/// |
-/// { ![variable] := [value]; [body] } |
-/// |
-/// Closure variables without a declaring [SetClosureVariable] are implicitly |
-/// declared at the entry to the [variable]'s enclosing function. |
-class SetClosureVariable extends Expression implements InteriorNode { |
- final Local variable; |
- final Reference value; |
- Expression body; |
- |
- /// If true, this declares a new copy of the closure variable. If so, all |
- /// uses of the closure variable must occur in the [body]. |
- /// |
- /// There can be at most one declaration per closure variable. If there is no |
- /// declaration, only one copy exists (per function execution). It is best to |
- /// avoid declaring closure variables if it is not necessary. |
- final bool isDeclaration; |
- |
- SetClosureVariable(this.variable, Primitive value, |
- {this.isDeclaration : false }) |
- : this.value = new Reference(value) { |
- assert(variable != null); |
- } |
- |
- accept(Visitor visitor) => visitor.visitSetClosureVariable(this); |
- |
- Expression plug(Expression expr) { |
- assert(body == null); |
- return body = expr; |
- } |
-} |
- |
-/// Create a potentially recursive function and store it in a closure variable. |
-/// The function can access itself using [GetClosureVariable] on [variable]. |
-/// There must not exist a [SetClosureVariable] to [variable]. |
-/// |
-/// This can be seen as a let rec binding: |
-/// |
-/// let rec [variable] = [definition] in [body] |
-/// |
-class DeclareFunction extends Expression implements InteriorNode { |
- final Local variable; |
- final FunctionDefinition definition; |
- Expression body; |
- |
- DeclareFunction(this.variable, this.definition); |
- |
- Expression plug(Expression expr) { |
- assert(body == null); |
- return body = expr; |
- } |
- |
- accept(Visitor visitor) => visitor.visitDeclareFunction(this); |
-} |
- |
-/// Invoke a continuation in tail position. |
-class InvokeContinuation extends Expression { |
- Reference continuation; |
- List<Reference> arguments; |
- |
- // An invocation of a continuation is recursive if it occurs in the body of |
- // the continuation itself. |
- bool isRecursive; |
- |
- InvokeContinuation(Continuation cont, List<Definition> args, |
- {recursive: false}) |
- : continuation = new Reference(cont), |
- arguments = _referenceList(args), |
- isRecursive = recursive { |
- assert(cont.parameters == null || |
- cont.parameters.length == args.length); |
- if (recursive) cont.isRecursive = true; |
- } |
- |
- /// A continuation invocation whose target and arguments will be filled |
- /// in later. |
- /// |
- /// Used as a placeholder for a jump whose target is not yet created |
- /// (e.g., in the translation of break and continue). |
- InvokeContinuation.uninitialized({recursive: false}) |
- : continuation = null, |
- arguments = null, |
- isRecursive = recursive; |
- |
- accept(Visitor visitor) => visitor.visitInvokeContinuation(this); |
-} |
- |
-/// The base class of things which can be tested and branched on. |
-abstract class Condition extends Node { |
-} |
- |
-class IsTrue extends Condition { |
- final Reference value; |
- |
- IsTrue(Definition val) : value = new Reference(val); |
- |
- accept(Visitor visitor) => visitor.visitIsTrue(this); |
-} |
- |
-/// Choose between a pair of continuations based on a condition value. |
-class Branch extends Expression { |
- final Condition condition; |
- final Reference trueContinuation; |
- final Reference falseContinuation; |
- |
- Branch(this.condition, Continuation trueCont, Continuation falseCont) |
- : trueContinuation = new Reference(trueCont), |
- falseContinuation = new Reference(falseCont); |
- |
- accept(Visitor visitor) => visitor.visitBranch(this); |
-} |
- |
-class Constant extends Primitive { |
- final ConstantExpression expression; |
- |
- Constant(this.expression); |
- |
- values.ConstantValue get value => expression.value; |
- |
- accept(Visitor visitor) => visitor.visitConstant(this); |
-} |
- |
-class This extends Primitive { |
- This(); |
- |
- accept(Visitor visitor) => visitor.visitThis(this); |
-} |
- |
-/// Reify the given type variable as a [Type]. |
-/// This depends on the current binding of 'this'. |
-class ReifyTypeVar extends Primitive { |
- final TypeVariableElement typeVariable; |
- |
- ReifyTypeVar(this.typeVariable); |
- |
- values.ConstantValue get constant => null; |
- |
- accept(Visitor visitor) => visitor.visitReifyTypeVar(this); |
-} |
- |
-class LiteralList extends Primitive { |
- /// The List type being created; this is not the type argument. |
- final GenericType type; |
- final List<Reference> values; |
- |
- LiteralList(this.type, Iterable<Primitive> values) |
- : this.values = _referenceList(values); |
- |
- accept(Visitor visitor) => visitor.visitLiteralList(this); |
-} |
- |
-class LiteralMapEntry { |
- final Reference key; |
- final Reference value; |
- |
- LiteralMapEntry(Primitive key, Primitive value) |
- : this.key = new Reference(key), |
- this.value = new Reference(value); |
-} |
- |
-class LiteralMap extends Primitive { |
- final GenericType type; |
- final List<LiteralMapEntry> entries; |
- |
- LiteralMap(this.type, this.entries); |
- |
- accept(Visitor visitor) => visitor.visitLiteralMap(this); |
-} |
- |
-/// Create a non-recursive function. |
-class CreateFunction extends Primitive { |
- final FunctionDefinition definition; |
- |
- CreateFunction(this.definition); |
- |
- accept(Visitor visitor) => visitor.visitCreateFunction(this); |
-} |
- |
-class Parameter extends Primitive { |
- Parameter(Element element) { |
- super.hint = element; |
- } |
- |
- accept(Visitor visitor) => visitor.visitParameter(this); |
-} |
- |
-/// Continuations are normally bound by 'let cont'. A continuation with one |
-/// parameter and no body is used to represent a function's return continuation. |
-/// The return continuation is bound by the Function, not by 'let cont'. |
-class Continuation extends Definition implements InteriorNode { |
- final List<Parameter> parameters; |
- Expression body = null; |
- |
- // A continuation is recursive if it has any recursive invocations. |
- bool isRecursive = false; |
- |
- bool get isReturnContinuation => body == null; |
- |
- Continuation(this.parameters); |
- |
- Continuation.retrn() : parameters = <Parameter>[new Parameter(null)]; |
- |
- accept(Visitor visitor) => visitor.visitContinuation(this); |
-} |
- |
-/// A function definition, consisting of parameters and a body. The parameters |
-/// include a distinguished continuation parameter. |
-class FunctionDefinition extends Node implements InteriorNode { |
- final FunctionElement element; |
- final Continuation returnContinuation; |
- final List<Parameter> parameters; |
- Expression body; |
- final List<ConstDeclaration> localConstants; |
- |
- /// Values for optional parameters. |
- final List<ConstantExpression> defaultParameterValues; |
- |
- FunctionDefinition(this.element, this.returnContinuation, |
- this.parameters, this.body, this.localConstants, |
- this.defaultParameterValues); |
- |
- FunctionDefinition.abstract(this.element, |
- this.parameters, |
- this.defaultParameterValues) |
- : this.returnContinuation = null, |
- this.localConstants = const <ConstDeclaration>[]; |
- |
- accept(Visitor visitor) => visitor.visitFunctionDefinition(this); |
- |
- /// Returns `true` if this function is abstract. |
- /// |
- /// If `true`, [body] and [returnContinuation] are `null` and [localConstants] |
- /// is empty. |
- bool get isAbstract => body == null; |
-} |
- |
-List<Reference> _referenceList(Iterable<Definition> definitions) { |
- return definitions.map((e) => new Reference(e)).toList(); |
-} |
- |
-abstract class Visitor<T> { |
- T visit(Node node) => node.accept(this); |
- // Abstract classes. |
- T visitNode(Node node) => null; |
- T visitExpression(Expression node) => visitNode(node); |
- T visitDefinition(Definition node) => visitNode(node); |
- T visitPrimitive(Primitive node) => visitDefinition(node); |
- T visitCondition(Condition node) => visitNode(node); |
- |
- // Concrete classes. |
- T visitFunctionDefinition(FunctionDefinition node) => visitNode(node); |
- |
- // Expressions. |
- T visitLetPrim(LetPrim node) => visitExpression(node); |
- T visitLetCont(LetCont node) => visitExpression(node); |
- T visitInvokeStatic(InvokeStatic node) => visitExpression(node); |
- T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node); |
- T visitInvokeMethod(InvokeMethod node) => visitExpression(node); |
- T visitInvokeSuperMethod(InvokeSuperMethod node) => visitExpression(node); |
- T visitInvokeConstructor(InvokeConstructor node) => visitExpression(node); |
- T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node); |
- T visitBranch(Branch node) => visitExpression(node); |
- T visitTypeOperator(TypeOperator node) => visitExpression(node); |
- T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node); |
- T visitDeclareFunction(DeclareFunction node) => visitExpression(node); |
- |
- // Definitions. |
- T visitLiteralList(LiteralList node) => visitPrimitive(node); |
- T visitLiteralMap(LiteralMap node) => visitPrimitive(node); |
- T visitConstant(Constant node) => visitPrimitive(node); |
- T visitThis(This node) => visitPrimitive(node); |
- T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node); |
- T visitCreateFunction(CreateFunction node) => visitPrimitive(node); |
- T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node); |
- T visitParameter(Parameter node) => visitPrimitive(node); |
- T visitContinuation(Continuation node) => visitDefinition(node); |
- |
- // Conditions. |
- T visitIsTrue(IsTrue node) => visitCondition(node); |
-} |
- |
-/// Recursively visits the entire CPS term, and calls abstract `process*` |
-/// (i.e. `processLetPrim`) functions in pre-order. |
-abstract class RecursiveVisitor extends Visitor { |
- // Ensures that RecursiveVisitor contains overrides for all relevant nodes. |
- // As a rule of thumb, nodes with structure to traverse should be overridden |
- // with the appropriate visits in this class (for example, visitLetCont), |
- // while leaving other nodes for subclasses (i.e., visitLiteralList). |
- visitNode(Node node) { |
- throw "RecursiveVisitor is stale, add missing visit overrides"; |
- } |
- |
- processReference(Reference ref) {} |
- |
- processFunctionDefinition(FunctionDefinition node) {} |
- visitFunctionDefinition(FunctionDefinition node) { |
- processFunctionDefinition(node); |
- node.parameters.forEach(visitParameter); |
- visit(node.body); |
- } |
- |
- // Expressions. |
- |
- processLetPrim(LetPrim node) {} |
- visitLetPrim(LetPrim node) { |
- processLetPrim(node); |
- visit(node.primitive); |
- visit(node.body); |
- } |
- |
- processLetCont(LetCont node) {} |
- visitLetCont(LetCont node) { |
- processLetCont(node); |
- visit(node.continuation); |
- visit(node.body); |
- } |
- |
- processInvokeStatic(InvokeStatic node) {} |
- visitInvokeStatic(InvokeStatic node) { |
- processInvokeStatic(node); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- processInvokeContinuation(InvokeContinuation node) {} |
- visitInvokeContinuation(InvokeContinuation node) { |
- processInvokeContinuation(node); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- processInvokeMethod(InvokeMethod node) {} |
- visitInvokeMethod(InvokeMethod node) { |
- processInvokeMethod(node); |
- processReference(node.receiver); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- processInvokeSuperMethod(InvokeSuperMethod node) {} |
- visitInvokeSuperMethod(InvokeSuperMethod node) { |
- processInvokeSuperMethod(node); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- processInvokeConstructor(InvokeConstructor node) {} |
- visitInvokeConstructor(InvokeConstructor node) { |
- processInvokeConstructor(node); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- processConcatenateStrings(ConcatenateStrings node) {} |
- visitConcatenateStrings(ConcatenateStrings node) { |
- processConcatenateStrings(node); |
- processReference(node.continuation); |
- node.arguments.forEach(processReference); |
- } |
- |
- |
- processBranch(Branch node) {} |
- visitBranch(Branch node) { |
- processBranch(node); |
- processReference(node.trueContinuation); |
- processReference(node.falseContinuation); |
- visit(node.condition); |
- } |
- |
- processTypeOperator(TypeOperator node) {} |
- visitTypeOperator(TypeOperator node) { |
- processTypeOperator(node); |
- processReference(node.continuation); |
- processReference(node.receiver); |
- } |
- |
- processSetClosureVariable(SetClosureVariable node) {} |
- visitSetClosureVariable(SetClosureVariable node) { |
- processSetClosureVariable(node); |
- processReference(node.value); |
- visit(node.body); |
- } |
- |
- processDeclareFunction(DeclareFunction node) {} |
- visitDeclareFunction(DeclareFunction node) { |
- processDeclareFunction(node); |
- visit(node.definition); |
- visit(node.body); |
- } |
- |
- // Definitions. |
- |
- processLiteralList(LiteralList node) {} |
- visitLiteralList(LiteralList node) { |
- processLiteralList(node); |
- node.values.forEach(processReference); |
- } |
- |
- processLiteralMap(LiteralMap node) {} |
- visitLiteralMap(LiteralMap node) { |
- processLiteralMap(node); |
- for (LiteralMapEntry entry in node.entries) { |
- processReference(entry.key); |
- processReference(entry.value); |
- } |
- } |
- |
- processConstant(Constant node) {} |
- visitConstant(Constant node) => processConstant(node); |
- |
- processThis(This node) {} |
- visitThis(This node) => processThis(node); |
- |
- processReifyTypeVar(ReifyTypeVar node) {} |
- visitReifyTypeVar(ReifyTypeVar node) => processReifyTypeVar(node); |
- |
- processCreateFunction(CreateFunction node) {} |
- visitCreateFunction(CreateFunction node) { |
- processCreateFunction(node); |
- visit(node.definition); |
- } |
- |
- processGetClosureVariable(GetClosureVariable node) {} |
- visitGetClosureVariable(GetClosureVariable node) => |
- processGetClosureVariable(node); |
- |
- processParameter(Parameter node) {} |
- visitParameter(Parameter node) => processParameter(node); |
- |
- processContinuation(Continuation node) {} |
- visitContinuation(Continuation node) { |
- processContinuation(node); |
- node.parameters.forEach(visitParameter); |
- visit(node.body); |
- } |
- |
- // Conditions. |
- |
- processIsTrue(IsTrue node) {} |
- visitIsTrue(IsTrue node) { |
- processIsTrue(node); |
- processReference(node.value); |
- } |
-} |
- |
-/// Keeps track of currently unused register indices. |
-class RegisterArray { |
- int nextIndex = 0; |
- final List<int> freeStack = <int>[]; |
- |
- /// Returns an index that is currently unused. |
- int makeIndex() { |
- if (freeStack.isEmpty) { |
- return nextIndex++; |
- } else { |
- return freeStack.removeLast(); |
- } |
- } |
- |
- void releaseIndex(int index) { |
- freeStack.add(index); |
- } |
-} |
- |
-/// Assigns indices to each primitive in the IR such that primitives that are |
-/// live simultaneously never get assigned the same index. |
-/// This information is used by the dart tree builder to generate fewer |
-/// redundant variables. |
-/// Currently, the liveness analysis is very simple and is often inadequate |
-/// for removing all of the redundant variables. |
-class RegisterAllocator extends Visitor { |
- /// Separate register spaces for each source-level variable/parameter. |
- /// Note that null is used as key for primitives without elements. |
- final Map<Element, RegisterArray> elementRegisters = |
- <Element, RegisterArray>{}; |
- |
- RegisterArray getRegisterArray(Element element) { |
- RegisterArray registers = elementRegisters[element]; |
- if (registers == null) { |
- registers = new RegisterArray(); |
- elementRegisters[element] = registers; |
- } |
- return registers; |
- } |
- |
- void allocate(Primitive primitive) { |
- if (primitive.registerIndex == null) { |
- primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex(); |
- } |
- } |
- |
- void release(Primitive primitive) { |
- // Do not share indices for temporaries as this may obstruct inlining. |
- if (primitive.hint == null) return; |
- if (primitive.registerIndex != null) { |
- getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex); |
- } |
- } |
- |
- void visitReference(Reference reference) { |
- allocate(reference.definition); |
- } |
- |
- void visitFunctionDefinition(FunctionDefinition node) { |
- if (!node.isAbstract) { |
- visit(node.body); |
- } |
- node.parameters.forEach(allocate); // Assign indices to unused parameters. |
- elementRegisters.clear(); |
- } |
- |
- void visitLetPrim(LetPrim node) { |
- visit(node.body); |
- release(node.primitive); |
- visit(node.primitive); |
- } |
- |
- void visitLetCont(LetCont node) { |
- visit(node.continuation); |
- visit(node.body); |
- } |
- |
- void visitInvokeStatic(InvokeStatic node) { |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitInvokeContinuation(InvokeContinuation node) { |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitInvokeMethod(InvokeMethod node) { |
- visitReference(node.receiver); |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitInvokeSuperMethod(InvokeSuperMethod node) { |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitInvokeConstructor(InvokeConstructor node) { |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitConcatenateStrings(ConcatenateStrings node) { |
- node.arguments.forEach(visitReference); |
- } |
- |
- void visitBranch(Branch node) { |
- visit(node.condition); |
- } |
- |
- void visitLiteralList(LiteralList node) { |
- node.values.forEach(visitReference); |
- } |
- |
- void visitLiteralMap(LiteralMap node) { |
- for (LiteralMapEntry entry in node.entries) { |
- visitReference(entry.key); |
- visitReference(entry.value); |
- } |
- } |
- |
- void visitTypeOperator(TypeOperator node) { |
- visitReference(node.receiver); |
- } |
- |
- void visitConstant(Constant node) { |
- } |
- |
- void visitThis(This node) { |
- } |
- |
- void visitReifyTypeVar(ReifyTypeVar node) { |
- } |
- |
- void visitCreateFunction(CreateFunction node) { |
- new RegisterAllocator().visit(node.definition); |
- } |
- |
- void visitGetClosureVariable(GetClosureVariable node) { |
- } |
- |
- void visitSetClosureVariable(SetClosureVariable node) { |
- visit(node.body); |
- visitReference(node.value); |
- } |
- |
- void visitDeclareFunction(DeclareFunction node) { |
- new RegisterAllocator().visit(node.definition); |
- visit(node.body); |
- } |
- |
- void visitParameter(Parameter node) { |
- throw "Parameters should not be visited by RegisterAllocator"; |
- } |
- |
- void visitContinuation(Continuation node) { |
- visit(node.body); |
- |
- // Arguments get allocated left-to-right, so we release parameters |
- // right-to-left. This increases the likelihood that arguments can be |
- // transferred without intermediate assignments. |
- for (int i = node.parameters.length - 1; i >= 0; --i) { |
- release(node.parameters[i]); |
- } |
- } |
- |
- void visitIsTrue(IsTrue node) { |
- visitReference(node.value); |
- } |
- |
-} |
- |