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

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

Issue 10702167: Fix bug in recompilation handling. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 5 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/nodes.dart ('k') | tests/language/field_optimization3_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/ssa/optimize.dart
diff --git a/lib/compiler/implementation/ssa/optimize.dart b/lib/compiler/implementation/ssa/optimize.dart
index d0f9286c7f4fde6c3abc6399835788b985f2926c..c8ef7e5129f39271f2572ead4d3d76bbff06f9c1 100644
--- a/lib/compiler/implementation/ssa/optimize.dart
+++ b/lib/compiler/implementation/ssa/optimize.dart
@@ -37,7 +37,7 @@ class SsaOptimizerTask extends CompilerTask {
new SsaGlobalValueNumberer(compiler),
new SsaCodeMotion(),
new SsaDeadCodeEliminator(),
- new SsaProcessRecompileCandidates(backend, work)];
+ new SsaRegisterRecompilationCandidates(backend, work)];
runPhases(graph, phases);
});
}
@@ -46,6 +46,7 @@ class SsaOptimizerTask extends CompilerTask {
return measure(() {
// Run the phases that will generate type guards.
List<OptimizationPhase> phases = <OptimizationPhase>[
+ new SsaRecompilationFieldTypePropagator(backend, work),
new SsaSpeculativeTypePropagator(compiler),
new SsaTypeGuardInserter(compiler, work),
new SsaEnvironmentBuilder(compiler),
@@ -1156,124 +1157,23 @@ class SsaTypeConversionInserter extends HBaseVisitor
}
}
-class SsaProcessRecompileCandidates
- extends HBaseVisitor implements OptimizationPhase {
- final String name = "SsaProcessRecompileCandidates";
+
+// Base class for the handling of recompilation based on inferred
+// field types.
+class BaseRecompilationVisitor extends HBaseVisitor {
final JavaScriptBackend backend;
final WorkItem work;
- HGraph graph;
Compiler get compiler() => backend.compiler;
- SsaProcessRecompileCandidates(this.backend, this.work);
-
- void visitGraph(HGraph visitee) {
- graph = visitee;
- visitDominatorTree(visitee);
- }
+ BaseRecompilationVisitor(this.backend, this.work);
- void visitFieldGet(HFieldGet node) {
- if (!node.element.enclosingElement.isClass()) return;
- Element field = node.element;
- HType type = backend.optimisticFieldTypeAfterConstruction(field);
- if (!type.isUnknown()) {
- switch (compiler.phase) {
- case Compiler.PHASE_COMPILING:
- // Recompile even if we haven't seen any types for this
- // field yet. There might still be only one setter in an
- // initializer list or constructor body.
- compiler.enqueuer.codegen.registerRecompilationCandidate(
- work.element);
- break;
- case Compiler.PHASE_RECOMPILING:
- if (!type.isConflicting()) {
- // Check if optimistic type is based on a setter in the
- // constructor body.
- if (backend.hasConstructorBodyFieldSetter(field)) {
- // If there are no other field setters then the one in
- // the constructor body, the type is guaranteed for this
- // field after construction.
- assert(!node.element.isGenerativeConstructorBody());
- if (!compiler.codegenWorld.hasInvokedSetter(field, compiler)) {
- node.guaranteedType =
- type.union(backend.fieldSettersTypeSoFar(node.element));
- } else {
- node.propagatedType =
- type.union(backend.fieldSettersTypeSoFar(node.element));
- }
- } else {
- // If there are no setters the initializer list type is
- // guaranteed to remain constant.
- //
- // TODO(ager): Why is this treated differently from the
- // case above? It seems to me that we could/should use
- // the union of the types for the field setters and the
- // initializer list here? It would give the same when
- // there are none and potentially better information for
- // more cases.
- if (!compiler.codegenWorld.hasFieldSetter(field, compiler) &&
- !compiler.codegenWorld.hasInvokedSetter(field, compiler)) {
- node.guaranteedType = type;
- } else {
- node.propagatedType = type;
- }
- }
- }
- break;
- }
- }
- }
-
- HInstruction visitEquals(HEquals node) {
- // Determine if one of the operands is an HFieldGet.
- HFieldGet field;
- HInstruction other;
- if (node.left is HFieldGet) {
- field = node.left;
- other = node.right;
- } else if (node.right is HFieldGet) {
- field = node.right;
- other = node.left;
- }
- // Try to optimize the case where a field which is known to always be an
- // integer is compared with a constant integer literal.
- if (other != null &&
- other.isConstantInteger() &&
- field.element != null &&
- field.element.enclosingElement.isClass()) {
- // Calculate the field type from the information available.
- HType type =
- backend.fieldSettersTypeSoFar(field.element).union(
- backend.typeFromInitializersSoFar(field.element));
- if (!type.isUnknown()) {
- switch (compiler.phase) {
- case Compiler.PHASE_COMPILING:
- compiler.enqueuer.codegen.registerRecompilationCandidate(
- work.element);
- break;
- case Compiler.PHASE_RECOMPILING:
- if (compiler.codegenWorld.hasInvokedSetter(field.element,
- compiler)) {
- // If there are invoked setters we don't know for sure that the
- // field will hold the calculated, but the fact that the class
- // itself stick to this type in the field is still a strong
- // signal to indicate the expected type of the field.
- field.propagatedType = type;
- graph.highTypeLikelyhood = true;
- } else {
- // If there are no invoked setters we know the type of this
- // field for sure.
- field.guaranteedType = type;
- }
- break;
- default:
- assert(false);
- break;
- }
- }
- }
- }
+ abstract void handleFieldGet(HFieldGet node, HType type);
+ abstract void handleFieldNumberOperation(HFieldGet field, HType type);
- HInstruction visitBinaryArithmetic(HBinaryArithmetic node) {
+ // Checks if the binary invocation operates on a field and a
+ // constant number. If it does [handleFieldNumberOperation] is
+ // called with the field and the type inferred for the field so far.
+ void checkFieldNumberOperation(HInvokeBinary node) {
// Determine if one of the operands is an HFieldGet.
HFieldGet field;
HInstruction other;
@@ -1284,46 +1184,147 @@ class SsaProcessRecompileCandidates
field = node.right;
other = node.left;
}
- // Check that the other operand is a number and that we have type
- // information for the field get.
+ // Try to optimize the case where a field which is known to always
+ // be an integer is compared with a constant number.
if (other != null &&
other.isConstantNumber() &&
field.element != null &&
field.element.enclosingElement.isClass()) {
- // If we have type information for the field and it contains
- // NUMBER, we mark for recompilation.
+ // Calculate the field type from the information available. If
+ // we have type information for the field and it contains NUMBER
+ // we use it as a candidate for recompilation.
Element fieldElement = field.element;
HType fieldSettersType = backend.fieldSettersTypeSoFar(fieldElement);
HType initializersType = backend.typeFromInitializersSoFar(fieldElement);
HType fieldType = fieldSettersType.union(initializersType);
HType type = HType.NUMBER.union(fieldType);
if (type == HType.NUMBER) {
- switch (compiler.phase) {
- case Compiler.PHASE_COMPILING:
- compiler.enqueuer.codegen.registerRecompilationCandidate(
- work.element);
- break;
- case Compiler.PHASE_RECOMPILING:
- if (compiler.codegenWorld.hasInvokedSetter(fieldElement,
- compiler)) {
- // If there are invoked setters we don't know for sure
- // that the field will hold a value of the calculated
- // type, but the fact that the class itself sticks to
- // this type for the field is still a strong signal
- // indicating the expected type of the field.
- field.propagatedType = type;
- graph.highTypeLikelyhood = true;
- } else {
- // If there are no invoked setters we know the type of
- // this field for sure.
- field.guaranteedType = type;
- }
- break;
- default:
- assert(false);
- break;
+ handleFieldNumberOperation(field, fieldType);
+ }
+ }
+ }
+
+ void visitFieldGet(HFieldGet node) {
+ if (!node.element.isInstanceMember()) return;
+ Element field = node.element;
+ HType type = backend.optimisticFieldTypeAfterConstruction(field);
+ if (!type.isUnknown()) {
+ // Allow handling even if we haven't seen any types for this
+ // field yet. There might still be only one setter in an
+ // initializer list or constructor body and recompilation
+ // can therefore pay off.
+ handleFieldGet(node, type);
+ }
+ }
+
+ HInstruction visitEquals(HEquals node) {
+ checkFieldNumberOperation(node);
+ }
+
+ HInstruction visitBinaryArithmetic(HBinaryArithmetic node) {
+ checkFieldNumberOperation(node);
+ }
+}
+
+
+// Visitor that registers candidates for recompilation.
+class SsaRegisterRecompilationCandidates
+ extends BaseRecompilationVisitor implements OptimizationPhase {
+ final String name = "SsaRegisterRecompileCandidates";
+ HGraph graph;
+
+ SsaRegisterRecompilationCandidates(
+ JavaScriptBackend backend, WorkItem work) : super(backend, work);
+
+ void visitGraph(HGraph visitee) {
+ graph = visitee;
+ if (compiler.phase == Compiler.PHASE_COMPILING) {
+ visitDominatorTree(visitee);
+ }
+ }
+
+ void handleFieldGet(HFieldGet node, HType type) {
+ assert(compiler.phase == Compiler.PHASE_COMPILING);
+ compiler.enqueuer.codegen.registerRecompilationCandidate(
+ work.element);
+ }
+
+ void handleFieldNumberOperation(HFieldGet node, HType type) {
+ assert(compiler.phase == Compiler.PHASE_COMPILING);
+ compiler.enqueuer.codegen.registerRecompilationCandidate(
+ work.element);
+ }
+}
+
+
+// Visitor that sets the known or suspected type of fields during
+// recompilation.
+class SsaRecompilationFieldTypePropagator
+ extends BaseRecompilationVisitor implements OptimizationPhase {
+ final String name = "SsaRecompilationFieldTypePropagator";
+ HGraph graph;
+
+ SsaRecompilationFieldTypePropagator(
+ JavaScriptBackend backend, WorkItem work) : super(backend, work);
+
+ void visitGraph(HGraph visitee) {
+ graph = visitee;
+ if (compiler.phase == Compiler.PHASE_RECOMPILING) {
+ visitDominatorTree(visitee);
+ }
+ }
+
+ void handleFieldGet(HFieldGet field, HType type) {
+ assert(compiler.phase == Compiler.PHASE_RECOMPILING);
+ if (!type.isConflicting()) {
+ Element element = field.element;
+ // Check if optimistic type is based on a setter in the
+ // constructor body.
+ if (backend.hasConstructorBodyFieldSetter(element)) {
+ // If there are no other field setters then the one in
+ // the constructor body, the type is guaranteed for this
+ // field after construction.
+ assert(!element.isGenerativeConstructorBody());
+ if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) {
+ field.guaranteedType =
+ type.union(backend.fieldSettersTypeSoFar(element));
+ } else {
+ field.propagatedType =
+ type.union(backend.fieldSettersTypeSoFar(element));
+ }
+ } else {
+ // If there are no setters the initializer list type is
+ // guaranteed to remain constant.
+ //
+ // TODO(ager): Why is this treated differently from the
+ // case above? It seems to me that we could/should use
+ // the union of the types for the field setters and the
+ // initializer list here? It would give the same when
+ // there are none and potentially better information for
+ // more cases.
+ if (!compiler.codegenWorld.hasFieldSetter(element, compiler) &&
+ !compiler.codegenWorld.hasInvokedSetter(element, compiler)) {
+ field.guaranteedType = type;
+ } else {
+ field.propagatedType = type;
}
}
}
}
+
+ void handleFieldNumberOperation(HFieldGet field, HType type) {
+ assert(compiler.phase == Compiler.PHASE_RECOMPILING);
+ if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) {
+ // If there are invoked setters we don't know for sure
+ // that the field will hold a value of the calculated
+ // type, but the fact that the class itself sticks to
+ // this type for the field is still a strong signal
+ // indicating the expected type of the field.
+ field.propagatedType = type;
+ } else {
+ // If there are no invoked setters we know the type of
+ // this field for sure.
+ field.guaranteedType = type;
+ }
+ }
}
« no previous file with comments | « lib/compiler/implementation/ssa/nodes.dart ('k') | tests/language/field_optimization3_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698