mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 01:28:21 +00:00
Strengthen type assertions post-dominated by checks during type propagation.
If a type assertion for a value is post-dominated by a class or smi check over the same value then raise the check over the assertion. This allows to eliminate type assertions in the cases like: AssertAssignable(x, int) CheckSmi(x) Currently post-domination is computed within a single block because post-dominators are not available. R=fschneider@google.com BUG= Review URL: https://codereview.chromium.org//12317013 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18777 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
8d24d2b98a
commit
bb0c073ff9
|
@ -24,6 +24,7 @@ DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
|
|||
DECLARE_FLAG(int, optimization_counter_threshold);
|
||||
DECLARE_FLAG(bool, print_ast);
|
||||
DECLARE_FLAG(bool, print_scopes);
|
||||
DECLARE_FLAG(bool, enable_type_checks);
|
||||
DECLARE_FLAG(bool, eliminate_type_checks);
|
||||
|
||||
|
||||
|
@ -624,6 +625,12 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
|
|||
|
||||
void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
|
||||
if (!is_optimizing()) {
|
||||
if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
|
||||
AssertAssignableInstr* assert = instr->AsAssertAssignable();
|
||||
AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
|
||||
assert->deopt_id(),
|
||||
assert->token_pos());
|
||||
}
|
||||
AllocateRegistersLocally(instr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
|
|||
DECLARE_FLAG(int, optimization_counter_threshold);
|
||||
DECLARE_FLAG(bool, print_ast);
|
||||
DECLARE_FLAG(bool, print_scopes);
|
||||
DECLARE_FLAG(bool, enable_type_checks);
|
||||
DECLARE_FLAG(bool, eliminate_type_checks);
|
||||
|
||||
|
||||
|
@ -620,6 +621,12 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
|
|||
|
||||
void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
|
||||
if (!is_optimizing()) {
|
||||
if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
|
||||
AssertAssignableInstr* assert = instr->AsAssertAssignable();
|
||||
AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
|
||||
assert->deopt_id(),
|
||||
assert->token_pos());
|
||||
}
|
||||
AllocateRegistersLocally(instr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,22 @@ FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
|
|||
: FlowGraphVisitor(flow_graph->reverse_postorder()),
|
||||
flow_graph_(flow_graph),
|
||||
types_(flow_graph->current_ssa_temp_index()),
|
||||
in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())) {
|
||||
in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())),
|
||||
asserts_(NULL),
|
||||
collected_asserts_(NULL) {
|
||||
for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
|
||||
types_.Add(NULL);
|
||||
}
|
||||
|
||||
if (FLAG_enable_type_checks) {
|
||||
asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
|
||||
flow_graph->current_ssa_temp_index());
|
||||
for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
|
||||
asserts_->Add(NULL);
|
||||
}
|
||||
|
||||
collected_asserts_ = new ZoneGrowableArray<intptr_t>(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,6 +94,10 @@ void FlowGraphTypePropagator::Propagate() {
|
|||
void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
|
||||
const intptr_t rollback_point = rollback_.length();
|
||||
|
||||
if (FLAG_enable_type_checks) {
|
||||
StrengthenAsserts(block);
|
||||
}
|
||||
|
||||
block->Accept(this);
|
||||
|
||||
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
|
||||
|
@ -203,6 +219,86 @@ Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
|
|||
}
|
||||
|
||||
|
||||
// Unwrap all assert assignable and get a real definition of the value.
|
||||
static Definition* UnwrapAsserts(Definition* defn) {
|
||||
while (defn->IsAssertAssignable()) {
|
||||
defn = defn->AsAssertAssignable()->value()->definition();
|
||||
}
|
||||
return defn;
|
||||
}
|
||||
|
||||
|
||||
// In the given block strengthen type assertions by hoisting first class or smi
|
||||
// check over the same value up to the point before the assertion. This allows
|
||||
// to eliminate type assertions that are postdominated by class or smi checks as
|
||||
// these checks are strongly stricter than type assertions.
|
||||
void FlowGraphTypePropagator::StrengthenAsserts(BlockEntryInstr* block) {
|
||||
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
|
||||
Instruction* instr = it.Current();
|
||||
|
||||
if (instr->IsCheckSmi() || instr->IsCheckClass()) {
|
||||
StrengthenAssertWith(instr);
|
||||
}
|
||||
|
||||
// If this is the first type assertion checking given value record it.
|
||||
AssertAssignableInstr* assert = instr->AsAssertAssignable();
|
||||
if (assert != NULL) {
|
||||
Definition* defn = UnwrapAsserts(assert->value()->definition());
|
||||
if ((*asserts_)[defn->ssa_temp_index()] == NULL) {
|
||||
(*asserts_)[defn->ssa_temp_index()] = assert;
|
||||
collected_asserts_->Add(defn->ssa_temp_index());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (intptr_t i = 0; i < collected_asserts_->length(); i++) {
|
||||
(*asserts_)[(*collected_asserts_)[i]] = NULL;
|
||||
}
|
||||
|
||||
collected_asserts_->TruncateTo(0);
|
||||
}
|
||||
|
||||
|
||||
void FlowGraphTypePropagator::StrengthenAssertWith(Instruction* check) {
|
||||
// Marker that is used to mark values that already had type assertion
|
||||
// strengthened.
|
||||
AssertAssignableInstr* kStrengthenedAssertMarker =
|
||||
reinterpret_cast<AssertAssignableInstr*>(-1);
|
||||
|
||||
Definition* defn = UnwrapAsserts(check->InputAt(0)->definition());
|
||||
|
||||
AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()];
|
||||
if ((assert == NULL) || (assert == kStrengthenedAssertMarker)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Instruction* check_clone = NULL;
|
||||
if (check->IsCheckSmi()) {
|
||||
check_clone =
|
||||
new CheckSmiInstr(assert->value()->Copy(),
|
||||
assert->env()->deopt_id());
|
||||
} else {
|
||||
ASSERT(check->IsCheckClass());
|
||||
check_clone =
|
||||
new CheckClassInstr(assert->value()->Copy(),
|
||||
assert->env()->deopt_id(),
|
||||
check->AsCheckClass()->unary_checks());
|
||||
}
|
||||
ASSERT(check_clone != NULL);
|
||||
ASSERT(assert->deopt_id() == assert->env()->deopt_id());
|
||||
|
||||
Value* use = check_clone->InputAt(0);
|
||||
use->set_instruction(check_clone);
|
||||
use->set_use_index(0);
|
||||
use->definition()->AddInputUse(use);
|
||||
|
||||
assert->env()->DeepCopyTo(check_clone);
|
||||
check_clone->InsertBefore(assert);
|
||||
|
||||
(*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker;
|
||||
}
|
||||
|
||||
|
||||
void CompileType::Union(CompileType* other) {
|
||||
if (other->IsNone()) {
|
||||
return;
|
||||
|
|
|
@ -38,6 +38,10 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
|
|||
void AddToWorklist(Definition* defn);
|
||||
Definition* RemoveLastFromWorklist();
|
||||
|
||||
// Type assertion strengthening.
|
||||
void StrengthenAsserts(BlockEntryInstr* block);
|
||||
void StrengthenAssertWith(Instruction* check);
|
||||
|
||||
FlowGraph* flow_graph_;
|
||||
|
||||
// Mapping between SSA values and their current reaching types. Valid
|
||||
|
@ -48,6 +52,9 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
|
|||
GrowableArray<Definition*> worklist_;
|
||||
BitVector* in_worklist_;
|
||||
|
||||
ZoneGrowableArray<AssertAssignableInstr*>* asserts_;
|
||||
ZoneGrowableArray<intptr_t>* collected_asserts_;
|
||||
|
||||
// RollbackEntry is used to track and rollback changed in the types_ array
|
||||
// done during dominator tree traversal.
|
||||
class RollbackEntry {
|
||||
|
|
|
@ -1111,7 +1111,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
|
|||
return value()->definition();
|
||||
}
|
||||
|
||||
// (3) For uninstantiated target types: If the instantiator type arguments
|
||||
// For uninstantiated target types: If the instantiator type arguments
|
||||
// are constant, instantiate the target type here.
|
||||
if (dst_type().IsInstantiated()) return this;
|
||||
|
||||
|
|
Loading…
Reference in a new issue