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 |
index b685c4582b9235c20c78583dc47cdbf5db06ba25..7a1850787ead40cbf62a296063868776deb7cf29 100644 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart |
@@ -119,6 +119,40 @@ abstract class Definition<T extends Definition<T>> extends Node { |
} |
} |
+class EffectiveUseIterator extends Iterator<Reference<Primitive>> { |
+ Reference<Primitive> current; |
+ Reference<Primitive> next; |
+ final List<Primitive> stack = <Primitive>[]; |
+ |
+ EffectiveUseIterator(Primitive prim) : next = prim.firstRef; |
+ |
+ bool moveNext() { |
+ Reference<Primitive> ref = next; |
+ while (true) { |
+ if (ref == null) { |
+ if (stack.isNotEmpty) { |
+ ref = stack.removeLast().firstRef; |
+ } else { |
+ return false; |
+ } |
+ } else if (ref.parent is Refinement) { |
+ stack.add(ref.parent); |
+ ref = ref.next; |
+ } else { |
+ current = ref; |
+ next = current.next; |
+ return true; |
+ } |
+ } |
+ } |
+} |
+ |
+class EffectiveUseIterable { |
+ Primitive primitive; |
+ EffectiveUseIterable(this.primitive); |
+ EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); |
+} |
+ |
/// A named value. |
/// |
/// The identity of the [Primitive] object is the name of the value. |
@@ -153,6 +187,34 @@ abstract class Primitive extends Definition<Primitive> { |
/// The source information associated with this primitive. |
// TODO(johnniwinther): Require source information for all primitives. |
SourceInformation get sourceInformation => null; |
+ |
+ /// If this is a [Refinement] node, returns the value being refined. |
+ Primitive get effectiveDefinition => this; |
+ |
+ /// True if the two primitives are (refinements of) the same value. |
+ bool sameValue(Primitive other) { |
+ return effectiveDefinition == other.effectiveDefinition; |
+ } |
+ |
+ /// Iterates all non-refinement uses of the primitive and all uses of |
+ /// a [Refinement] of this primitive (transitively). |
+ /// |
+ /// Notes regarding concurrent modification: |
+ /// - The current reference may safely be unlinked. |
+ /// - Yet unvisited references may not be unlinked. |
+ /// - References to this primitive created during iteration will not be seen. |
+ /// - References to a refinement of this primitive may not be created during |
+ /// iteration. |
+ EffectiveUseIterable get effectiveUses => new EffectiveUseIterable(this); |
+ |
+ bool get hasMultipleEffectiveUses { |
+ Iterator it = effectiveUses.iterator; |
+ return it.moveNext() && it.moveNext(); |
+ } |
+ |
+ bool get hasNoEffectiveUses { |
+ return !effectiveUses.iterator.moveNext(); |
+ } |
} |
/// Operands to invocations and primitives are always variables. They point to |
@@ -439,6 +501,28 @@ class InvokeConstructor extends CallExpression { |
accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
} |
+/// An alias for [value] in a context where the value is known to satisfy |
+/// [type]. |
+/// |
+/// Refinement nodes are inserted before the type propagator pass and removed |
+/// afterwards, so as not to complicate passes that don't reason about types, |
+/// but need to reason about value references being identical (i.e. referring |
+/// to the same primitive). |
+class Refinement extends Primitive { |
+ Reference<Primitive> value; |
+ final TypeMask type; |
+ |
+ Refinement(Primitive value, this.type) |
+ : value = new Reference<Primitive>(value); |
+ |
+ bool get isSafeForElimination => true; |
+ bool get isSafeForReordering => false; |
+ |
+ accept(Visitor visitor) => visitor.visitRefinement(this); |
+ |
+ Primitive get effectiveDefinition => value.definition.effectiveDefinition; |
+} |
+ |
/// An "is" type test. |
/// |
/// Returns `true` if [value] is an instance of [type]. |
@@ -1201,6 +1285,7 @@ abstract class Visitor<T> { |
T visitGetLength(GetLength node); |
T visitGetIndex(GetIndex node); |
T visitSetIndex(SetIndex node); |
+ T visitRefinement(Refinement node); |
// Support for literal foreign code. |
T visitForeignCode(ForeignCode node); |
@@ -1504,6 +1589,12 @@ class LeafVisitor implements Visitor { |
processReference(node.index); |
processReference(node.value); |
} |
+ |
+ processRefinement(Refinement node) {} |
+ visitRefinement(Refinement node) { |
+ processRefinement(node); |
+ processReference(node.value); |
+ } |
} |
typedef void StackAction(); |