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

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

Issue 1220123004: dart2js cps: Ensure definitions are specialized before their uses. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebase Created 5 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 | « pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 49e3ba624a6904119ae90558517762ceeae7a80a..091ca5368398ae3efef88918d6842c78d09171a5 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -174,6 +174,15 @@ class TypeMaskSystem {
// TODO(asgerf): Support function types, and what else might be missing.
return AbstractBool.Maybe;
}
+
+ /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
+ /// the empty string, or null.
+ AbstractBool boolify(TypeMask type) {
+ if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
+ return AbstractBool.True;
+ }
+ return AbstractBool.Maybe;
+ }
}
class ConstantPropagationLattice {
@@ -371,6 +380,30 @@ class ConstantPropagationLattice {
}
}
+ bool isEmptyString(ConstantValue value) {
+ return value is StringConstantValue && value.primitiveValue.isEmpty;
+ }
+
+ /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
+ /// the empty string, or null.
+ AbstractBool boolify(AbstractValue value) {
+ if (value.isNothing) return AbstractBool.Nothing;
+ if (value.isConstant) {
+ ConstantValue constantValue = value.constant;
+ if (constantValue.isFalse ||
+ constantValue.isNull ||
+ constantValue.isZero ||
+ constantValue.isMinusZero ||
+ constantValue.isNaN ||
+ isEmptyString(constantValue)) {
+ return AbstractBool.False;
+ } else {
+ return AbstractBool.True;
+ }
+ }
+ return typeSystem.boolify(value.type);
+ }
+
/// The possible return types of a method that may be targeted by
/// [typedSelector]. If the given selector is not a [TypedSelector], any
/// reachable method matching the selector may be targeted.
@@ -560,44 +593,49 @@ class TransformingVisitor extends RecursiveVisitor {
//
// (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
void visitBranch(Branch node) {
- bool trueReachable = reachable.contains(node.trueContinuation.definition);
- bool falseReachable = reachable.contains(node.falseContinuation.definition);
- bool bothReachable = (trueReachable && falseReachable);
- bool noneReachable = !(trueReachable || falseReachable);
-
- if (bothReachable || noneReachable) {
- // Nothing to do, shrinking reductions take care of the unreachable case.
- super.visitBranch(node);
+ Continuation trueCont = node.trueContinuation.definition;
+ Continuation falseCont = node.falseContinuation.definition;
+ IsTrue conditionNode = node.condition;
+ Primitive condition = conditionNode.value.definition;
+
+ AbstractValue conditionValue = getValue(condition);
+ AbstractBool boolifiedValue = lattice.boolify(conditionValue);
+
+ if (boolifiedValue == AbstractBool.True) {
+ InvokeContinuation invoke = new InvokeContinuation(trueCont, []);
+ replaceSubtree(node, invoke);
+ visitInvokeContinuation(invoke);
+ return;
+ }
+ if (boolifiedValue == AbstractBool.False) {
+ InvokeContinuation invoke = new InvokeContinuation(falseCont, []);
+ replaceSubtree(node, invoke);
+ visitInvokeContinuation(invoke);
return;
}
- Continuation successor = (trueReachable) ?
- node.trueContinuation.definition : node.falseContinuation.definition;
-
- // Replace the branch by a continuation invocation.
-
- assert(successor.parameters.isEmpty);
- InvokeContinuation invoke =
- new InvokeContinuation(successor, <Primitive>[]);
-
- replaceSubtree(node, invoke);
- visitInvokeContinuation(invoke);
- }
-
- /// True if the given reference is a use that converts its value to a boolean
- /// and only uses the coerced value.
- bool isBoolifyingUse(Reference<Primitive> ref) {
- Node use = ref.parent;
- return use is IsTrue ||
- use is ApplyBuiltinOperator && use.operator == BuiltinOperator.IsFalsy;
- }
-
- /// True if all uses of [prim] only use its value after boolean conversion.
- bool isAlwaysBoolified(Primitive prim) {
- for (Reference ref = prim.firstRef; ref != null; ref = ref.next) {
- if (!isBoolifyingUse(ref)) return false;
+ if (condition is ApplyBuiltinOperator &&
+ condition.operator == BuiltinOperator.LooseEq) {
+ Primitive leftArg = condition.arguments[0].definition;
+ Primitive rightArg = condition.arguments[1].definition;
+ AbstractValue left = getValue(leftArg);
+ AbstractValue right = getValue(rightArg);
+ if (right.isNullConstant &&
+ lattice.isDefinitelyNotNumStringBool(left)) {
+ // Rewrite:
+ // if (x == null) S1 else S2
+ // =>
+ // if (x) S2 else S1 (note the swapped branches)
+ Branch branch = new Branch(new IsTrue(leftArg), falseCont, trueCont);
+ replaceSubtree(node, branch);
+ return;
+ } else if (left.isNullConstant &&
+ lattice.isDefinitelyNotNumStringBool(right)) {
+ Branch branch = new Branch(new IsTrue(rightArg), falseCont, trueCont);
+ replaceSubtree(node, branch);
+ return;
+ }
}
- return true;
}
/// Replaces [node] with a more specialized instruction, if possible.
@@ -615,15 +653,6 @@ class TransformingVisitor extends RecursiveVisitor {
visitLetPrim(let);
return true; // So returning early is more convenient.
}
- bool replaceWithUnary(BuiltinOperator operator,
- Primitive argument) {
- Primitive prim =
- new ApplyBuiltinOperator(operator, <Primitive>[argument]);
- LetPrim let = makeLetPrimInvoke(prim, cont);
- replaceSubtree(node, let);
- visitLetPrim(let);
- return true;
- }
if (node.selector.isOperator && node.arguments.length == 2) {
// The operators we specialize are are intercepted calls, so the operands
@@ -637,19 +666,6 @@ class TransformingVisitor extends RecursiveVisitor {
// Equality is special due to its treatment of null values and the
// fact that Dart-null corresponds to both JS-null and JS-undefined.
// Please see documentation for IsFalsy, StrictEq, and LooseEq.
- bool isBoolified = isAlwaysBoolified(cont.parameters.single);
- // Comparison with null constants.
- if (isBoolified &&
- right.isNullConstant &&
- lattice.isDefinitelyNotNumStringBool(left)) {
- // TODO(asgerf): This is shorter but might confuse te VM? Evaluate.
- return replaceWithUnary(BuiltinOperator.IsFalsy, leftArg);
- }
- if (isBoolified &&
- left.isNullConstant &&
- lattice.isDefinitelyNotNumStringBool(right)) {
- return replaceWithUnary(BuiltinOperator.IsFalsy, rightArg);
- }
if (left.isNullConstant || right.isNullConstant) {
return replaceWithBinary(BuiltinOperator.LooseEq, leftArg, rightArg);
}
@@ -1089,6 +1105,41 @@ class TransformingVisitor extends RecursiveVisitor {
}
visit(node.body);
}
+
+ void visitLetCont(LetCont node) {
+ // Visit body before continuations to ensure more information is available
+ // about the parameters. In particular, if this is a call continuation, its
+ // invocation should be specialized before the body is processed, because
+ // we specialize definitions before their uses.
+ visit(node.body);
+ node.continuations.forEach(visit);
+ }
+
+ void visitInvokeContinuation(InvokeContinuation node) {
+ // Inline the single-use continuations. These are often introduced when
+ // specializing an invocation node. These would also be inlined by a later
+ // pass, but doing it here helps simplify pattern matching code, since the
+ // effective definition of a primitive can then be found without going
+ // through redundant InvokeContinuations.
+ Continuation cont = node.continuation.definition;
+ if (cont.hasExactlyOneUse &&
+ !cont.isReturnContinuation &&
+ !cont.isRecursive &&
+ !node.isEscapingTry) {
+ for (int i = 0; i < node.arguments.length; ++i) {
+ node.arguments[i].definition.substituteFor(cont.parameters[i]);
+ node.arguments[i].unlink();
+ }
+ node.continuation.unlink();
+ InteriorNode parent = node.parent;
+ Expression body = cont.body;
+ parent.body = body;
+ body.parent = parent;
+ cont.body = new Unreachable();
+ cont.body.parent = cont;
+ visit(body);
+ }
+ }
}
/**
@@ -1559,7 +1610,12 @@ class TypePropagationVisitor implements Visitor {
void visitConstant(Constant node) {
ConstantValue value = node.value;
- setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
+ if (value.isDummy || !value.isConstant) {
+ // TODO(asgerf): Explain how this happens and why we don't want them.
+ setValue(node, nonConstant(typeSystem.getTypeOf(value)));
+ } else {
+ setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
+ }
}
void visitCreateFunction(CreateFunction node) {
@@ -1722,6 +1778,7 @@ class AbstractValue {
AbstractValue._internal(this.kind, this.constant, this.type) {
assert(kind != CONSTANT || constant != null);
+ assert(constant is! SyntheticConstantValue);
}
AbstractValue.nothing()
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart ('k') | pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698