Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(611)

Unified Diff: lib/compiler/implementation/ssa/types.dart

Issue 10139012: Refactor types in ssa nodes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/compiler/implementation/ssa/tracer.dart ('k') | lib/compiler/implementation/ssa/types_propagation.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/ssa/types.dart
diff --git a/lib/compiler/implementation/ssa/types.dart b/lib/compiler/implementation/ssa/types.dart
index 0f12bb9e8e1b3d6998147afeddea202411b5822c..2afdea04f941a1fd202cf714ae3334a44ed2b90b 100644
--- a/lib/compiler/implementation/ssa/types.dart
+++ b/lib/compiler/implementation/ssa/types.dart
@@ -1,139 +1,292 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2012, 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.
-class SsaTypePropagator extends HGraphVisitor implements OptimizationPhase {
-
- final Map<int, HInstruction> workmap;
- final List<int> worklist;
- final Compiler compiler;
- String get name() => 'type propagator';
-
- SsaTypePropagator(Compiler this.compiler)
- : workmap = new Map<int, HInstruction>(),
- worklist = new List<int>();
-
-
- HType computeType(HInstruction instruction) {
- return instruction.computeTypeFromInputTypes();
- }
-
- // Re-compute and update the type of the instruction. Returns
- // whether or not the type was changed.
- bool updateType(HInstruction instruction) {
- HType oldType = instruction.propagatedType;
- HType newType = instruction.hasGuaranteedType()
- ? instruction.guaranteedType
- : computeType(instruction);
- // We unconditionally replace the propagated type with the new type. The
- // computeType must make sure that we eventually reach a stable state.
- instruction.propagatedType = newType;
- return oldType !== newType;
- }
-
- void visitGraph(HGraph graph) {
- visitDominatorTree(graph);
- processWorklist();
- }
-
- visitBasicBlock(HBasicBlock block) {
- if (block.isLoopHeader()) {
- block.forEachPhi((HPhi phi) {
- // Set the initial type for the phi. In theory we would need to mark the
- // type of all other incoming edges as "unitialized" and take this into
- // account when doing the propagation inside the phis. Just setting
- // the [propagatedType] is however easier.
- phi.propagatedType = phi.inputs[0].propagatedType;
- addToWorkList(phi);
- });
- } else {
- block.forEachPhi((HPhi phi) {
- if (updateType(phi)) addDependentInstructionsToWorkList(phi);
- });
- }
+abstract class HType {
+ const HType();
- HInstruction instruction = block.first;
- while (instruction !== null) {
- if (updateType(instruction)) {
- addDependentInstructionsToWorkList(instruction);
- }
- instruction = instruction.next;
- }
+ static final HType CONFLICTING = const HAnalysisType("conflicting");
+ static final HType UNKNOWN = const HAnalysisType("unknown");
+ static final HType BOOLEAN = const HBooleanType();
+ static final HType NUMBER = const HNumberType();
+ static final HType INTEGER = const HIntegerType();
+ static final HType DOUBLE = const HDoubleType();
+ static final HType INDEXABLE_PRIMITIVE = const HIndexablePrimitiveType();
+ static final HType STRING = const HStringType();
+ static final HType READABLE_ARRAY = const HReadableArrayType();
+ static final HType MUTABLE_ARRAY = const HMutableArrayType();
+ static final HType EXTENDABLE_ARRAY = const HExtendableArrayType();
+
+ bool isConflicting() => this === CONFLICTING;
+ bool isUnknown() => this === UNKNOWN;
+ bool isBoolean() => false;
+ bool isNumber() => false;
+ bool isInteger() => false;
+ bool isDouble() => false;
+ bool isString() => false;
+ bool isIndexablePrimitive() => false;
+ bool isReadableArray() => false;
+ bool isMutableArray() => false;
+ bool isExtendableArray() => false;
+ bool isPrimitive() => false;
+ bool isNonPrimitive() => false;
+
+ /** A type is useful it is not unknown and not conflicting. */
+ bool isUseful() => !isUnknown() && !isConflicting();
+ /** Alias for isReadableArray. */
+ bool isArray() => isReadableArray();
+
+ /**
+ * The intersection of two types is the intersection of its values. For
+ * example:
+ * * INTEGER.intersect(NUMBER) => INTEGER.
+ * * DOUBLE.intersect(INTEGER) => CONFLICTING.
+ * * MUTABLE_ARRAY.intersect(READABLE_ARRAY) => MUTABLE_ARRAY.
+ *
+ * When there is no predefined type to represent the intersection returns
+ * [CONFLICTING].
+ *
+ * An intersection with [UNKNOWN] returns the non-UNKNOWN type. An
+ * intersection with [CONFLICTING] returns [CONFLICTING].
+ */
+ abstract HType intersection(HType other);
+
+ /**
+ * The union of two types is the union of its values. For example:
+ * * INTEGER.union(NUMBER) => NUMBER.
+ * * DOUBLE.union(INTEGER) => NUMBER.
+ * * MUTABLE_ARRAY.union(READABLE_ARRAY) => READABLE_ARRAY.
+ *
+ * When there is no predefined type to represent the union returns
+ * [CONFLICTING].
+ *
+ * A union with [UNKNOWN] returns the non-UNKNOWN type. A union with
+ * [CONFLICTING] returns [CONFLICTING].
+ */
+ abstract HType union(HType other);
+}
+
+/** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */
+class HAnalysisType extends HType {
+ final String name;
+ const HAnalysisType(this.name);
+ String toString() => name;
+
+ HType combine(HType other) {
+ if (isUnknown()) return other;
+ if (other.isUnknown()) return this;
+ return HType.CONFLICTING;
}
- void processWorklist() {
- while (!worklist.isEmpty()) {
- int id = worklist.removeLast();
- HInstruction instruction = workmap[id];
- assert(instruction !== null);
- workmap.remove(id);
- if (updateType(instruction)) {
- addDependentInstructionsToWorkList(instruction);
- }
- }
+ HType union(HType other) => combine(other);
+ HType intersection(HType other) => combine(other);
+}
+
+abstract class HPrimitiveType extends HType {
+ const HPrimitiveType();
+ bool isPrimitive() => true;
+}
+
+class HBooleanType extends HPrimitiveType {
+ const HBooleanType();
+ bool isBoolean() => true;
+ String toString() => "boolean";
+
+ HType combine(HType other) {
+ if (other.isBoolean() || other.isUnknown()) return HType.BOOLEAN;
+ return HType.CONFLICTING;
+ }
+
+ // Since the boolean type is a one-element set the union and intersection are
+ // the same.
+ HType union(HType other) => combine(other);
+ HType intersection(HType other) => combine(other);
+}
+
+class HNumberType extends HPrimitiveType {
+ const HNumberType();
+ bool isNumber() => true;
+ String toString() => "number";
+
+ HType union(HType other) {
+ if (other.isNumber() || other.isUnknown()) return HType.NUMBER;
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (other.isUnknown()) return HType.NUMBER;
+ if (other.isNumber()) return other;
+ return HType.CONFLICTING;
+ }
+}
+
+class HIntegerType extends HNumberType {
+ const HIntegerType();
+ bool isInteger() => true;
+ String toString() => "integer";
+
+ HType union(HType other) {
+ if (other.isInteger() || other.isUnknown()) return HType.INTEGER;
+ if (other.isNumber()) return HType.NUMBER;
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (other.isUnknown()) return HType.INTEGER;
+ if (other.isDouble()) return HType.CONFLICTING;
+ if (other.isNumber()) return this;
+ return HType.CONFLICTING;
+ }
+}
+
+class HDoubleType extends HNumberType {
+ const HDoubleType();
+ bool isDouble() => true;
+ String toString() => "double";
+
+ HType union(HType other) {
+ if (other.isDouble() || other.isUnknown()) return HType.DOUBLE;
+ if (other.isNumber()) return HType.NUMBER;
+ return HType.CONFLICTING;
}
- void addDependentInstructionsToWorkList(HInstruction instruction) {
- for (int i = 0, length = instruction.usedBy.length; i < length; i++) {
- // The non-speculative type propagator only propagates types forward. We
- // thus only need to add the users of the [instruction] to the list.
- addToWorkList(instruction.usedBy[i]);
+ HType intersection(HType other) {
+ if (other.isUnknown()) return HType.DOUBLE;
+ if (other.isInteger()) return HType.CONFLICTING;
+ if (other.isNumber()) return this;
+ return HType.CONFLICTING;
+ }
+}
+
+class HIndexablePrimitiveType extends HPrimitiveType {
+ const HIndexablePrimitiveType();
+ bool isIndexablePrimitive() => true;
+ String toString() => "indexable";
+
+ HType union(HType other) {
+ if (other.isIndexablePrimitive() || other.isUnknown()) {
+ return HType.INDEXABLE_PRIMITIVE;
}
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (other.isUnknown()) return HType.INDEXABLE_PRIMITIVE;
+ if (other.isIndexablePrimitive()) return other;
+ return HType.CONFLICTING;
+ }
+}
+
+class HStringType extends HIndexablePrimitiveType {
+ const HStringType();
+ bool isString() => true;
+ String toString() => "string";
+
+ HType union(HType other) {
+ if (other.isString() || other.isUnknown()) return HType.STRING;
+ if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE;
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (other.isString() || other.isUnknown()) return HType.STRING;
+ if (other.isArray()) return HType.CONFLICTING;
+ if (other.isIndexablePrimitive()) return HType.STRING;
+ return HType.CONFLICTING;
}
+}
+
+class HReadableArrayType extends HIndexablePrimitiveType {
+ const HReadableArrayType();
+ bool isReadableArray() => true;
+ String toString() => "readable array";
- void addToWorkList(HInstruction instruction) {
- final int id = instruction.id;
- if (!workmap.containsKey(id)) {
- worklist.add(id);
- workmap[id] = instruction;
+ HType union(HType other) {
+ if (other.isReadableArray() || other.isUnknown()) {
+ return HType.READABLE_ARRAY;
}
+ if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE;
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (this === other || other.isUnknown()) return HType.READABLE_ARRAY;
+ if (other.isString()) return HType.CONFLICTING;
+ if (other.isReadableArray()) return other;
+ if (other.isIndexablePrimitive()) return this;
+ return HType.CONFLICTING;
}
}
-class SsaSpeculativeTypePropagator extends SsaTypePropagator {
- final String name = 'speculative type propagator';
- SsaSpeculativeTypePropagator(Compiler compiler) : super(compiler);
-
- void addDependentInstructionsToWorkList(HInstruction instruction) {
- // The speculative type propagator propagates types forward and backward.
- // Not only do we need to add the users of the [instruction] to the list.
- // We also need to add the inputs fo the [instruction], since they might
- // want to propagate the desired outgoing type.
- for (int i = 0, length = instruction.usedBy.length; i < length; i++) {
- addToWorkList(instruction.usedBy[i]);
+class HMutableArrayType extends HReadableArrayType {
+ const HMutableArrayType();
+ bool isMutableArray() => true;
+ String toString() => "mutable array";
+
+ HType union(HType other) {
+ if (other.isMutableArray() || other.isUnknown()) {
+ return HType.MUTABLE_ARRAY;
}
- for (int i = 0, length = instruction.inputs.length; i < length; i++) {
- addToWorkList(instruction.inputs[i]);
+ if (other.isReadableArray()) return HType.READABLE_ARRAY;
+ if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE;
+ return HType.CONFLICTING;
+ }
+
+ HType intersection(HType other) {
+ if (this === other || other.isUnknown()) return HType.MUTABLE_ARRAY;
+ if (other.isString()) return HType.CONFLICTING;
+ if (other.isMutableArray()) return other;
+ if (other.isIndexablePrimitive()) return HType.MUTABLE_ARRAY;
+ return HType.CONFLICTING;
+ }
+}
+
+class HExtendableArrayType extends HMutableArrayType {
+ const HExtendableArrayType();
+ bool isExtendableArray() => true;
+ String toString() => "extendable array";
+
+ HType union(HType other) {
+ if (other.isExtendableArray() || other.isUnknown()) {
+ return HType.EXTENDABLE_ARRAY;
}
+ if (other.isMutableArray()) return HType.MUTABLE_ARRAY;
+ if (other.isReadableArray()) return HType.READABLE_ARRAY;
+ if (other.isIndexablePrimitive()) return HType.INDEXABLE_PRIMITIVE;
+ return HType.CONFLICTING;
}
- HType computeDesiredType(HInstruction instruction) {
- HType desiredType = HType.UNKNOWN;
- for (final user in instruction.usedBy) {
- desiredType =
- desiredType.combine(user.computeDesiredTypeForInput(instruction));
- // No need to continue if two users disagree on the type.
- if (desiredType.isConflicting()) break;
+ HType intersection(HType other) {
+ if (this === other || other.isUnknown()) return HType.EXTENDABLE_ARRAY;
+ if (other.isString()) return HType.CONFLICTING;
+ if (other.isIndexablePrimitive()) return HType.EXTENDABLE_ARRAY;
+ return HType.CONFLICTING;
+ }
+}
+
+class HNonPrimitiveType extends HType {
+ final Type type;
+
+ const HNonPrimitiveType(Type this.type);
+ bool isNonPrimitive() => true;
+ String toString() => type.toString();
+
+ HType combine(HType other) {
+ if (other.isNonPrimitive()) {
+ HNonPrimitiveType temp = other;
+ if (this.type === temp.type) return this;
}
- return desiredType;
- }
-
- HType computeType(HInstruction instruction) {
- // Once we are in a conflicting state don't update the type anymore.
- HType oldType = instruction.propagatedType;
- if (oldType.isConflicting()) return oldType;
-
- HType newType = super.computeType(instruction);
- // [computeDesiredType] goes to all usedBys and lets them compute their
- // desired type. By setting the [newType] here we give them more context to
- // work with.
- instruction.propagatedType = newType;
- HType desiredType = computeDesiredType(instruction);
- // If the desired type is conflicting just return the computed type.
- if (desiredType.isConflicting()) return newType;
- // TODO(ngeoffray): Allow speculative optimizations on
- // non-primitive types?
- if (desiredType.isNonPrimitive()) return newType;
- return newType.combine(desiredType);
+ if (other.isUnknown()) return this;
+ return HType.CONFLICTING;
+ }
+
+ // As long as we don't keep track of super/sub types for non-primitive types
+ // the intersection and union is the same.
+ HType intersection(HType other) => combine(other);
+ HType union(HType other) => combine(other);
+
+ Element lookupMember(SourceString name) {
+ ClassElement classElement = type.element;
+ return classElement.lookupMember(name);
}
}
« no previous file with comments | « lib/compiler/implementation/ssa/tracer.dart ('k') | lib/compiler/implementation/ssa/types_propagation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698