| Index: runtime/vm/intermediate_language.cc
|
| diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
|
| index 43c04212b9f5851d88d8bfa2e2acaf8113c87df3..616c21418869b43a25bf8f33f994d79c64f1f910 100644
|
| --- a/runtime/vm/intermediate_language.cc
|
| +++ b/runtime/vm/intermediate_language.cc
|
| @@ -318,6 +318,25 @@ FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
|
| #undef DEFINE_ACCEPT
|
|
|
|
|
| +void Instruction::SetEnvironment(Environment* deopt_env) {
|
| + intptr_t use_index = 0;
|
| + for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) {
|
| + Value* use = it.CurrentValue();
|
| + use->set_instruction(this);
|
| + use->set_use_index(use_index++);
|
| + }
|
| + env_ = deopt_env;
|
| +}
|
| +
|
| +
|
| +void Instruction::RemoveEnvironment() {
|
| + for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) {
|
| + it.CurrentValue()->RemoveFromUseList();
|
| + }
|
| + env_ = NULL;
|
| +}
|
| +
|
| +
|
| Instruction* Instruction::RemoveFromGraph(bool return_previous) {
|
| ASSERT(!IsBlockEntry());
|
| ASSERT(!IsControl());
|
| @@ -326,29 +345,23 @@ Instruction* Instruction::RemoveFromGraph(bool return_previous) {
|
| ASSERT(!IsReThrow());
|
| ASSERT(!IsGoto());
|
| ASSERT(previous() != NULL);
|
| + // We cannot assert that the instruction, if it is a definition, has no
|
| + // uses. This function is used to remove instructions from the graph and
|
| + // reinsert them elsewhere (e.g., hoisting).
|
| Instruction* prev_instr = previous();
|
| Instruction* next_instr = next();
|
| ASSERT(next_instr != NULL);
|
| ASSERT(!next_instr->IsBlockEntry());
|
| prev_instr->LinkTo(next_instr);
|
| - // Reset successor and previous instruction to indicate
|
| - // that the instruction is removed from the graph.
|
| + UnuseAllInputs();
|
| + // Reset the successor and previous instruction to indicate that the
|
| + // instruction is removed from the graph.
|
| set_previous(NULL);
|
| set_next(NULL);
|
| return return_previous ? prev_instr : next_instr;
|
| }
|
|
|
|
|
| -void Instruction::InsertBefore(Instruction* next) {
|
| - ASSERT(previous_ == NULL);
|
| - ASSERT(next_ == NULL);
|
| - next_ = next;
|
| - previous_ = next->previous_;
|
| - next->previous_ = this;
|
| - previous_->next_ = this;
|
| -}
|
| -
|
| -
|
| void Instruction::InsertAfter(Instruction* prev) {
|
| ASSERT(previous_ == NULL);
|
| ASSERT(next_ == NULL);
|
| @@ -356,6 +369,13 @@ void Instruction::InsertAfter(Instruction* prev) {
|
| next_ = prev->next_;
|
| next_->previous_ = this;
|
| previous_->next_ = this;
|
| +
|
| + // Update def-use chains whenever instructions are added to the graph
|
| + // after initial graph construction.
|
| + for (intptr_t i = InputCount() - 1; i >= 0; --i) {
|
| + Value* input = InputAt(i);
|
| + input->definition()->AddInputUse(input);
|
| + }
|
| }
|
|
|
|
|
| @@ -472,7 +492,6 @@ void Value::RemoveFromUseList() {
|
| if (next != NULL) next->set_previous_use(prev);
|
| }
|
|
|
| - set_definition(NULL);
|
| set_previous_use(NULL);
|
| set_next_use(NULL);
|
| }
|
| @@ -537,23 +556,15 @@ void Definition::ReplaceWith(Definition* other,
|
| }
|
| // Take other's environment from this definition.
|
| ASSERT(other->env() == NULL);
|
| - intptr_t use_index = 0;
|
| - for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) {
|
| - Value* use = it.CurrentValue();
|
| - use->set_instruction(other);
|
| - use->set_use_index(use_index++);
|
| - }
|
| - other->set_env(env());
|
| - set_env(NULL);
|
| + other->SetEnvironment(env());
|
| + env_ = NULL;
|
| // Replace all uses of this definition with other.
|
| ReplaceUsesWith(other);
|
| // Reuse this instruction's SSA name for other.
|
| ASSERT(!other->HasSSATemp());
|
| if (HasSSATemp()) other->set_ssa_temp_index(ssa_temp_index());
|
| - // Remove this definition's input uses.
|
| - UnuseAllInputs();
|
|
|
| - // Finally remove this definition from the graph.
|
| + // Finally insert the other definition in place of this one in the graph.
|
| previous()->LinkTo(other);
|
| if ((iterator != NULL) && (this == iterator->Current())) {
|
| // Remove through the iterator.
|
| @@ -561,6 +572,8 @@ void Definition::ReplaceWith(Definition* other,
|
| iterator->RemoveCurrentFromGraph();
|
| } else {
|
| other->LinkTo(next());
|
| + // Remove this definition's input uses.
|
| + UnuseAllInputs();
|
| }
|
| set_previous(NULL);
|
| set_next(NULL);
|
| @@ -583,23 +596,18 @@ void BranchInstr::RawSetInputAt(intptr_t i, Value* value) {
|
| // A misleadingly named function for use in template functions that replace
|
| // both definitions with definitions and branch comparisons with
|
| // comparisons. In the branch case, leave the branch intact and replace its
|
| -// comparison with another comparison.
|
| +// comparison with a new comparison not currently in the graph.
|
| void BranchInstr::ReplaceWith(ComparisonInstr* other,
|
| ForwardInstructionIterator* ignored) {
|
| - // Record the new comparison's input uses.
|
| - for (intptr_t i = other->InputCount() - 1; i >= 0; --i) {
|
| - Value* input = other->InputAt(i);
|
| - input->definition()->AddInputUse(input);
|
| - }
|
| SetComparison(other);
|
| }
|
|
|
|
|
| void BranchInstr::SetComparison(ComparisonInstr* comp) {
|
| - // The new comparison's input uses are already recorded in their
|
| - // definition's use lists.
|
| for (intptr_t i = comp->InputCount() - 1; i >= 0; --i) {
|
| - comp->InputAt(i)->set_instruction(this);
|
| + Value* input = comp->InputAt(i);
|
| + input->definition()->AddInputUse(input);
|
| + input->set_instruction(this);
|
| }
|
| // There should be no need to copy or unuse an environment.
|
| ASSERT(comparison()->env() == NULL);
|
| @@ -1174,9 +1182,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
|
| // It is ok to insert instructions before the current during
|
| // forward iteration.
|
| optimizer->InsertBefore(this, null_constant, NULL, Definition::kValue);
|
| - instantiator_type_arguments()->RemoveFromUseList();
|
| - instantiator_type_arguments()->set_definition(null_constant);
|
| - null_constant->AddInputUse(instantiator_type_arguments());
|
| + instantiator_type_arguments()->BindTo(null_constant);
|
| }
|
| return this;
|
| }
|
| @@ -1205,9 +1211,6 @@ Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
|
| (comp->input_use_list()->next_use() == NULL) &&
|
| (comp->env_use_list() == NULL)) {
|
| comp->RemoveFromGraph();
|
| - // It is safe to pass a NULL iterator because we're replacing the
|
| - // comparison wrapped in a BranchInstr which does not modify the
|
| - // linked list of instructions.
|
| SetComparison(comp);
|
| if (FLAG_trace_optimization) {
|
| OS::Print("Merging comparison v%"Pd"\n", comp->ssa_temp_index());
|
| @@ -1541,14 +1544,11 @@ void Environment::DeepCopyTo(Instruction* instr) const {
|
| }
|
|
|
| Environment* copy = DeepCopy();
|
| - intptr_t use_index = 0;
|
| + instr->SetEnvironment(copy);
|
| for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
|
| Value* value = it.CurrentValue();
|
| - value->set_instruction(instr);
|
| - value->set_use_index(use_index++);
|
| value->definition()->AddEnvUse(value);
|
| }
|
| - instr->set_env(copy);
|
| }
|
|
|
|
|
| @@ -1560,6 +1560,7 @@ void Environment::DeepCopyToOuter(Instruction* instr) const {
|
| ASSERT(instr->env()->outer() == NULL);
|
| intptr_t argument_count = instr->env()->fixed_parameter_count();
|
| Environment* copy = DeepCopy(values_.length() - argument_count);
|
| + instr->env()->outer_ = copy;
|
| intptr_t use_index = instr->env()->Length(); // Start index after inner.
|
| for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
|
| Value* value = it.CurrentValue();
|
| @@ -1567,7 +1568,6 @@ void Environment::DeepCopyToOuter(Instruction* instr) const {
|
| value->set_use_index(use_index++);
|
| value->definition()->AddEnvUse(value);
|
| }
|
| - instr->env()->outer_ = copy;
|
| }
|
|
|
|
|
|
|