VM: Fix bug in type propagation at conditionals.
Propagating type/cid at conditional branches is not possible because it may cause invalid code motion. For this to be safe we need to explicitly represent the dependency between checks eliminated in a branch and the condition that constrains the type/cid. BUG= R=vegorov@google.com Review URL: https://codereview.chromium.org/1491373005 .
This commit is contained in:
@@ -149,8 +149,6 @@ void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleBranchOnStrictCompare(block);
|
|
||||||
|
|
||||||
for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
|
for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
|
||||||
PropagateRecursive(block->dominated_blocks()[i]);
|
PropagateRecursive(block->dominated_blocks()[i]);
|
||||||
}
|
}
|
||||||
@@ -159,61 +157,6 @@ void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FlowGraphTypePropagator::HandleBranchOnStrictCompare(
|
|
||||||
BlockEntryInstr* block) {
|
|
||||||
BranchInstr* branch = block->last_instruction()->AsBranch();
|
|
||||||
if (branch == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StrictCompareInstr* compare = branch->comparison()->AsStrictCompare();
|
|
||||||
if ((compare == NULL) || !compare->right()->BindsToConstant()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const intptr_t rollback_point = rollback_.length();
|
|
||||||
|
|
||||||
Definition* defn = compare->left()->definition();
|
|
||||||
const Object& right = compare->right()->BoundConstant();
|
|
||||||
intptr_t cid = right.GetClassId();
|
|
||||||
|
|
||||||
if (defn->IsLoadClassId() && right.IsSmi()) {
|
|
||||||
defn = defn->AsLoadClassId()->object()->definition();
|
|
||||||
cid = Smi::Cast(right).Value();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CheckClassInstr::IsImmutableClassId(cid)) {
|
|
||||||
if ((cid == kOneByteStringCid) || (cid == kTwoByteStringCid)) {
|
|
||||||
SetTypeOf(defn, ZoneCompileType::Wrap(CompileType::String()));
|
|
||||||
PropagateRecursive((compare->kind() == Token::kEQ_STRICT) ?
|
|
||||||
branch->true_successor() : branch->false_successor());
|
|
||||||
RollbackTo(rollback_point);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compare->kind() == Token::kEQ_STRICT) {
|
|
||||||
if (cid == kNullCid) {
|
|
||||||
branch->set_constrained_type(MarkNonNullable(defn));
|
|
||||||
PropagateRecursive(branch->false_successor());
|
|
||||||
}
|
|
||||||
|
|
||||||
SetCid(defn, cid);
|
|
||||||
PropagateRecursive(branch->true_successor());
|
|
||||||
} else if (compare->kind() == Token::kNE_STRICT) {
|
|
||||||
if (cid == kNullCid) {
|
|
||||||
branch->set_constrained_type(MarkNonNullable(defn));
|
|
||||||
PropagateRecursive(branch->true_successor());
|
|
||||||
}
|
|
||||||
|
|
||||||
SetCid(defn, cid);
|
|
||||||
PropagateRecursive(branch->false_successor());
|
|
||||||
}
|
|
||||||
|
|
||||||
RollbackTo(rollback_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
|
void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
|
||||||
for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
|
for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
|
||||||
types_[rollback_[i].index()] = rollback_[i].type();
|
types_[rollback_[i].index()] = rollback_[i].type();
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
|
|||||||
void Propagate();
|
void Propagate();
|
||||||
|
|
||||||
void PropagateRecursive(BlockEntryInstr* block);
|
void PropagateRecursive(BlockEntryInstr* block);
|
||||||
void HandleBranchOnStrictCompare(BlockEntryInstr* block);
|
|
||||||
|
|
||||||
void RollbackTo(intptr_t rollback_point);
|
void RollbackTo(intptr_t rollback_point);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2015, 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.
|
||||||
|
// VMOptions=--optimization-counter-threshold=1000 --max-polymorphic-checks=1
|
||||||
|
|
||||||
|
// Test correct loop invariant code motion and type propagation from is-checks
|
||||||
|
// and null-comparisons.
|
||||||
|
|
||||||
|
class B {
|
||||||
|
var b;
|
||||||
|
B(this.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
final f0;
|
||||||
|
|
||||||
|
final a;
|
||||||
|
C() : a = new B(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foo(x) {
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
i + i;
|
||||||
|
i + i;
|
||||||
|
if (x is C) {
|
||||||
|
x.a.b < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Y { var f = null; }
|
||||||
|
|
||||||
|
bar(y) {
|
||||||
|
var x = y.f;
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
if (x != null) {
|
||||||
|
x.a.b < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
main () {
|
||||||
|
var o = new Y();
|
||||||
|
o.f = new C();
|
||||||
|
bar(o);
|
||||||
|
o.f = null;
|
||||||
|
bar(o);
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; i++) bar(o);
|
||||||
|
|
||||||
|
foo(new C());
|
||||||
|
foo(0);
|
||||||
|
|
||||||
|
for (var i = 0; i < 1000; i++) foo(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user