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

Unified Diff: pkg/compiler/lib/src/cps_ir/type_propagation.dart

Issue 1330503003: dart2js cps: Add path-sensitive types by inserting refinement IR nodes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Comments Created 5 years, 3 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
Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 3212f9406308c66fd34bf3c33220d4125f53e861..1ac163ee538b0732f31819e3dfb1f7c485a61acb 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, 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.
+library dart2js.cps_ir.type_propagation;
import 'optimizers.dart';
@@ -700,6 +701,7 @@ class TransformingVisitor extends LeafVisitor {
void visitLetPrim(LetPrim node) {
AbstractValue value = getValue(node.primitive);
if (node.primitive is! Constant &&
+ node.primitive is! Refinement &&
node.primitive.isSafeForElimination &&
value.isConstant) {
// If the value is a known constant, compile it as a constant.
@@ -1132,16 +1134,17 @@ class TransformingVisitor extends LeafVisitor {
/// This is a short-term solution to avoid inserting a lot of bounds checks,
/// since there is currently no optimization for eliminating them.
bool hasTooManyIndexAccesses(Primitive receiver) {
+ receiver = receiver.effectiveDefinition;
int count = 0;
- for (Reference ref = receiver.firstRef; ref != null; ref = ref.next) {
+ for (Reference ref in receiver.effectiveUses) {
Node use = ref.parent;
if (use is InvokeMethod &&
(use.selector.isIndex || use.selector.isIndexSet) &&
- getDartReceiver(use) == receiver) {
+ getDartReceiver(use).sameValue(receiver)) {
++count;
- } else if (use is GetIndex && use.object.definition == receiver) {
+ } else if (use is GetIndex && use.object.definition.sameValue(receiver)) {
++count;
- } else if (use is SetIndex && use.object.definition == receiver) {
+ } else if (use is SetIndex && use.object.definition.sameValue(receiver)) {
++count;
}
if (count > 2) return true;
@@ -1322,7 +1325,7 @@ class TransformingVisitor extends LeafVisitor {
// Check that all uses of the iterator are 'moveNext' and 'current'.
assert(!isInterceptedSelector(Selectors.moveNext));
assert(!isInterceptedSelector(Selectors.current));
- for (Reference ref = iterator.firstRef; ref != null; ref = ref.next) {
+ for (Reference ref in iterator.effectiveUses) {
if (ref.parent is! InvokeMethod) return false;
InvokeMethod use = ref.parent;
if (ref != use.receiver) return false;
@@ -1339,8 +1342,8 @@ class TransformingVisitor extends LeafVisitor {
MutableVariable current = new MutableVariable(new LoopItemEntity());
// Rewrite all uses of the iterator.
- while (iterator.firstRef != null) {
- InvokeMethod use = iterator.firstRef.parent;
+ for (Reference ref in iterator.effectiveUses) {
+ InvokeMethod use = ref.parent;
Continuation useCont = use.continuation.definition;
if (use.selector == Selectors.current) {
// Rewrite iterator.current to a use of the 'current' variable.
@@ -1446,6 +1449,9 @@ class TransformingVisitor extends LeafVisitor {
}
}
+ // All effective uses have been rewritten.
+ destroyRefinementsOfDeadPrimitive(iterator);
+
// Rewrite the iterator call to initializers for 'index' and 'current'.
CpsFragment cps = new CpsFragment();
cps.letMutable(index, cps.makeZero());
@@ -1488,7 +1494,8 @@ class TransformingVisitor extends LeafVisitor {
while (true) {
Node parent = node.parent;
if (parent is LetCont ||
- parent is LetPrim && parent.primitive.isSafeForReordering) {
+ parent is LetPrim && parent.primitive.isSafeForReordering ||
+ parent is LetPrim && parent.primitive is Refinement) {
node = parent;
} else {
return parent;
@@ -1510,7 +1517,7 @@ class TransformingVisitor extends LeafVisitor {
assert(!isInterceptedSelector(call));
assert(call.argumentCount == node.arguments.length);
- Primitive tearOff = node.receiver.definition;
+ Primitive tearOff = node.receiver.definition.effectiveDefinition;
// Note: We don't know if [tearOff] is actually a tear-off.
// We name variables based on the pattern we are trying to match.
@@ -1545,9 +1552,6 @@ class TransformingVisitor extends LeafVisitor {
Continuation getterCont = tearOffInvoke.continuation.definition;
- // TODO(asgerf): Support torn-off intercepted methods.
- if (isInterceptedSelector(getter)) return false;
-
Primitive object = tearOffInvoke.receiver.definition;
// Ensure that the object actually has a foo member, since we might
@@ -1561,7 +1565,7 @@ class TransformingVisitor extends LeafVisitor {
// If there are multiple uses, we cannot eliminate the getter call and
// therefore risk duplicating its side effects.
- if (!isPure && tearOff.hasMultipleUses) return false;
+ if (!isPure && tearOff.hasMultipleEffectiveUses) return false;
// If the getter call is impure, we risk reordering side effects.
if (!isPure && getEffectiveParent(node) != getterCont) {
@@ -1578,10 +1582,11 @@ class TransformingVisitor extends LeafVisitor {
node.receiver.unlink();
replaceSubtree(node, invoke, unlink: false);
- if (tearOff.hasNoUses) {
+ if (tearOff.hasNoEffectiveUses) {
// Eliminate the getter call if it has no more uses.
// This cannot be delegated to other optimizations because we need to
// avoid duplication of side effects.
+ destroyRefinementsOfDeadPrimitive(tearOff);
getterCont.parameters.clear();
replaceSubtree(tearOffInvoke, new InvokeContinuation(getterCont, []));
} else {
@@ -1597,6 +1602,18 @@ class TransformingVisitor extends LeafVisitor {
return false;
}
+ void destroyRefinementsOfDeadPrimitive(Primitive prim) {
+ while (prim.firstRef != null) {
+ Refinement refine = prim.firstRef.parent;
+ destroyRefinementsOfDeadPrimitive(refine);
+ LetPrim letPrim = refine.parent;
+ InteriorNode parent = letPrim.parent;
+ parent.body = letPrim.body;
+ letPrim.body.parent = parent;
+ prim.firstRef.unlink();
+ }
+ }
+
/// Inlines a single-use closure if it leaves the closure object with only
/// field accesses. This is optimized later by [ScalarReplacer].
bool specializeSingleUseClosureCall(InvokeMethod node) {
@@ -1692,7 +1709,7 @@ class TransformingVisitor extends LeafVisitor {
node.receiverIsNotNull = receiver.isDefinitelyNotNull;
if (isInterceptedSelector(node.selector) &&
- node.receiver.definition == node.arguments[0].definition) {
+ node.receiver.definition.sameValue(node.arguments[0].definition)) {
// The receiver and first argument are the same; that means we already
// determined in visitInterceptor that we are targeting a non-interceptor.
@@ -1986,7 +2003,7 @@ class TransformingVisitor extends LeafVisitor {
if (parent is LetPrim && parent.primitive is ApplyBuiltinMethod) {
ApplyBuiltinMethod previous = parent.primitive;
if (previous.method == BuiltinMethod.Push &&
- previous.receiver.definition == node.receiver.definition) {
+ previous.receiver.definition.sameValue(node.receiver.definition)) {
// We found two consecutive pushes.
// Move all arguments from the first push onto the second one.
List<Reference<Primitive>> arguments = previous.arguments;
@@ -2120,6 +2137,8 @@ class TypePropagationVisitor implements Visitor {
JavaScriptBackend get backend => typeSystem.backend;
+ World get classWorld => typeSystem.classWorld;
+
AbstractValue get nothing => lattice.nothing;
AbstractValue nonConstant([TypeMask type]) => lattice.nonConstant(type);
@@ -2560,9 +2579,15 @@ class TypePropagationVisitor implements Visitor {
break; // Cast fails. Continuation should remain unreachable.
case AbstractBool.Maybe:
- // TODO(asgerf): Narrow type of output to those that survive the cast.
setReachable(cont);
- setValue(cont.parameters.single, input);
+ TypeMask type = input.type;
+ if (node.type.element is ClassElement) {
+ // Narrow type of output to those that survive the cast.
+ type = type.intersection(
+ new TypeMask.subtype(node.type.element, classWorld),
+ classWorld);
+ }
+ setValue(cont.parameters.single, nonConstant(type));
break;
}
}
@@ -2676,7 +2701,7 @@ class TypePropagationVisitor implements Visitor {
}
@override
- visitTypeExpression(TypeExpression node) {
+ void visitTypeExpression(TypeExpression node) {
// TODO(karlklose): come up with a type marker for JS entities or switch to
// real constants of type [Type].
setValue(node, nonConstant());
@@ -2688,7 +2713,7 @@ class TypePropagationVisitor implements Visitor {
}
@override
- visitForeignCode(ForeignCode node) {
+ void visitForeignCode(ForeignCode node) {
if (node.continuation != null) {
Continuation continuation = node.continuation.definition;
setReachable(continuation);
@@ -2715,10 +2740,23 @@ class TypePropagationVisitor implements Visitor {
}
@override
- visitAwait(Await node) {
+ void visitAwait(Await node) {
Continuation continuation = node.continuation.definition;
setReachable(continuation);
}
+
+ @override
+ void visitRefinement(Refinement node) {
+ AbstractValue value = getValue(node.value.definition);
+ if (value.isNothing || typeSystem.areDisjoint(value.type, node.type)) {
+ setValue(node, nothing);
+ } else if (value.isConstant) {
+ setValue(node, value);
+ } else {
+ setValue(node,
+ nonConstant(value.type.intersection(node.type, classWorld)));
+ }
+ }
}
/// Represents the abstract value of a primitive value at some point in the
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698