Skip to content

Commit

Permalink
VM: Fix bug in type propagation at conditionals.
Browse files Browse the repository at this point in the history
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 .
  • Loading branch information
fsc8000 committed Dec 3, 2015
1 parent d94b68c commit dff13be
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 58 deletions.
57 changes: 0 additions & 57 deletions runtime/vm/flow_graph_type_propagator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@ void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
}
}

HandleBranchOnStrictCompare(block);

for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
PropagateRecursive(block->dominated_blocks()[i]);
}
Expand All @@ -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) {
for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
types_[rollback_[i].index()] = rollback_[i].type();
Expand Down
1 change: 0 additions & 1 deletion runtime/vm/flow_graph_type_propagator.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
void Propagate();

void PropagateRecursive(BlockEntryInstr* block);
void HandleBranchOnStrictCompare(BlockEntryInstr* block);

void RollbackTo(intptr_t rollback_point);

Expand Down
56 changes: 56 additions & 0 deletions tests/language/vm/type_propagation_test.dart
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit dff13be

Please sign in to comment.