diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index 7e32c7b1dbe..5f3bd7e221c 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc @@ -293,6 +293,9 @@ void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { block->AsTargetEntry()->adjust_edge_weight(scale_factor); } Instruction* instr = block; + if (block->env() != NULL) { + call_->env()->DeepCopyToOuter(callee_graph->isolate(), block); + } for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { instr = it.Current(); // TODO(zerny): Avoid creating unnecessary environments. Note that some @@ -358,7 +361,6 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, caller_graph_->set_max_block_id(join_id); JoinEntryInstr* join = new(I) JoinEntryInstr(join_id, try_index); - join->InheritDeoptTargetAfter(isolate(), call_); // The dominator set of the join is the intersection of the dominator // sets of all the predecessors. If we keep the dominator sets ordered @@ -430,6 +432,7 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, phi->SetInputAt(i, ValueAt(i)); } join->InsertPhi(phi); + join->InheritDeoptTargetAfter(caller_graph_, call_, phi); return phi; } else { // In the case that the result is unused, remove the return value uses @@ -437,6 +440,7 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, for (intptr_t i = 0; i < num_exits; ++i) { ReturnAt(i)->UnuseAllInputs(); } + join->InheritDeoptTargetAfter(caller_graph_, call_, NULL); return NULL; } } @@ -462,7 +466,7 @@ void InlineExitCollector::ReplaceCall(TargetEntryInstr* callee_entry) { TargetEntryInstr* false_block = new(I) TargetEntryInstr(caller_graph_->allocate_block_id(), call_block->try_index()); - false_block->InheritDeoptTargetAfter(isolate(), call_); + false_block->InheritDeoptTargetAfter(caller_graph_, call_, NULL); false_block->LinkTo(call_->next()); call_block->ReplaceAsPredecessorWith(false_block); diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc index 207582a538a..5bbfc9a9c9d 100644 --- a/runtime/vm/flow_graph_inliner.cc +++ b/runtime/vm/flow_graph_inliner.cc @@ -1653,7 +1653,10 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { ReturnInstr* fallback_return = new ReturnInstr(call_->instance_call()->token_pos(), new Value(fallback_call)); - fallback_return->InheritDeoptTargetAfter(isolate(), call_); + fallback_return->InheritDeoptTargetAfter( + owner_->caller_graph(), + call_, + fallback_call); AppendInstruction(AppendInstruction(cursor, fallback_call), fallback_return); exit_collector_->AddExit(fallback_return); diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index 8476a7c8491..a4d70faf9b5 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -739,11 +739,17 @@ void Instruction::UnuseAllInputs() { } -void Instruction::InheritDeoptTargetAfter(Isolate* isolate, - Instruction* other) { - ASSERT(other->env() != NULL); - deopt_id_ = Isolate::ToDeoptAfter(other->deopt_id_); - other->env()->DeepCopyTo(isolate, this); +void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, + Definition* call, + Definition* result) { + ASSERT(call->env() != NULL); + deopt_id_ = Isolate::ToDeoptAfter(call->deopt_id_); + call->env()->DeepCopyAfterTo(flow_graph->isolate(), + this, + call->ArgumentCount(), + flow_graph->constant_dead(), + result != NULL ? result + : flow_graph->constant_dead()); env()->set_deopt_id(deopt_id_); } @@ -3027,6 +3033,29 @@ void Environment::DeepCopyTo(Isolate* isolate, Instruction* instr) const { } +void Environment::DeepCopyAfterTo(Isolate* isolate, + Instruction* instr, + intptr_t argc, + Definition* dead, + Definition* result) const { + for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { + it.CurrentValue()->RemoveFromUseList(); + } + + Environment* copy = DeepCopy(isolate, values_.length() - argc); + for (intptr_t i = 0; i < argc; i++) { + copy->values_.Add(new(isolate) Value(dead)); + } + copy->values_.Add(new(isolate) Value(result)); + + instr->SetEnvironment(copy); + for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { + Value* value = it.CurrentValue(); + value->definition()->AddEnvUse(value); + } +} + + // Copies the environment as outer on an inlined instruction and updates the // environment use lists. void Environment::DeepCopyToOuter(Isolate* isolate, Instruction* instr) const { diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index 5d5b537ff34..02812cb6bf6 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -840,7 +840,9 @@ FOR_EACH_ABSTRACT_INSTRUCTION(INSTRUCTION_TYPE_CHECK) return false; } - void InheritDeoptTargetAfter(Isolate* isolate, Instruction* other); + void InheritDeoptTargetAfter(FlowGraph* flow_graph, + Definition* call, + Definition* result); virtual bool MayThrow() const = 0; @@ -7910,6 +7912,12 @@ class Environment : public ZoneAllocated { void DeepCopyTo(Isolate* isolate, Instruction* instr) const; void DeepCopyToOuter(Isolate* isolate, Instruction* instr) const; + void DeepCopyAfterTo(Isolate* isolate, + Instruction* instr, + intptr_t argc, + Definition* dead, + Definition* result) const; + void PrintTo(BufferFormatter* f) const; const char* ToCString() const;