From bcf2900a262da7da1b0514ff2d2e0fbe22fa5e1c Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 25 May 2017 10:12:19 -0700 Subject: [PATCH] Reapply "Shuffle around deopt id allocation to give the flow graph builder a chance to record other data as they are allocated". - Fix inlining of new List(n) to propogate deopt id. - Fix CreateArrayOpt to check for a Smi length. R=vegorov@google.com Review-Url: https://codereview.chromium.org/2900963008 . --- runtime/vm/aot_optimizer.cc | 9 +- runtime/vm/branch_optimizer.cc | 28 +- runtime/vm/constant_propagator.cc | 13 +- runtime/vm/flow_graph.cc | 3 +- runtime/vm/flow_graph_builder.cc | 327 ++++++++++-------- runtime/vm/flow_graph_builder.h | 5 + runtime/vm/flow_graph_inliner.cc | 159 +++++---- runtime/vm/intermediate_language.cc | 16 +- runtime/vm/intermediate_language.h | 130 +++---- runtime/vm/intermediate_language_test.cc | 10 +- runtime/vm/intrinsifier.cc | 6 +- runtime/vm/jit_optimizer.cc | 9 +- runtime/vm/kernel_binary_flowgraph.cc | 5 +- runtime/vm/kernel_to_il.cc | 93 ++--- runtime/vm/kernel_to_il.h | 6 + runtime/vm/regexp_assembler.cc | 2 +- runtime/vm/regexp_assembler_ir.cc | 72 ++-- runtime/vm/regexp_assembler_ir.h | 4 + runtime/vm/simulator_dbc.cc | 55 +-- .../vm/create_array_instr_deopt2_test.dart | 24 ++ .../vm/create_array_instr_deopt_test.dart | 20 ++ 21 files changed, 582 insertions(+), 414 deletions(-) create mode 100644 tests/language/vm/create_array_instr_deopt2_test.dart create mode 100644 tests/language/vm/create_array_instr_deopt_test.dart diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc index 513936c56eb..3bf995ab509 100644 --- a/runtime/vm/aot_optimizer.cc +++ b/runtime/vm/aot_optimizer.cc @@ -710,7 +710,7 @@ bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, StrictCompareInstr* comp = new (Z) StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, new (Z) Value(left), new (Z) Value(right), - false); // No number check. + /* number_check = */ false, Thread::kNoDeoptId); ReplaceCall(call, comp); return true; } @@ -1441,10 +1441,9 @@ void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { ConstantInstr* cid = flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); - StrictCompareInstr* check_cid = - new (Z) StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, - new (Z) Value(left_cid), new (Z) Value(cid), - false); // No number check. + StrictCompareInstr* check_cid = new (Z) StrictCompareInstr( + call->token_pos(), Token::kEQ_STRICT, new (Z) Value(left_cid), + new (Z) Value(cid), /* number_check = */ false, Thread::kNoDeoptId); ReplaceCall(call, check_cid); return; } diff --git a/runtime/vm/branch_optimizer.cc b/runtime/vm/branch_optimizer.cc index f68bbcaef33..0048b7ed637 100644 --- a/runtime/vm/branch_optimizer.cc +++ b/runtime/vm/branch_optimizer.cc @@ -65,8 +65,8 @@ JoinEntryInstr* BranchSimplifier::ToJoinEntry(Zone* zone, // Convert a target block into a join block. Branches will be duplicated // so the former true and false targets become joins of the control flows // from all the duplicated branches. - JoinEntryInstr* join = - new (zone) JoinEntryInstr(target->block_id(), target->try_index()); + JoinEntryInstr* join = new (zone) JoinEntryInstr( + target->block_id(), target->try_index(), Thread::kNoDeoptId); join->InheritDeoptTarget(zone, target); join->LinkTo(target->next()); join->set_last_instruction(target->last_instruction()); @@ -82,7 +82,8 @@ BranchInstr* BranchSimplifier::CloneBranch(Zone* zone, ComparisonInstr* comparison = branch->comparison(); ComparisonInstr* new_comparison = comparison->CopyWithNewOperands(new_left, new_right); - BranchInstr* new_branch = new (zone) BranchInstr(new_comparison); + BranchInstr* new_branch = + new (zone) BranchInstr(new_comparison, Thread::kNoDeoptId); return new_branch; } @@ -183,20 +184,24 @@ void BranchSimplifier::Simplify(FlowGraph* flow_graph) { // Connect the branch to the true and false joins, via empty target // blocks. - TargetEntryInstr* true_target = new (zone) TargetEntryInstr( - flow_graph->max_block_id() + 1, block->try_index()); + TargetEntryInstr* true_target = + new (zone) TargetEntryInstr(flow_graph->max_block_id() + 1, + block->try_index(), Thread::kNoDeoptId); true_target->InheritDeoptTarget(zone, join_true); - TargetEntryInstr* false_target = new (zone) TargetEntryInstr( - flow_graph->max_block_id() + 2, block->try_index()); + TargetEntryInstr* false_target = + new (zone) TargetEntryInstr(flow_graph->max_block_id() + 2, + block->try_index(), Thread::kNoDeoptId); false_target->InheritDeoptTarget(zone, join_false); flow_graph->set_max_block_id(flow_graph->max_block_id() + 2); *new_branch->true_successor_address() = true_target; *new_branch->false_successor_address() = false_target; - GotoInstr* goto_true = new (zone) GotoInstr(join_true); + GotoInstr* goto_true = + new (zone) GotoInstr(join_true, Thread::kNoDeoptId); goto_true->InheritDeoptTarget(zone, join_true); true_target->LinkTo(goto_true); true_target->set_last_instruction(goto_true); - GotoInstr* goto_false = new (zone) GotoInstr(join_false); + GotoInstr* goto_false = + new (zone) GotoInstr(join_false, Thread::kNoDeoptId); goto_false->InheritDeoptTarget(zone, join_false); false_target->LinkTo(goto_false); false_target->set_last_instruction(goto_false); @@ -295,8 +300,9 @@ void IfConverter::Simplify(FlowGraph* flow_graph) { ComparisonInstr* new_comparison = comparison->CopyWithNewOperands( comparison->left()->Copy(zone), comparison->right()->Copy(zone)); - IfThenElseInstr* if_then_else = new (zone) IfThenElseInstr( - new_comparison, if_true->Copy(zone), if_false->Copy(zone)); + IfThenElseInstr* if_then_else = new (zone) + IfThenElseInstr(new_comparison, if_true->Copy(zone), + if_false->Copy(zone), Thread::kNoDeoptId); flow_graph->InsertBefore(branch, if_then_else, NULL, FlowGraph::kValue); diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc index 2792f822b99..d080aeddd29 100644 --- a/runtime/vm/constant_propagator.cc +++ b/runtime/vm/constant_propagator.cc @@ -1551,7 +1551,8 @@ void ConstantPropagator::EliminateRedundantBranches() { // Drop the comparison, which does not have side effects JoinEntryInstr* join = if_true->AsJoinEntry(); if (join->phis() == NULL) { - GotoInstr* jump = new (Z) GotoInstr(if_true->AsJoinEntry()); + GotoInstr* jump = + new (Z) GotoInstr(if_true->AsJoinEntry(), Thread::kNoDeoptId); jump->InheritDeoptTarget(Z, branch); Instruction* previous = branch->previous(); @@ -1694,16 +1695,16 @@ void ConstantPropagator::Transform() { ASSERT(reachable_->Contains(if_false->preorder_number())); ASSERT(if_false->parallel_move() == NULL); ASSERT(if_false->loop_info() == NULL); - join = - new (Z) JoinEntryInstr(if_false->block_id(), if_false->try_index()); + join = new (Z) JoinEntryInstr( + if_false->block_id(), if_false->try_index(), Thread::kNoDeoptId); join->InheritDeoptTarget(Z, if_false); if_false->UnuseAllInputs(); next = if_false->next(); } else if (!reachable_->Contains(if_false->preorder_number())) { ASSERT(if_true->parallel_move() == NULL); ASSERT(if_true->loop_info() == NULL); - join = - new (Z) JoinEntryInstr(if_true->block_id(), if_true->try_index()); + join = new (Z) JoinEntryInstr(if_true->block_id(), if_true->try_index(), + Thread::kNoDeoptId); join->InheritDeoptTarget(Z, if_true); if_true->UnuseAllInputs(); next = if_true->next(); @@ -1714,7 +1715,7 @@ void ConstantPropagator::Transform() { // Drop the comparison, which does not have side effects as long // as it is a strict compare (the only one we can determine is // constant with the current analysis). - GotoInstr* jump = new (Z) GotoInstr(join); + GotoInstr* jump = new (Z) GotoInstr(join, Thread::kNoDeoptId); jump->InheritDeoptTarget(Z, branch); Instruction* previous = branch->previous(); diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc index 2ca8a160661..a9c8302bee4 100644 --- a/runtime/vm/flow_graph.cc +++ b/runtime/vm/flow_graph.cc @@ -1018,7 +1018,8 @@ void FlowGraph::Rename(GrowableArray* live_phis, for (intptr_t i = parameter_count(); i < variable_count(); ++i) { if (i == CurrentContextEnvIndex()) { if (function().IsClosureFunction()) { - CurrentContextInstr* context = new CurrentContextInstr(); + CurrentContextInstr* context = + new CurrentContextInstr(Thread::kNoDeoptId); context->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. AddToInitialDefinitions(context); env.Add(context); diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc index 96ccbae3562..8973cc48c5b 100644 --- a/runtime/vm/flow_graph_builder.cc +++ b/runtime/vm/flow_graph_builder.cc @@ -173,8 +173,8 @@ intptr_t FlowGraphBuilder::context_level() const { JoinEntryInstr* NestedStatement::BreakTargetFor(SourceLabel* label) { if (label != label_) return NULL; if (break_target_ == NULL) { - break_target_ = new (owner()->zone()) - JoinEntryInstr(owner()->AllocateBlockId(), try_index()); + break_target_ = new (owner()->zone()) JoinEntryInstr( + owner()->AllocateBlockId(), try_index(), owner()->GetNextDeoptId()); } return break_target_; } @@ -246,8 +246,8 @@ class NestedLoop : public NestedStatement { JoinEntryInstr* NestedLoop::ContinueTargetFor(SourceLabel* label) { if (label != this->label()) return NULL; if (continue_target_ == NULL) { - continue_target_ = new (owner()->zone()) - JoinEntryInstr(owner()->AllocateBlockId(), try_index()); + continue_target_ = new (owner()->zone()) JoinEntryInstr( + owner()->AllocateBlockId(), try_index(), owner()->GetNextDeoptId()); } return continue_target_; } @@ -289,8 +289,8 @@ JoinEntryInstr* NestedSwitch::ContinueTargetFor(SourceLabel* label) { for (intptr_t i = 0; i < case_labels_.length(); ++i) { if (label != case_labels_[i]) continue; if (case_targets_[i] == NULL) { - case_targets_[i] = new (owner()->zone()) - JoinEntryInstr(owner()->AllocateBlockId(), try_index()); + case_targets_[i] = new (owner()->zone()) JoinEntryInstr( + owner()->AllocateBlockId(), try_index(), owner()->GetNextDeoptId()); } return case_targets_[i]; } @@ -442,7 +442,8 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, // Create a join of the returns. intptr_t join_id = caller_graph_->max_block_id() + 1; caller_graph_->set_max_block_id(join_id); - JoinEntryInstr* join = new (Z) JoinEntryInstr(join_id, try_index); + JoinEntryInstr* join = new (Z) + JoinEntryInstr(join_id, try_index, Thread::Current()->GetNextDeoptId()); // The dominator set of the join is the intersection of the dominator // sets of all the predecessors. If we keep the dominator sets ordered @@ -460,7 +461,8 @@ Definition* InlineExitCollector::JoinReturns(BlockEntryInstr** exit_block, GrowableArray join_dominators; for (intptr_t i = 0; i < num_exits; ++i) { // Add the control-flow edge. - GotoInstr* goto_instr = new (Z) GotoInstr(join); + GotoInstr* goto_instr = + new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()); goto_instr->InheritDeoptTarget(zone(), ReturnAt(i)); LastInstructionAt(i)->LinkTo(goto_instr); ExitBlockAt(i)->set_last_instruction(LastInstructionAt(i)->next()); @@ -546,16 +548,19 @@ void InlineExitCollector::ReplaceCall(TargetEntryInstr* callee_entry) { // goes to the rest of the caller graph. It is removed as unreachable code // by the constant propagation. TargetEntryInstr* false_block = new (Z) TargetEntryInstr( - caller_graph_->allocate_block_id(), call_block->try_index()); + caller_graph_->allocate_block_id(), call_block->try_index(), + Thread::Current()->GetNextDeoptId()); false_block->InheritDeoptTargetAfter(caller_graph_, call_, NULL); false_block->LinkTo(call_->next()); call_block->ReplaceAsPredecessorWith(false_block); ConstantInstr* true_const = caller_graph_->GetConstant(Bool::True()); - BranchInstr* branch = new (Z) BranchInstr(new (Z) StrictCompareInstr( - TokenPosition::kNoSource, Token::kEQ_STRICT, new (Z) Value(true_const), - new (Z) Value(true_const), - false)); // No number check. + BranchInstr* branch = new (Z) + BranchInstr(new (Z) StrictCompareInstr( + TokenPosition::kNoSource, Token::kEQ_STRICT, + new (Z) Value(true_const), new (Z) Value(true_const), + false, Thread::Current()->GetNextDeoptId()), + Thread::Current()->GetNextDeoptId()); // No number check. branch->InheritDeoptTarget(zone(), call_); *branch->true_successor_address() = callee_entry; *branch->false_successor_address() = false_block; @@ -699,7 +704,8 @@ void EffectGraphVisitor::AddInstruction(Instruction* instruction) { void EffectGraphVisitor::AddReturnExit(TokenPosition token_pos, Value* value) { ASSERT(is_open()); - ReturnInstr* return_instr = new (Z) ReturnInstr(token_pos, value); + ReturnInstr* return_instr = + new (Z) ReturnInstr(token_pos, value, owner()->GetNextDeoptId()); AddInstruction(return_instr); InlineExitCollector* exit_collector = owner()->exit_collector(); if (exit_collector != NULL) { @@ -712,7 +718,7 @@ void EffectGraphVisitor::AddReturnExit(TokenPosition token_pos, Value* value) { void EffectGraphVisitor::Goto(JoinEntryInstr* join) { ASSERT(is_open()); if (is_empty()) { - entry_ = new (Z) GotoInstr(join); + entry_ = new (Z) GotoInstr(join, owner()->GetNextDeoptId()); } else { exit()->Goto(join); } @@ -761,8 +767,9 @@ void EffectGraphVisitor::Join(const TestGraphVisitor& test_fragment, } else if (false_exit == NULL) { exit_ = true_exit; } else { - JoinEntryInstr* join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr* join = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); true_exit->Goto(join); false_exit->Goto(join); exit_ = join; @@ -792,10 +799,11 @@ void EffectGraphVisitor::TieLoop( Append(test_preamble_fragment); Append(test_fragment); } else { - JoinEntryInstr* join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); - CheckStackOverflowInstr* check = - new (Z) CheckStackOverflowInstr(token_pos, owner()->loop_depth()); + JoinEntryInstr* join = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); + CheckStackOverflowInstr* check = new (Z) CheckStackOverflowInstr( + token_pos, owner()->loop_depth(), owner()->GetNextDeoptId()); join->LinkTo(check); if (!test_preamble_fragment.is_empty()) { check->LinkTo(test_preamble_fragment.entry()); @@ -929,7 +937,8 @@ void TestGraphVisitor::ConnectBranchesTo( ASSERT(!branches.is_empty()); for (intptr_t i = 0; i < branches.length(); i++) { TargetEntryInstr* target = new (Z) - TargetEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + TargetEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); *(branches[i]) = target; target->Goto(join); } @@ -952,13 +961,15 @@ BlockEntryInstr* TestGraphVisitor::CreateSuccessorFor( if (branches.length() == 1) { TargetEntryInstr* target = new (Z) - TargetEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + TargetEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); *(branches[0]) = target; return target; } JoinEntryInstr* join = - new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); ConnectBranchesTo(branches, join); return join; } @@ -977,13 +988,14 @@ BlockEntryInstr* TestGraphVisitor::CreateFalseSuccessor() const { void TestGraphVisitor::ReturnValue(Value* value) { Isolate* isolate = Isolate::Current(); if (isolate->type_checks() || isolate->asserts()) { - value = Bind(new (Z) AssertBooleanInstr(condition_token_pos(), value)); + value = Bind(new (Z) AssertBooleanInstr(condition_token_pos(), value, + owner()->GetNextDeoptId())); } Value* constant_true = Bind(new (Z) ConstantInstr(Bool::True())); StrictCompareInstr* comp = new (Z) StrictCompareInstr( - condition_token_pos(), Token::kEQ_STRICT, value, constant_true, - false); // No number check. - BranchInstr* branch = new (Z) BranchInstr(comp); + condition_token_pos(), Token::kEQ_STRICT, value, constant_true, false, + owner()->GetNextDeoptId()); // No number check. + BranchInstr* branch = new (Z) BranchInstr(comp, owner()->GetNextDeoptId()); AddInstruction(branch); CloseFragment(); @@ -993,7 +1005,7 @@ void TestGraphVisitor::ReturnValue(Value* value) { void TestGraphVisitor::MergeBranchWithStrictCompare(StrictCompareInstr* comp) { - BranchInstr* branch = new (Z) BranchInstr(comp); + BranchInstr* branch = new (Z) BranchInstr(comp, owner()->GetNextDeoptId()); AddInstruction(branch); CloseFragment(); true_successor_addresses_.Add(branch->true_successor_address()); @@ -1006,8 +1018,8 @@ void TestGraphVisitor::MergeBranchWithNegate(BooleanNegateInstr* neg) { Value* constant_true = Bind(new (Z) ConstantInstr(Bool::True())); StrictCompareInstr* comp = new (Z) StrictCompareInstr( condition_token_pos(), Token::kNE_STRICT, neg->value(), constant_true, - false); // No number check. - BranchInstr* branch = new (Z) BranchInstr(comp); + false, owner()->GetNextDeoptId()); // No number check. + BranchInstr* branch = new (Z) BranchInstr(comp, owner()->GetNextDeoptId()); AddInstruction(branch); CloseFragment(); true_successor_addresses_.Add(branch->true_successor_address()); @@ -1141,11 +1153,11 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { ZoneGrowableArray* no_arguments = new (Z) ZoneGrowableArray(0); const int kTypeArgsLen = 0; - StaticCallInstr* call_async_clear_thread_stack_trace = - new (Z) StaticCallInstr(node->token_pos().ToSynthetic(), - async_clear_thread_stack_trace, kTypeArgsLen, - Object::null_array(), no_arguments, - owner()->ic_data_array()); + StaticCallInstr* call_async_clear_thread_stack_trace = new (Z) + StaticCallInstr(node->token_pos().ToSynthetic(), + async_clear_thread_stack_trace, kTypeArgsLen, + Object::null_array(), no_arguments, + owner()->ic_data_array(), owner()->GetNextDeoptId()); Do(call_async_clear_thread_stack_trace); } @@ -1180,7 +1192,8 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { const int kTypeArgsLen = 0; StaticCallInstr* call = new (Z) StaticCallInstr( node->token_pos().ToSynthetic(), complete_on_async_return, kTypeArgsLen, - Object::null_array(), arguments, owner()->ic_data_array()); + Object::null_array(), arguments, owner()->ic_data_array(), + owner()->GetNextDeoptId()); Do(call); // Rebind the return value for the actual return call to be null. @@ -1198,8 +1211,9 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { if ((function.IsAsyncClosure() || function.IsSyncGenClosure() || function.IsAsyncGenClosure()) && (node->return_type() == ReturnNode::kContinuationTarget)) { - JoinEntryInstr* const join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr* const join = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); owner()->await_joins()->Add(join); exit_ = join; } @@ -1242,7 +1256,8 @@ void ValueGraphVisitor::VisitTypeNode(TypeNode* node) { function_type_arguments = BuildFunctionTypeArguments(token_pos); } ReturnDefinition(new (Z) InstantiateTypeInstr( - token_pos, type, instantiator_type_arguments, function_type_arguments)); + token_pos, type, instantiator_type_arguments, function_type_arguments, + owner()->GetNextDeoptId())); } @@ -1332,8 +1347,8 @@ void EffectGraphVisitor::VisitBinaryOpNode(BinaryOpNode* node) { ValueGraphVisitor for_right(owner()); node->right()->Visit(&for_right); Value* right_value = for_right.value(); - for_right.Do( - new (Z) AssertBooleanInstr(node->right()->token_pos(), right_value)); + for_right.Do(new (Z) AssertBooleanInstr( + node->right()->token_pos(), right_value, owner()->GetNextDeoptId())); if (node->kind() == Token::kAND) { Join(for_left, for_right, empty); } else { @@ -1368,9 +1383,10 @@ void EffectGraphVisitor::VisitBinaryOpNode(BinaryOpNode* node) { const String& name = Symbols::Token(node->kind()); const intptr_t kTypeArgsLen = 0; const intptr_t kNumArgsChecked = 2; - InstanceCallInstr* call = new (Z) InstanceCallInstr( - node->token_pos(), name, node->kind(), arguments, kTypeArgsLen, - Object::null_array(), kNumArgsChecked, owner()->ic_data_array()); + InstanceCallInstr* call = new (Z) + InstanceCallInstr(node->token_pos(), name, node->kind(), arguments, + kTypeArgsLen, Object::null_array(), kNumArgsChecked, + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } @@ -1393,13 +1409,13 @@ void ValueGraphVisitor::VisitBinaryOpNode(BinaryOpNode* node) { Value* right_value = for_right.value(); Isolate* isolate = Isolate::Current(); if (isolate->type_checks() || isolate->asserts()) { - right_value = for_right.Bind( - new (Z) AssertBooleanInstr(node->right()->token_pos(), right_value)); + right_value = for_right.Bind(new (Z) AssertBooleanInstr( + node->right()->token_pos(), right_value, owner()->GetNextDeoptId())); } Value* constant_true = for_right.Bind(new (Z) ConstantInstr(Bool::True())); Value* compare = for_right.Bind(new (Z) StrictCompareInstr( - node->token_pos(), Token::kEQ_STRICT, right_value, constant_true, - false)); // No number check. + node->token_pos(), Token::kEQ_STRICT, right_value, constant_true, false, + owner()->GetNextDeoptId())); // No number check. for_right.Do(BuildStoreExprTemp(compare, node->token_pos())); if (node->kind() == Token::kAND) { @@ -1535,7 +1551,7 @@ void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()), node->kind(), arguments, kTypeArgsLen, Object::null_array(), // No argument names. - kNumArgsChecked, owner()->ic_data_array()); + kNumArgsChecked, owner()->ic_data_array(), owner()->GetNextDeoptId()); if (negate_result) { result = new (Z) BooleanNegateInstr(Bind(result)); } @@ -1560,7 +1576,7 @@ void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { node->token_pos(), Library::PrivateCoreLibName(Symbols::_instanceOf()), node->kind(), arguments, kTypeArgsLen, Object::null_array(), // No argument names. - kNumArgsChecked, owner()->ic_data_array()); + kNumArgsChecked, owner()->ic_data_array(), owner()->GetNextDeoptId()); if (negate_result) { result = new (Z) BooleanNegateInstr(Bind(result)); } @@ -1599,7 +1615,7 @@ void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { node->token_pos(), Library::PrivateCoreLibName(Symbols::_as()), node->kind(), arguments, kTypeArgsLen, Object::null_array(), // No argument names. - kNumArgsChecked, owner()->ic_data_array()); + kNumArgsChecked, owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } @@ -1616,8 +1632,8 @@ StrictCompareInstr* EffectGraphVisitor::BuildStrictCompare( right->Visit(&for_right_value); Append(for_right_value); StrictCompareInstr* comp = new (Z) StrictCompareInstr( - token_pos, kind, for_left_value.value(), for_right_value.value(), - true); // Number check. + token_pos, kind, for_left_value.value(), for_right_value.value(), true, + owner()->GetNextDeoptId()); // Number check. return comp; } @@ -1673,16 +1689,17 @@ void EffectGraphVisitor::VisitComparisonNode(ComparisonNode* node) { const intptr_t kTypeArgsLen = 0; const intptr_t kNumArgsChecked = 2; - Definition* result = new (Z) - InstanceCallInstr(node->token_pos(), Symbols::EqualOperator(), - Token::kEQ, // Result is negated later for kNE. - arguments, kTypeArgsLen, Object::null_array(), - kNumArgsChecked, owner()->ic_data_array()); + Definition* result = new (Z) InstanceCallInstr( + node->token_pos(), Symbols::EqualOperator(), + Token::kEQ, // Result is negated later for kNE. + arguments, kTypeArgsLen, Object::null_array(), kNumArgsChecked, + owner()->ic_data_array(), owner()->GetNextDeoptId()); if (node->kind() == Token::kNE) { Isolate* isolate = Isolate::Current(); if (isolate->type_checks() || isolate->asserts()) { Value* value = Bind(result); - result = new (Z) AssertBooleanInstr(node->token_pos(), value); + result = new (Z) AssertBooleanInstr(node->token_pos(), value, + owner()->GetNextDeoptId()); } Value* value = Bind(result); result = new (Z) BooleanNegateInstr(value); @@ -1710,7 +1727,8 @@ void EffectGraphVisitor::VisitComparisonNode(ComparisonNode* node) { const intptr_t kTypeArgsLen = 0; InstanceCallInstr* comp = new (Z) InstanceCallInstr( node->token_pos(), Symbols::Token(node->kind()), node->kind(), arguments, - kTypeArgsLen, Object::null_array(), 2, owner()->ic_data_array()); + kTypeArgsLen, Object::null_array(), 2, owner()->ic_data_array(), + owner()->GetNextDeoptId()); ReturnDefinition(comp); } @@ -1724,8 +1742,8 @@ void EffectGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) { Value* value = for_value.value(); Isolate* isolate = Isolate::Current(); if (isolate->type_checks() || isolate->asserts()) { - value = - Bind(new (Z) AssertBooleanInstr(node->operand()->token_pos(), value)); + value = Bind(new (Z) AssertBooleanInstr( + node->operand()->token_pos(), value, owner()->GetNextDeoptId())); } BooleanNegateInstr* negate = new (Z) BooleanNegateInstr(value); ReturnDefinition(negate); @@ -1742,7 +1760,8 @@ void EffectGraphVisitor::VisitUnaryOpNode(UnaryOpNode* node) { const intptr_t kTypeArgsLen = 0; InstanceCallInstr* call = new (Z) InstanceCallInstr( node->token_pos(), Symbols::Token(node->kind()), node->kind(), arguments, - kTypeArgsLen, Object::null_array(), 1, owner()->ic_data_array()); + kTypeArgsLen, Object::null_array(), 1, owner()->ic_data_array(), + owner()->GetNextDeoptId()); ReturnDefinition(call); } @@ -1840,8 +1859,9 @@ void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { // Compute the start of the statements fragment. JoinEntryInstr* statement_start = NULL; if (node->label() == NULL) { - statement_start = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + statement_start = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); } else { // The case nodes are nested inside a SequenceNode that is the body of a // SwitchNode. The SwitchNode on the nesting stack contains the @@ -1893,7 +1913,8 @@ void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { } else { if (statement_exit != NULL) { JoinEntryInstr* join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); statement_exit->Goto(join); next_target->Goto(join); exit_instruction = join; @@ -1976,7 +1997,8 @@ void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { // Tie do-while loop (test is after the body). JoinEntryInstr* body_entry_join = - new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); Goto(body_entry_join); Instruction* body_exit = AppendFragment(body_entry_join, for_body); @@ -1984,10 +2006,11 @@ void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { if ((body_exit != NULL) || (join != NULL)) { if (join == NULL) { join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); } - CheckStackOverflowInstr* check = new (Z) - CheckStackOverflowInstr(node->token_pos(), owner()->loop_depth()); + CheckStackOverflowInstr* check = new (Z) CheckStackOverflowInstr( + node->token_pos(), owner()->loop_depth(), owner()->GetNextDeoptId()); join->LinkTo(check); check->LinkTo(for_test.entry()); if (body_exit != NULL) { @@ -2035,8 +2058,9 @@ void EffectGraphVisitor::VisitForNode(ForNode* node) { // Join the loop body and increment and then tie the loop. JoinEntryInstr* continue_join = nested_loop.continue_target(); if ((continue_join != NULL) || for_body.is_open()) { - JoinEntryInstr* loop_entry = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr* loop_entry = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); if (continue_join != NULL) { if (for_body.is_open()) for_body.Goto(continue_join); Instruction* current = AppendFragment(continue_join, for_increment); @@ -2053,7 +2077,8 @@ void EffectGraphVisitor::VisitForNode(ForNode* node) { // the context level (if any) matches the that of the increment // expression. AddInstruction(new (Z) CheckStackOverflowInstr( - node->increment()->token_pos(), owner()->loop_depth())); + node->increment()->token_pos(), owner()->loop_depth(), + owner()->GetNextDeoptId())); } if (node->condition() == NULL) { @@ -2248,8 +2273,8 @@ void EffectGraphVisitor::VisitArrayNode(ArrayNode* node) { BuildInstantiatedTypeArguments(node->token_pos(), type_args); Value* num_elements = Bind(new (Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(node->length())))); - CreateArrayInstr* create = - new (Z) CreateArrayInstr(node->token_pos(), element_type, num_elements); + CreateArrayInstr* create = new (Z) CreateArrayInstr( + node->token_pos(), element_type, num_elements, owner()->GetNextDeoptId()); Value* array_val = Bind(create); { @@ -2299,16 +2324,16 @@ void EffectGraphVisitor::VisitStringInterpolateNode( Z, Resolver::ResolveStatic( cls, Library::PrivateCoreLibName(Symbols::InterpolateSingle()), kTypeArgsLen, kNumberOfArguments, kNoArgumentNames)); - StaticCallInstr* call = new (Z) - StaticCallInstr(node->token_pos(), function, kTypeArgsLen, - kNoArgumentNames, values, owner()->ic_data_array()); + StaticCallInstr* call = new (Z) StaticCallInstr( + node->token_pos(), function, kTypeArgsLen, kNoArgumentNames, values, + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); return; } arguments->Visit(&for_argument); Append(for_argument); - StringInterpolateInstr* instr = - new (Z) StringInterpolateInstr(for_argument.value(), node->token_pos()); + StringInterpolateInstr* instr = new (Z) StringInterpolateInstr( + for_argument.value(), node->token_pos(), owner()->GetNextDeoptId()); ReturnDefinition(instr); } @@ -2530,7 +2555,7 @@ void EffectGraphVisitor::VisitInstanceCallNode(InstanceCallNode* node) { InstanceCallInstr* call = new (Z) InstanceCallInstr( node->token_pos(), node->function_name(), Token::kILLEGAL, arguments, node->arguments()->type_args_len(), node->arguments()->names(), 1, - owner()->ic_data_array()); + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } } @@ -2546,7 +2571,8 @@ void EffectGraphVisitor::VisitStaticCallNode(StaticCallNode* node) { BuildPushArguments(*node->arguments(), arguments); StaticCallInstr* call = new (Z) StaticCallInstr( node->token_pos(), node->function(), node->arguments()->type_args_len(), - node->arguments()->names(), arguments, owner()->ic_data_array()); + node->arguments()->names(), arguments, owner()->ic_data_array(), + owner()->GetNextDeoptId()); if (node->function().recognized_kind() != MethodRecognizer::kUnknown) { call->set_result_cid(MethodRecognizer::ResultCid(node->function())); } @@ -2580,8 +2606,8 @@ void EffectGraphVisitor::BuildClosureCall(ClosureCallNode* node, function_load->set_is_immutable(true); Value* function_val = Bind(function_load); - Definition* closure_call = - new (Z) ClosureCallInstr(function_val, node, arguments); + Definition* closure_call = new (Z) ClosureCallInstr( + function_val, node, arguments, owner()->GetNextDeoptId()); if (result_needed) { Value* result = Bind(closure_call); Do(new (Z) StoreLocalInstr(*tmp_var, result, ST(node->token_pos()))); @@ -2605,13 +2631,15 @@ void ValueGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) { void EffectGraphVisitor::VisitInitStaticFieldNode(InitStaticFieldNode* node) { Value* field = Bind( new (Z) ConstantInstr(Field::ZoneHandle(Z, node->field().Original()))); - AddInstruction(new (Z) InitStaticFieldInstr(field, node->field())); + AddInstruction(new (Z) InitStaticFieldInstr(field, node->field(), + owner()->GetNextDeoptId())); } void EffectGraphVisitor::VisitCloneContextNode(CloneContextNode* node) { Value* context = Bind(BuildCurrentContext(node->token_pos())); - Value* clone = Bind(new (Z) CloneContextInstr(node->token_pos(), context)); + Value* clone = Bind(new (Z) CloneContextInstr(node->token_pos(), context, + owner()->GetNextDeoptId())); Do(BuildStoreContext(clone, node->token_pos())); } @@ -2645,9 +2673,10 @@ void EffectGraphVisitor::BuildConstructorCall( BuildPushArguments(*node->arguments(), arguments); const intptr_t kTypeArgsLen = 0; - Do(new (Z) StaticCallInstr(node->token_pos(), node->constructor(), - kTypeArgsLen, node->arguments()->names(), - arguments, owner()->ic_data_array())); + Do(new (Z) + StaticCallInstr(node->token_pos(), node->constructor(), kTypeArgsLen, + node->arguments()->names(), arguments, + owner()->ic_data_array(), owner()->GetNextDeoptId())); } @@ -2686,9 +2715,10 @@ void EffectGraphVisitor::VisitConstructorCallNode(ConstructorCallNode* node) { ASSERT(arguments->length() == 1); BuildPushArguments(*node->arguments(), arguments); const int kTypeArgsLen = 0; - StaticCallInstr* call = new (Z) StaticCallInstr( - node->token_pos(), node->constructor(), kTypeArgsLen, - node->arguments()->names(), arguments, owner()->ic_data_array()); + StaticCallInstr* call = new (Z) + StaticCallInstr(node->token_pos(), node->constructor(), kTypeArgsLen, + node->arguments()->names(), arguments, + owner()->ic_data_array(), owner()->GetNextDeoptId()); const intptr_t result_cid = GetResultCidOfListFactory(node); if (result_cid != kDynamicCid) { call->set_result_cid(result_cid); @@ -2830,7 +2860,7 @@ Value* EffectGraphVisitor::BuildInstantiatedTypeArguments( } return Bind(new (Z) InstantiateTypeArgumentsInstr( token_pos, type_arguments, instantiator_class, instantiator_type_args, - function_type_args)); + function_type_args, owner()->GetNextDeoptId())); } @@ -2919,9 +2949,10 @@ void EffectGraphVisitor::VisitInstanceGetterNode(InstanceGetterNode* node) { const String& name = String::ZoneHandle(Z, Field::GetterSymbol(node->field_name())); const intptr_t kTypeArgsLen = 0; - InstanceCallInstr* call = new (Z) InstanceCallInstr( - node->token_pos(), name, Token::kGET, arguments, kTypeArgsLen, - Object::null_array(), 1, owner()->ic_data_array()); + InstanceCallInstr* call = new (Z) + InstanceCallInstr(node->token_pos(), name, Token::kGET, arguments, + kTypeArgsLen, Object::null_array(), 1, + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } } @@ -2983,9 +3014,10 @@ void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { String::ZoneHandle(Z, Field::SetterSymbol(node->field_name())); const int kTypeArgsLen = 0; const intptr_t kNumArgsChecked = 1; // Do not check value type. - InstanceCallInstr* call = new (Z) InstanceCallInstr( - token_pos, name, Token::kSET, arguments, kTypeArgsLen, - Object::null_array(), kNumArgsChecked, owner()->ic_data_array()); + InstanceCallInstr* call = new (Z) + InstanceCallInstr(token_pos, name, Token::kSET, arguments, kTypeArgsLen, + Object::null_array(), kNumArgsChecked, + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } @@ -3030,7 +3062,8 @@ void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { const intptr_t kNumArgsChecked = 1; // Do not check value type. Do(new (Z) InstanceCallInstr(token_pos, name, Token::kSET, arguments, kTypeArgsLen, Object::null_array(), - kNumArgsChecked, owner()->ic_data_array())); + kNumArgsChecked, owner()->ic_data_array(), + owner()->GetNextDeoptId())); ReturnDefinition(BuildLoadExprTemp(token_pos)); } @@ -3093,10 +3126,10 @@ void EffectGraphVisitor::VisitStaticGetterNode(StaticGetterNode* node) { } ASSERT(!getter_function.IsNull()); const intptr_t kTypeArgsLen = 0; - StaticCallInstr* call = - new (Z) StaticCallInstr(node->token_pos(), getter_function, kTypeArgsLen, - Object::null_array(), // No names - arguments, owner()->ic_data_array()); + StaticCallInstr* call = new (Z) StaticCallInstr( + node->token_pos(), getter_function, kTypeArgsLen, + Object::null_array(), // No names + arguments, owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(call); } @@ -3158,7 +3191,8 @@ void EffectGraphVisitor::BuildStaticSetter(StaticSetterNode* node, const intptr_t kTypeArgsLen = 0; call = new (Z) StaticCallInstr(token_pos, setter_function, kTypeArgsLen, Object::null_array(), // No names. - arguments, owner()->ic_data_array()); + arguments, owner()->ic_data_array(), + owner()->GetNextDeoptId()); } if (result_is_needed) { Do(call); @@ -3250,8 +3284,9 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { Value* other = Bind(new (Z) LoadLocalInstr(*other_var, token_pos)); // Receiver is not a number because numbers override equality. const bool kNoNumberCheck = false; - StrictCompareInstr* compare = new (Z) StrictCompareInstr( - token_pos, Token::kEQ_STRICT, receiver, other, kNoNumberCheck); + StrictCompareInstr* compare = new (Z) + StrictCompareInstr(token_pos, Token::kEQ_STRICT, receiver, other, + kNoNumberCheck, owner()->GetNextDeoptId()); return ReturnDefinition(compare); } case MethodRecognizer::kStringBaseLength: @@ -3271,9 +3306,9 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { Value* zero_val = Bind(new (Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(0)))); Value* load_val = Bind(load); - StrictCompareInstr* compare = new (Z) - StrictCompareInstr(token_pos, Token::kEQ_STRICT, load_val, zero_val, - false); // No number check. + StrictCompareInstr* compare = new (Z) StrictCompareInstr( + token_pos, Token::kEQ_STRICT, load_val, zero_val, false, + owner()->GetNextDeoptId()); // No number check. return ReturnDefinition(compare); } case MethodRecognizer::kGrowableArrayLength: @@ -3316,8 +3351,8 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) { node->scope()->LookupVariable(Symbols::Length(), true); Value* length = Bind(new (Z) LoadLocalInstr(*length_parameter, token_pos)); - CreateArrayInstr* create_array = - new CreateArrayInstr(token_pos, element_type, length); + CreateArrayInstr* create_array = new CreateArrayInstr( + token_pos, element_type, length, owner()->GetNextDeoptId()); return ReturnDefinition(create_array); } case MethodRecognizer::kBigint_getDigits: { @@ -3607,7 +3642,7 @@ void EffectGraphVisitor::VisitLoadIndexedNode(LoadIndexedNode* node) { // Generate static call to super operator. StaticCallInstr* load = new (Z) StaticCallInstr( node->token_pos(), *super_function, kTypeArgsLen, Object::null_array(), - arguments, owner()->ic_data_array()); + arguments, owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(load); } else { // Generate dynamic call to index operator. @@ -3615,7 +3650,7 @@ void EffectGraphVisitor::VisitLoadIndexedNode(LoadIndexedNode* node) { InstanceCallInstr* load = new (Z) InstanceCallInstr( node->token_pos(), Symbols::IndexToken(), Token::kINDEX, arguments, kTypeArgsLen, Object::null_array(), checked_argument_count, - owner()->ic_data_array()); + owner()->ic_data_array(), owner()->GetNextDeoptId()); ReturnDefinition(load); } } @@ -3681,7 +3716,7 @@ Definition* EffectGraphVisitor::BuildStoreIndexedValues(StoreIndexedNode* node, StaticCallInstr* store = new (Z) StaticCallInstr( token_pos, *super_function, kTypeArgsLen, Object::null_array(), - arguments, owner()->ic_data_array()); + arguments, owner()->ic_data_array(), owner()->GetNextDeoptId()); if (result_is_needed) { Do(store); return BuildLoadExprTemp(token_pos); @@ -3694,7 +3729,7 @@ Definition* EffectGraphVisitor::BuildStoreIndexedValues(StoreIndexedNode* node, InstanceCallInstr* store = new (Z) InstanceCallInstr( token_pos, Symbols::AssignIndexToken(), Token::kASSIGN_INDEX, arguments, kTypeArgsLen, Object::null_array(), checked_argument_count, - owner()->ic_data_array()); + owner()->ic_data_array(), owner()->GetNextDeoptId()); if (result_is_needed) { Do(store); return BuildLoadExprTemp(token_pos); @@ -3865,11 +3900,11 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { ASSERT(!async_set_thread_stack_trace.IsNull()); // Call _asyncSetThreadStackTrace const intptr_t kTypeArgsLen = 0; - StaticCallInstr* call_async_set_thread_stack_trace = - new (Z) StaticCallInstr(node->token_pos().ToSynthetic(), - async_set_thread_stack_trace, kTypeArgsLen, - Object::null_array(), arguments, - owner()->ic_data_array()); + StaticCallInstr* call_async_set_thread_stack_trace = new (Z) + StaticCallInstr(node->token_pos().ToSynthetic(), + async_set_thread_stack_trace, kTypeArgsLen, + Object::null_array(), arguments, + owner()->ic_data_array(), owner()->GetNextDeoptId()); Do(call_async_set_thread_stack_trace); } @@ -3903,8 +3938,8 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { // if we inline or not. if (!function.IsImplicitGetterFunction() && !function.IsImplicitSetterFunction()) { - CheckStackOverflowInstr* check = - new (Z) CheckStackOverflowInstr(node->token_pos(), 0); + CheckStackOverflowInstr* check = new (Z) CheckStackOverflowInstr( + node->token_pos(), 0, owner()->GetNextDeoptId()); // If we are inlining don't actually attach the stack check. We must still // create the stack check in order to allocate a deopt id. if (!owner()->IsInlining()) { @@ -3944,8 +3979,9 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { if (is_top_level_sequence && (function.IsAsyncClosure() || function.IsSyncGenClosure() || function.IsAsyncGenClosure())) { - JoinEntryInstr* preamble_end = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr* preamble_end = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); ASSERT(exit() != NULL); exit()->Goto(preamble_end); ASSERT(exit()->next()->IsGoto()); @@ -4087,13 +4123,14 @@ void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { if (for_try.is_open()) { JoinEntryInstr* after_try = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index); + JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index, + owner()->GetNextDeoptId()); for_try.Goto(after_try); for_try.exit_ = after_try; } - JoinEntryInstr* try_entry = - new (Z) JoinEntryInstr(owner()->AllocateBlockId(), try_handler_index); + JoinEntryInstr* try_entry = new (Z) JoinEntryInstr( + owner()->AllocateBlockId(), try_handler_index, owner()->GetNextDeoptId()); Goto(try_entry); AppendFragment(try_entry, for_try); @@ -4133,7 +4170,8 @@ void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { if (for_catch.is_open()) { JoinEntryInstr* join = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index); + JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index, + owner()->GetNextDeoptId()); for_catch.Goto(join); if (is_open()) Goto(join); exit_ = join; @@ -4158,7 +4196,8 @@ void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { catch_block->rethrow_stacktrace_var(), finally_block->token_pos())); for_finally.PushArgument(stacktrace); for_finally.AddInstruction( - new (Z) ReThrowInstr(catch_block->token_pos(), catch_handler_index)); + new (Z) ReThrowInstr(catch_block->token_pos(), catch_handler_index, + owner()->GetNextDeoptId())); for_finally.CloseFragment(); } ASSERT(!for_finally.is_open()); @@ -4221,9 +4260,9 @@ StaticCallInstr* EffectGraphVisitor::BuildStaticNoSuchMethodCall( ZoneGrowableArray* push_arguments = new (Z) ZoneGrowableArray(2); BuildPushArguments(*args, push_arguments); - return new (Z) StaticCallInstr(args_pos, no_such_method_func, kTypeArgsLen, - Object::null_array(), push_arguments, - owner()->ic_data_array()); + return new (Z) StaticCallInstr( + args_pos, no_such_method_func, kTypeArgsLen, Object::null_array(), + push_arguments, owner()->ic_data_array(), owner()->GetNextDeoptId()); } @@ -4289,7 +4328,8 @@ StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError( ASSERT(!func.IsNull()); return new (Z) StaticCallInstr(token_pos, func, kTypeArgsLen, Object::null_array(), // No names. - arguments, owner()->ic_data_array()); + arguments, owner()->ic_data_array(), + owner()->GetNextDeoptId()); } @@ -4309,13 +4349,14 @@ void EffectGraphVisitor::BuildThrowNode(ThrowNode* node) { PushArgument(for_exception.value()); Instruction* instr = NULL; if (node->stacktrace() == NULL) { - instr = new (Z) ThrowInstr(node->token_pos()); + instr = new (Z) ThrowInstr(node->token_pos(), owner()->GetNextDeoptId()); } else { ValueGraphVisitor for_stack_trace(owner()); node->stacktrace()->Visit(&for_stack_trace); Append(for_stack_trace); PushArgument(for_stack_trace.value()); - instr = new (Z) ReThrowInstr(node->token_pos(), owner()->catch_try_index()); + instr = new (Z) ReThrowInstr(node->token_pos(), owner()->catch_try_index(), + owner()->GetNextDeoptId()); } AddInstruction(instr); } @@ -4355,7 +4396,8 @@ void EffectGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) { // context variable. JoinEntryInstr* finally_entry = - new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); EffectGraphVisitor for_finally_block(owner()); for_finally_block.AdjustContextLevel(node->finally_block()->scope()); node->finally_block()->Visit(&for_finally_block); @@ -4365,8 +4407,9 @@ void EffectGraphVisitor::VisitInlinedFinallyNode(InlinedFinallyNode* node) { } if (for_finally_block.is_open()) { - JoinEntryInstr* after_finally = new (Z) - JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); + JoinEntryInstr* after_finally = + new (Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index(), + owner()->GetNextDeoptId()); for_finally_block.Goto(after_finally); for_finally_block.exit_ = after_finally; } @@ -4396,8 +4439,8 @@ FlowGraph* FlowGraphBuilder::BuildGraph() { AstPrinter ast_printer; ast_printer.PrintFunctionScope(parsed_function()); } - TargetEntryInstr* normal_entry = new (Z) - TargetEntryInstr(AllocateBlockId(), CatchClauseNode::kInvalidTryIndex); + TargetEntryInstr* normal_entry = new (Z) TargetEntryInstr( + AllocateBlockId(), CatchClauseNode::kInvalidTryIndex, GetNextDeoptId()); graph_entry_ = new (Z) GraphEntryInstr(parsed_function(), normal_entry, osr_id_); EffectGraphVisitor for_effect(this); diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h index 41f7e95af53..5fbc056f296 100644 --- a/runtime/vm/flow_graph_builder.h +++ b/runtime/vm/flow_graph_builder.h @@ -114,6 +114,11 @@ class FlowGraphBuilder : public ValueObject { intptr_t AllocateBlockId() { return ++last_used_block_id_; } void SetInitialBlockId(intptr_t id) { last_used_block_id_ = id; } + intptr_t GetNextDeoptId() { + // TODO(rmacnak): Record current scope / context level. + return thread()->GetNextDeoptId(); + } + intptr_t context_level() const; void IncrementLoopDepth() { ++loop_depth_; } diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc index f5b3030347d..d0d9d3e6cf5 100644 --- a/runtime/vm/flow_graph_inliner.cc +++ b/runtime/vm/flow_graph_inliner.cc @@ -1480,10 +1480,10 @@ bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { new_join->AddDominatedBlock(block); } // Create a new target with the join as unconditional successor. - TargetEntryInstr* new_target = - new TargetEntryInstr(AllocateBlockId(), old_target->try_index()); + TargetEntryInstr* new_target = new TargetEntryInstr( + AllocateBlockId(), old_target->try_index(), Thread::kNoDeoptId); new_target->InheritDeoptTarget(zone(), new_join); - GotoInstr* new_goto = new (Z) GotoInstr(new_join); + GotoInstr* new_goto = new (Z) GotoInstr(new_join, Thread::kNoDeoptId); new_goto->InheritDeoptTarget(zone(), new_join); new_target->LinkTo(new_goto); new_target->set_last_instruction(new_goto); @@ -1622,8 +1622,9 @@ bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, InlineExitCollector* exit_collector = new (Z) InlineExitCollector(owner_->caller_graph(), call_); - ReturnInstr* result = new (Z) - ReturnInstr(call_->instance_call()->token_pos(), new (Z) Value(last)); + ReturnInstr* result = + new (Z) ReturnInstr(call_->instance_call()->token_pos(), + new (Z) Value(last), Thread::kNoDeoptId); owner_->caller_graph()->AppendTo( last, result, call_->env(), // Return can become deoptimization target. @@ -1653,8 +1654,8 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { const intptr_t try_idx = call_->GetBlock()->try_index(); // Start with a fresh target entry. - TargetEntryInstr* entry = - new (Z) TargetEntryInstr(AllocateBlockId(), try_idx); + TargetEntryInstr* entry = new (Z) TargetEntryInstr( + AllocateBlockId(), try_idx, Thread::Current()->GetNextDeoptId()); entry->InheritDeoptTarget(zone(), call_); // This function uses a cursor (a pointer to the 'current' instruction) to @@ -1719,7 +1720,7 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { // the join. JoinEntryInstr* join = callee_entry->AsJoinEntry(); ASSERT(join->dominator() != NULL); - GotoInstr* goto_join = new GotoInstr(join); + GotoInstr* goto_join = new GotoInstr(join, Thread::kNoDeoptId); goto_join->InheritDeoptTarget(zone(), join); cursor->LinkTo(goto_join); current_block->set_last_instruction(goto_join); @@ -1749,13 +1750,13 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { new Value(load_cid), new Value(cid_constant_end), kSmiCid, call_->deopt_id()); BranchInstr* branch_top = upper_limit_branch = - new BranchInstr(compare_top); + new BranchInstr(compare_top, Thread::kNoDeoptId); branch_top->InheritDeoptTarget(zone(), call_); cursor = AppendInstruction(cursor, branch_top); current_block->set_last_instruction(branch_top); - TargetEntryInstr* below_target = - new TargetEntryInstr(AllocateBlockId(), try_idx); + TargetEntryInstr* below_target = new TargetEntryInstr( + AllocateBlockId(), try_idx, Thread::kNoDeoptId); below_target->InheritDeoptTarget(zone(), call_); current_block->AddDominatedBlock(below_target); cursor = current_block = below_target; @@ -1765,13 +1766,13 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { call_->instance_call()->token_pos(), Token::kGTE, new Value(load_cid), new Value(cid_constant), kSmiCid, call_->deopt_id()); - branch = new BranchInstr(compare_bottom); + branch = new BranchInstr(compare_bottom, Thread::kNoDeoptId); } else { StrictCompareInstr* compare = new StrictCompareInstr( call_->instance_call()->token_pos(), Token::kEQ_STRICT, new Value(load_cid), new Value(cid_constant), - false); // No number check. - branch = new BranchInstr(compare); + /* number_check = */ false, Thread::kNoDeoptId); + branch = new BranchInstr(compare, Thread::kNoDeoptId); } branch->InheritDeoptTarget(zone(), call_); @@ -1802,9 +1803,10 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { JoinEntryInstr* join = callee_entry->AsJoinEntry(); ASSERT(join != NULL); ASSERT(join->dominator() != NULL); - true_target = new TargetEntryInstr(AllocateBlockId(), try_idx); + true_target = new TargetEntryInstr(AllocateBlockId(), try_idx, + Thread::kNoDeoptId); true_target->InheritDeoptTarget(zone(), join); - GotoInstr* goto_join = new GotoInstr(join); + GotoInstr* goto_join = new GotoInstr(join, Thread::kNoDeoptId); goto_join->InheritDeoptTarget(zone(), join); true_target->LinkTo(goto_join); true_target->set_last_instruction(goto_join); @@ -1816,7 +1818,7 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { // fall-through code below for non-inlined variants. TargetEntryInstr* false_target = - new TargetEntryInstr(AllocateBlockId(), try_idx); + new TargetEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); false_target->InheritDeoptTarget(zone(), call_); *branch->false_successor_address() = false_target; cid_test_entry_block->AddDominatedBlock(false_target); @@ -1826,14 +1828,15 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { if (test_is_range) { // If we tested against a range of Cids there are two different tests // that can go to the no-cid-match target. - JoinEntryInstr* join = new JoinEntryInstr(AllocateBlockId(), try_idx); - TargetEntryInstr* false_target2 = - new TargetEntryInstr(AllocateBlockId(), try_idx); + JoinEntryInstr* join = + new JoinEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); + TargetEntryInstr* false_target2 = new TargetEntryInstr( + AllocateBlockId(), try_idx, Thread::kNoDeoptId); *upper_limit_branch->false_successor_address() = false_target2; cid_test_entry_block->AddDominatedBlock(false_target2); cid_test_entry_block->AddDominatedBlock(join); - GotoInstr* goto_1 = new GotoInstr(join); - GotoInstr* goto_2 = new GotoInstr(join); + GotoInstr* goto_1 = new GotoInstr(join, Thread::kNoDeoptId); + GotoInstr* goto_2 = new GotoInstr(join, Thread::kNoDeoptId); false_target->LinkTo(goto_1); false_target2->LinkTo(goto_2); false_target->set_last_instruction(goto_1); @@ -1866,8 +1869,9 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { owner_->caller_graph()->alloc_ssa_temp_index()); fallback_call->InheritDeoptTarget(zone(), call_); fallback_call->set_total_call_count(call_->CallCount()); - ReturnInstr* fallback_return = new ReturnInstr( - call_->instance_call()->token_pos(), new Value(fallback_call)); + ReturnInstr* fallback_return = + new ReturnInstr(call_->instance_call()->token_pos(), + new Value(fallback_call), Thread::kNoDeoptId); fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, fallback_call); AppendInstruction(AppendInstruction(cursor, fallback_call), @@ -2243,8 +2247,9 @@ static bool InlineGetIndexed(FlowGraph* flow_graph, Definition* array = receiver; Definition* index = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; @@ -2292,8 +2297,9 @@ static bool InlineSetIndexed(FlowGraph* flow_graph, Definition* index = call->ArgumentAt(1); Definition* stored_value = call->ArgumentAt(2); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; if (flow_graph->isolate()->type_checks()) { @@ -2429,8 +2435,9 @@ static bool InlineDoubleOp(FlowGraph* flow_graph, Definition* left = receiver; Definition* right = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); // Arguments are checked. No need for class check. BinaryDoubleOpInstr* double_bin_op = new (Z) @@ -2453,8 +2460,9 @@ static bool InlineDoubleTestOp(FlowGraph* flow_graph, return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); // Arguments are checked. No need for class check. @@ -2475,8 +2483,9 @@ static bool InlineSmiBitAndFromSmi(FlowGraph* flow_graph, Definition* left = receiver; Definition* right = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); // Right arguments is known to be smi: other._bitAndFromSmi(this); BinarySmiOpInstr* smi_op = @@ -2499,8 +2508,9 @@ static bool InlineGrowableArraySetter(FlowGraph* flow_graph, Definition* array = receiver; Definition* value = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); // This is an internal method, no need to check argument types. @@ -2585,8 +2595,9 @@ static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph, ASSERT(array_cid != kIllegalCid); Definition* array = receiver; Definition* index = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; @@ -2628,8 +2639,9 @@ static bool InlineByteArrayBaseStore(FlowGraph* flow_graph, ASSERT(array_cid != kIllegalCid); Definition* array = receiver; Definition* index = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; @@ -2794,8 +2806,9 @@ static bool InlineStringBaseCharAt(FlowGraph* flow_graph, Definition* str = receiver; Definition* index = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); @@ -2822,8 +2835,9 @@ static bool InlineStringCodeUnitAt(FlowGraph* flow_graph, Definition* str = receiver; Definition* index = call->ArgumentAt(1); - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); @@ -2935,8 +2949,9 @@ static bool InlineFloat32x4Method(FlowGraph* flow_graph, return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; switch (kind) { @@ -3053,8 +3068,9 @@ static bool InlineSimdShuffleMethod(FlowGraph* flow_graph, if (!ShouldInlineSimd()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; Definition* mask_definition = call->ArgumentAt(1); @@ -3081,8 +3097,9 @@ static bool InlineSimdShuffleMixMethod(FlowGraph* flow_graph, if (!ShouldInlineSimd()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; Definition* mask_definition = call->ArgumentAt(2); @@ -3110,8 +3127,9 @@ static bool InlineInt32x4Method(FlowGraph* flow_graph, if (!ShouldInlineSimd()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; switch (kind) { @@ -3166,8 +3184,9 @@ static bool InlineFloat64x2Method(FlowGraph* flow_graph, if (!ShouldInlineSimd()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; switch (kind) { @@ -3217,8 +3236,9 @@ static bool InlineSimdConstructor(FlowGraph* flow_graph, if (!ShouldInlineSimd()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; switch (kind) { @@ -3298,8 +3318,9 @@ static bool InlineMathCFunction(FlowGraph* flow_graph, if (!CanUnboxDouble()) { return false; } - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Instruction* cursor = *entry; @@ -3660,8 +3681,9 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, return InlineMathCFunction(flow_graph, call, kind, entry, last); case MethodRecognizer::kObjectConstructor: { - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); ASSERT(!call->HasUses()); *last = NULL; // Empty body. @@ -3676,10 +3698,11 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, if (length >= 0 && length <= Array::kMaxElements) { Value* type = new (Z) Value(call->ArgumentAt(0)); *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + call->GetBlock()->try_index(), + Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); - *last = - new (Z) CreateArrayInstr(call->token_pos(), type, num_elements); + *last = new (Z) CreateArrayInstr(call->token_pos(), type, + num_elements, call->deopt_id()); flow_graph->AppendTo( *entry, *last, call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, @@ -3707,8 +3730,9 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, } if (!type.IsNull()) { - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); *last = new (Z) ConstantInstr(type); flow_graph->AppendTo( @@ -3723,8 +3747,9 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, case MethodRecognizer::kOneByteStringSetAt: { // This is an internal method, no need to check argument types nor // range. - *entry = new (Z) TargetEntryInstr(flow_graph->allocate_block_id(), - call->GetBlock()->try_index()); + *entry = new (Z) + TargetEntryInstr(flow_graph->allocate_block_id(), + call->GetBlock()->try_index(), Thread::kNoDeoptId); (*entry)->InheritDeoptTarget(Z, call); Definition* str = call->ArgumentAt(0); Definition* index = call->ArgumentAt(1); diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index fe521dae39d..358f299bfb3 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -604,7 +604,9 @@ const Object& Value::BoundConstant() const { GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function, TargetEntryInstr* normal_entry, intptr_t osr_id) - : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex), + : BlockEntryInstr(0, + CatchClauseNode::kInvalidTryIndex, + Thread::Current()->GetNextDeoptId()), parsed_function_(parsed_function), normal_entry_(normal_entry), catch_entries_(), @@ -1109,7 +1111,8 @@ bool BlockEntryInstr::PruneUnreachable(GraphEntryInstr* graph_entry, // we can simply jump to the beginning of the block. ASSERT(instr->previous() == this); - GotoInstr* goto_join = new GotoInstr(AsJoinEntry()); + GotoInstr* goto_join = + new GotoInstr(AsJoinEntry(), Thread::Current()->GetNextDeoptId()); goto_join->CopyDeoptIdFrom(*parent); graph_entry->normal_entry()->LinkTo(goto_join); return true; @@ -1336,7 +1339,7 @@ BlockEntryInstr* GotoInstr::SuccessorAt(intptr_t index) const { void Instruction::Goto(JoinEntryInstr* entry) { - LinkTo(new GotoInstr(entry)); + LinkTo(new GotoInstr(entry, Thread::Current()->GetNextDeoptId())); } @@ -3222,8 +3225,9 @@ StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, Token::Kind kind, Value* left, Value* right, - bool needs_number_check) - : TemplateComparison(token_pos, kind, Thread::Current()->GetNextDeoptId()), + bool needs_number_check, + intptr_t deopt_id) + : TemplateComparison(token_pos, kind, deopt_id), needs_number_check_(needs_number_check) { ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); SetInputAt(0, left); @@ -3834,7 +3838,7 @@ ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, Value* new_right) { return new StrictCompareInstr(token_pos(), kind(), new_left, new_right, - needs_number_check()); + needs_number_check(), Thread::kNoDeoptId); } diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index e017cf72e4c..fdcca2fa4ea 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -1262,8 +1262,8 @@ class BlockEntryInstr : public Instruction { DEFINE_INSTRUCTION_TYPE_CHECK(BlockEntry) protected: - BlockEntryInstr(intptr_t block_id, intptr_t try_index) - : Instruction(Thread::Current()->GetNextDeoptId()), + BlockEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id) + : Instruction(deopt_id), block_id_(block_id), try_index_(try_index), preorder_number_(-1), @@ -1442,8 +1442,8 @@ class GraphEntryInstr : public BlockEntryInstr { class JoinEntryInstr : public BlockEntryInstr { public: - JoinEntryInstr(intptr_t block_id, intptr_t try_index) - : BlockEntryInstr(block_id, try_index), + JoinEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id) + : BlockEntryInstr(block_id, try_index, deopt_id), predecessors_(2), // Two is the assumed to be the common case. phis_(NULL) {} @@ -1512,8 +1512,8 @@ class PhiIterator : public ValueObject { class TargetEntryInstr : public BlockEntryInstr { public: - TargetEntryInstr(intptr_t block_id, intptr_t try_index) - : BlockEntryInstr(block_id, try_index), + TargetEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id) + : BlockEntryInstr(block_id, try_index, deopt_id), predecessor_(NULL), edge_weight_(0.0) {} @@ -1553,8 +1553,10 @@ class IndirectEntryInstr : public JoinEntryInstr { public: IndirectEntryInstr(intptr_t block_id, intptr_t indirect_id, - intptr_t try_index) - : JoinEntryInstr(block_id, try_index), indirect_id_(indirect_id) {} + intptr_t try_index, + intptr_t deopt_id) + : JoinEntryInstr(block_id, try_index, deopt_id), + indirect_id_(indirect_id) {} DECLARE_INSTRUCTION(IndirectEntry) @@ -1581,7 +1583,7 @@ class CatchBlockEntryInstr : public BlockEntryInstr { bool needs_stacktrace, intptr_t deopt_id, bool should_restore_closure_context = false) - : BlockEntryInstr(block_id, try_index), + : BlockEntryInstr(block_id, try_index, deopt_id), graph_entry_(graph_entry), predecessor_(NULL), catch_handler_types_(Array::ZoneHandle(handler_types.raw())), @@ -1591,9 +1593,7 @@ class CatchBlockEntryInstr : public BlockEntryInstr { needs_stacktrace_(needs_stacktrace), should_restore_closure_context_(should_restore_closure_context), handler_token_pos_(handler_token_pos), - is_generated_(is_generated) { - deopt_id_ = deopt_id; - } + is_generated_(is_generated) {} DECLARE_INSTRUCTION(CatchBlockEntry) @@ -2108,9 +2108,8 @@ inline Definition* Instruction::ArgumentAt(intptr_t index) const { class ReturnInstr : public TemplateInstruction<1, NoThrow> { public: - ReturnInstr(TokenPosition token_pos, Value* value) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), - token_pos_(token_pos) { + ReturnInstr(TokenPosition token_pos, Value* value, intptr_t deopt_id) + : TemplateInstruction(deopt_id), token_pos_(token_pos) { SetInputAt(0, value); } @@ -2138,9 +2137,8 @@ class ReturnInstr : public TemplateInstruction<1, NoThrow> { class ThrowInstr : public TemplateInstruction<0, Throws> { public: - explicit ThrowInstr(TokenPosition token_pos) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), - token_pos_(token_pos) {} + explicit ThrowInstr(TokenPosition token_pos, intptr_t deopt_id) + : TemplateInstruction(deopt_id), token_pos_(token_pos) {} DECLARE_INSTRUCTION(Throw) @@ -2163,8 +2161,10 @@ class ReThrowInstr : public TemplateInstruction<0, Throws> { public: // 'catch_try_index' can be CatchClauseNode::kInvalidTryIndex if the // rethrow has been artificially generated by the parser. - ReThrowInstr(TokenPosition token_pos, intptr_t catch_try_index) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), + ReThrowInstr(TokenPosition token_pos, + intptr_t catch_try_index, + intptr_t deopt_id) + : TemplateInstruction(deopt_id), token_pos_(token_pos), catch_try_index_(catch_try_index) {} @@ -2214,8 +2214,8 @@ class StopInstr : public TemplateInstruction<0, NoThrow> { class GotoInstr : public TemplateInstruction<0, NoThrow> { public: - explicit GotoInstr(JoinEntryInstr* entry) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), + explicit GotoInstr(JoinEntryInstr* entry, intptr_t deopt_id) + : TemplateInstruction(deopt_id), block_(NULL), successor_(entry), edge_weight_(0.0), @@ -2428,10 +2428,8 @@ class TemplateComparison class BranchInstr : public Instruction { public: - explicit BranchInstr(ComparisonInstr* comparison) - : Instruction(Thread::Current()->GetNextDeoptId()), - comparison_(comparison), - constant_target_(NULL) { + explicit BranchInstr(ComparisonInstr* comparison, intptr_t deopt_id) + : Instruction(deopt_id), comparison_(comparison), constant_target_(NULL) { ASSERT(comparison->env() == NULL); for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) { comparison->InputAt(i)->set_instruction(this); @@ -2710,9 +2708,8 @@ class AssertAssignableInstr : public TemplateDefinition<3, Throws, Pure> { class AssertBooleanInstr : public TemplateDefinition<1, Throws, Pure> { public: - AssertBooleanInstr(TokenPosition token_pos, Value* value) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), - token_pos_(token_pos) { + AssertBooleanInstr(TokenPosition token_pos, Value* value, intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos) { SetInputAt(0, value); } @@ -2741,8 +2738,8 @@ class AssertBooleanInstr : public TemplateDefinition<1, Throws, Pure> { // a computation, not a value, because it's mutable. class CurrentContextInstr : public TemplateDefinition<0, NoThrow> { public: - CurrentContextInstr() - : TemplateDefinition(Thread::Current()->GetNextDeoptId()) {} + explicit CurrentContextInstr(intptr_t deopt_id) + : TemplateDefinition(deopt_id) {} DECLARE_INSTRUCTION(CurrentContext) virtual CompileType ComputeType() const; @@ -2825,8 +2822,9 @@ class ClosureCallInstr : public TemplateDartCall<1> { public: ClosureCallInstr(Value* function, ClosureCallNode* node, - ZoneGrowableArray* arguments) - : TemplateDartCall(Thread::Current()->GetNextDeoptId(), + ZoneGrowableArray* arguments, + intptr_t deopt_id) + : TemplateDartCall(deopt_id, node->arguments()->type_args_len(), node->arguments()->names(), arguments, @@ -2839,8 +2837,9 @@ class ClosureCallInstr : public TemplateDartCall<1> { ZoneGrowableArray* arguments, intptr_t type_args_len, const Array& argument_names, - TokenPosition token_pos) - : TemplateDartCall(Thread::Current()->GetNextDeoptId(), + TokenPosition token_pos, + intptr_t deopt_id) + : TemplateDartCall(deopt_id, type_args_len, argument_names, arguments, @@ -2874,8 +2873,9 @@ class InstanceCallInstr : public TemplateDartCall<0> { intptr_t type_args_len, const Array& argument_names, intptr_t checked_argument_count, - const ZoneGrowableArray& ic_data_array) - : TemplateDartCall(Thread::Current()->GetNextDeoptId(), + const ZoneGrowableArray& ic_data_array, + intptr_t deopt_id) + : TemplateDartCall(deopt_id, type_args_len, argument_names, arguments, @@ -3033,7 +3033,8 @@ class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> { Token::Kind kind, Value* left, Value* right, - bool needs_number_check); + bool needs_number_check, + intptr_t deopt_id); DECLARE_INSTRUCTION(StrictCompare) @@ -3245,8 +3246,11 @@ class RelationalOpInstr : public TemplateComparison<2, NoThrow, Pure> { // materialization of true and false constants. class IfThenElseInstr : public Definition { public: - IfThenElseInstr(ComparisonInstr* comparison, Value* if_true, Value* if_false) - : Definition(Thread::Current()->GetNextDeoptId()), + IfThenElseInstr(ComparisonInstr* comparison, + Value* if_true, + Value* if_false, + intptr_t deopt_id) + : Definition(deopt_id), comparison_(comparison), if_true_(Smi::Cast(if_true->BoundConstant()).Value()), if_false_(Smi::Cast(if_false->BoundConstant()).Value()) { @@ -3328,8 +3332,9 @@ class StaticCallInstr : public TemplateDartCall<0> { intptr_t type_args_len, const Array& argument_names, ZoneGrowableArray* arguments, - const ZoneGrowableArray& ic_data_array) - : TemplateDartCall(Thread::Current()->GetNextDeoptId(), + const ZoneGrowableArray& ic_data_array, + intptr_t deopt_id) + : TemplateDartCall(deopt_id, type_args_len, argument_names, arguments, @@ -4049,8 +4054,10 @@ class StringToCharCodeInstr : public TemplateDefinition<1, NoThrow, Pure> { class StringInterpolateInstr : public TemplateDefinition<1, Throws> { public: - StringInterpolateInstr(Value* value, TokenPosition token_pos) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), + StringInterpolateInstr(Value* value, + TokenPosition token_pos, + intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos), function_(Function::ZoneHandle()) { SetInputAt(0, value); @@ -4385,8 +4392,9 @@ class CreateArrayInstr : public TemplateDefinition<2, Throws> { public: CreateArrayInstr(TokenPosition token_pos, Value* element_type, - Value* num_elements) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), + Value* num_elements, + intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos), identity_(AliasIdentity::Unknown()) { SetInputAt(kElementTypePos, element_type); @@ -4594,10 +4602,9 @@ class InstantiateTypeInstr : public TemplateDefinition<2, Throws> { InstantiateTypeInstr(TokenPosition token_pos, const AbstractType& type, Value* instantiator_type_arguments, - Value* function_type_arguments) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), - token_pos_(token_pos), - type_(type) { + Value* function_type_arguments, + intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos), type_(type) { ASSERT(type.IsZoneHandle() || type.IsReadOnlyHandle()); SetInputAt(0, instantiator_type_arguments); SetInputAt(1, function_type_arguments); @@ -4630,8 +4637,9 @@ class InstantiateTypeArgumentsInstr : public TemplateDefinition<2, Throws> { const TypeArguments& type_arguments, const Class& instantiator_class, Value* instantiator_type_arguments, - Value* function_type_arguments) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), + Value* function_type_arguments, + intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos), type_arguments_(type_arguments), instantiator_class_(instantiator_class) { @@ -4692,9 +4700,8 @@ class AllocateContextInstr : public TemplateDefinition<0, NoThrow> { class InitStaticFieldInstr : public TemplateInstruction<1, Throws> { public: - InitStaticFieldInstr(Value* input, const Field& field) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), - field_(field) { + InitStaticFieldInstr(Value* input, const Field& field, intptr_t deopt_id) + : TemplateInstruction(deopt_id), field_(field) { SetInputAt(0, input); CheckField(field); } @@ -4717,9 +4724,10 @@ class InitStaticFieldInstr : public TemplateInstruction<1, Throws> { class CloneContextInstr : public TemplateDefinition<1, NoThrow> { public: - CloneContextInstr(TokenPosition token_pos, Value* context_value) - : TemplateDefinition(Thread::Current()->GetNextDeoptId()), - token_pos_(token_pos) { + CloneContextInstr(TokenPosition token_pos, + Value* context_value, + intptr_t deopt_id) + : TemplateDefinition(deopt_id), token_pos_(token_pos) { SetInputAt(0, context_value); } @@ -7254,8 +7262,10 @@ class UnaryDoubleOpInstr : public TemplateDefinition<1, NoThrow, Pure> { class CheckStackOverflowInstr : public TemplateInstruction<0, NoThrow> { public: - CheckStackOverflowInstr(TokenPosition token_pos, intptr_t loop_depth) - : TemplateInstruction(Thread::Current()->GetNextDeoptId()), + CheckStackOverflowInstr(TokenPosition token_pos, + intptr_t loop_depth, + intptr_t deopt_id) + : TemplateInstruction(deopt_id), token_pos_(token_pos), loop_depth_(loop_depth) {} diff --git a/runtime/vm/intermediate_language_test.cc b/runtime/vm/intermediate_language_test.cc index 61b9e0507e3..46b916f451a 100644 --- a/runtime/vm/intermediate_language_test.cc +++ b/runtime/vm/intermediate_language_test.cc @@ -8,19 +8,19 @@ namespace dart { TEST_CASE(InstructionTests) { - TargetEntryInstr* target_instr = - new TargetEntryInstr(1, CatchClauseNode::kInvalidTryIndex); + TargetEntryInstr* target_instr = new TargetEntryInstr( + 1, CatchClauseNode::kInvalidTryIndex, Thread::kNoDeoptId); EXPECT(target_instr->IsBlockEntry()); EXPECT(!target_instr->IsDefinition()); - CurrentContextInstr* context = new CurrentContextInstr(); + CurrentContextInstr* context = new CurrentContextInstr(Thread::kNoDeoptId); EXPECT(context->IsDefinition()); EXPECT(!context->IsBlockEntry()); } TEST_CASE(OptimizationTests) { - JoinEntryInstr* join = - new JoinEntryInstr(1, CatchClauseNode::kInvalidTryIndex); + JoinEntryInstr* join = new JoinEntryInstr( + 1, CatchClauseNode::kInvalidTryIndex, Thread::kNoDeoptId); Definition* def1 = new PhiInstr(join, 0); Definition* def2 = new PhiInstr(join, 0); diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc index 0ef00b27fd4..de5ccd2282c 100644 --- a/runtime/vm/intrinsifier.cc +++ b/runtime/vm/intrinsifier.cc @@ -170,7 +170,8 @@ bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function, intptr_t block_id = builder.AllocateBlockId(); TargetEntryInstr* normal_entry = - new TargetEntryInstr(block_id, CatchClauseNode::kInvalidTryIndex); + new TargetEntryInstr(block_id, CatchClauseNode::kInvalidTryIndex, + Thread::Current()->GetNextDeoptId()); GraphEntryInstr* graph_entry = new GraphEntryInstr( parsed_function, normal_entry, Compiler::kNoOSRDeoptId); FlowGraph* graph = new FlowGraph(parsed_function, graph_entry, block_id); @@ -318,7 +319,8 @@ class BlockBuilder : public ValueObject { } void AddIntrinsicReturn(Value* value) { - ReturnInstr* instr = new ReturnInstr(TokenPos(), value); + ReturnInstr* instr = + new ReturnInstr(TokenPos(), value, Thread::Current()->GetNextDeoptId()); AddInstruction(instr); entry_->set_last_instruction(instr); } diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc index 151e187e1e5..ed052448065 100644 --- a/runtime/vm/jit_optimizer.cc +++ b/runtime/vm/jit_optimizer.cc @@ -602,7 +602,7 @@ bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, StrictCompareInstr* comp = new (Z) StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, new (Z) Value(left), new (Z) Value(right), - false); // No number check. + /* number_check = */ false, Thread::kNoDeoptId); ReplaceCall(call, comp); return true; } @@ -1356,10 +1356,9 @@ void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { ConstantInstr* cid = flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); - StrictCompareInstr* check_cid = - new (Z) StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT, - new (Z) Value(left_cid), new (Z) Value(cid), - false); // No number check. + StrictCompareInstr* check_cid = new (Z) StrictCompareInstr( + call->token_pos(), Token::kEQ_STRICT, new (Z) Value(left_cid), + new (Z) Value(cid), /* number_check = */ false, Thread::kNoDeoptId); ReplaceCall(call, check_cid); return; } diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc index e6a41fc2fa1..9e39c23f5ff 100644 --- a/runtime/vm/kernel_binary_flowgraph.cc +++ b/runtime/vm/kernel_binary_flowgraph.cc @@ -3554,7 +3554,7 @@ Fragment StreamingFlowGraphBuilder::BuildWhileStatement() { Fragment loop(join); loop += CheckStackOverflow(); loop += condition; - entry = new (Z) GotoInstr(join); + entry = new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()); } else { entry = condition.entry; } @@ -3588,7 +3588,8 @@ Fragment StreamingFlowGraphBuilder::BuildDoStatement() { repeat += Goto(join); loop_depth_dec(); - return Fragment(new (Z) GotoInstr(join), loop_exit); + return Fragment(new (Z) GotoInstr(join, Thread::Current()->GetNextDeoptId()), + loop_exit); } Fragment StreamingFlowGraphBuilder::BuildForStatement() { diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc index e55dc92fa80..f28bad745a3 100644 --- a/runtime/vm/kernel_to_il.cc +++ b/runtime/vm/kernel_to_il.cc @@ -2017,6 +2017,7 @@ FlowGraphBuilder::FlowGraphBuilder( intptr_t osr_id, intptr_t first_block_id) : translation_helper_(Thread::Current()), + thread_(translation_helper_.thread()), zone_(translation_helper_.zone()), node_(node), parsed_function_(parsed_function), @@ -2248,9 +2249,9 @@ Fragment FlowGraphBuilder::LoadFunctionTypeArguments() { Fragment FlowGraphBuilder::InstantiateType(const AbstractType& type) { Value* function_type_args = Pop(); Value* instantiator_type_args = Pop(); - InstantiateTypeInstr* instr = - new (Z) InstantiateTypeInstr(TokenPosition::kNoSource, type, - instantiator_type_args, function_type_args); + InstantiateTypeInstr* instr = new (Z) InstantiateTypeInstr( + TokenPosition::kNoSource, type, instantiator_type_args, + function_type_args, GetNextDeoptId()); Push(instr); return Fragment(instr); } @@ -2262,7 +2263,7 @@ Fragment FlowGraphBuilder::InstantiateTypeArguments( Value* instantiator_type_args = Pop(); InstantiateTypeArgumentsInstr* instr = new (Z) InstantiateTypeArgumentsInstr( TokenPosition::kNoSource, type_arguments, *active_class_.klass, - instantiator_type_args, function_type_args); + instantiator_type_args, function_type_args, GetNextDeoptId()); Push(instr); return Fragment(instr); } @@ -2352,8 +2353,9 @@ Fragment FlowGraphBuilder::StrictCompare(Token::Kind kind, bool number_check /* = false */) { Value* right = Pop(); Value* left = Pop(); - StrictCompareInstr* compare = new (Z) StrictCompareInstr( - TokenPosition::kNoSource, kind, left, right, number_check); + StrictCompareInstr* compare = + new (Z) StrictCompareInstr(TokenPosition::kNoSource, kind, left, right, + number_check, GetNextDeoptId()); Push(compare); return Fragment(compare); } @@ -2381,8 +2383,8 @@ Fragment FlowGraphBuilder::BranchIfEqual(TargetEntryInstr** then_entry, Value* left_value = Pop(); StrictCompareInstr* compare = new (Z) StrictCompareInstr( TokenPosition::kNoSource, negate ? Token::kNE_STRICT : Token::kEQ_STRICT, - left_value, right_value, false); - BranchInstr* branch = new (Z) BranchInstr(compare); + left_value, right_value, false, GetNextDeoptId()); + BranchInstr* branch = new (Z) BranchInstr(compare, GetNextDeoptId()); *then_entry = *branch->true_successor_address() = BuildTargetEntry(); *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry(); return Fragment(branch).closed(); @@ -2394,9 +2396,10 @@ Fragment FlowGraphBuilder::BranchIfStrictEqual( TargetEntryInstr** otherwise_entry) { Value* rhs = Pop(); Value* lhs = Pop(); - StrictCompareInstr* compare = new (Z) StrictCompareInstr( - TokenPosition::kNoSource, Token::kEQ_STRICT, lhs, rhs, false); - BranchInstr* branch = new (Z) BranchInstr(compare); + StrictCompareInstr* compare = + new (Z) StrictCompareInstr(TokenPosition::kNoSource, Token::kEQ_STRICT, + lhs, rhs, false, GetNextDeoptId()); + BranchInstr* branch = new (Z) BranchInstr(compare, GetNextDeoptId()); *then_entry = *branch->true_successor_address() = BuildTargetEntry(); *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry(); return Fragment(branch).closed(); @@ -2446,8 +2449,8 @@ Fragment FlowGraphBuilder::TryCatch(int try_handler_index) { // => We therefore create a block for the body (fresh try index) and another // join block (with current try index). Fragment body; - JoinEntryInstr* entry = - new (Z) JoinEntryInstr(AllocateBlockId(), try_handler_index); + JoinEntryInstr* entry = new (Z) + JoinEntryInstr(AllocateBlockId(), try_handler_index, GetNextDeoptId()); body += LoadLocal(parsed_function_->current_context_var()); body += StoreLocal(TokenPosition::kNoSource, CurrentCatchContext()); body += Drop(); @@ -2468,8 +2471,8 @@ Fragment FlowGraphBuilder::CheckStackOverflowInPrologue() { Fragment FlowGraphBuilder::CheckStackOverflow() { - return Fragment( - new (Z) CheckStackOverflowInstr(TokenPosition::kNoSource, loop_depth_)); + return Fragment(new (Z) CheckStackOverflowInstr( + TokenPosition::kNoSource, loop_depth_, GetNextDeoptId())); } @@ -2478,8 +2481,8 @@ Fragment FlowGraphBuilder::CloneContext() { Fragment instructions = LoadLocal(context_variable); - CloneContextInstr* clone_instruction = - new (Z) CloneContextInstr(TokenPosition::kNoSource, Pop()); + CloneContextInstr* clone_instruction = new (Z) + CloneContextInstr(TokenPosition::kNoSource, Pop(), GetNextDeoptId()); instructions <<= clone_instruction; Push(clone_instruction); @@ -2499,16 +2502,17 @@ Fragment FlowGraphBuilder::Constant(const Object& value) { Fragment FlowGraphBuilder::CreateArray() { Value* element_count = Pop(); - CreateArrayInstr* array = new (Z) CreateArrayInstr(TokenPosition::kNoSource, - Pop(), // Element type. - element_count); + CreateArrayInstr* array = + new (Z) CreateArrayInstr(TokenPosition::kNoSource, + Pop(), // Element type. + element_count, GetNextDeoptId()); Push(array); return Fragment(array); } Fragment FlowGraphBuilder::Goto(JoinEntryInstr* destination) { - return Fragment(new (Z) GotoInstr(destination)).closed(); + return Fragment(new (Z) GotoInstr(destination, GetNextDeoptId())).closed(); } @@ -2536,9 +2540,9 @@ Fragment FlowGraphBuilder::InstanceCall(TokenPosition position, intptr_t num_args_checked) { ArgumentArray arguments = GetArguments(argument_count); const intptr_t kTypeArgsLen = 0; // Generic instance calls not yet supported. - InstanceCallInstr* call = new (Z) - InstanceCallInstr(position, name, kind, arguments, kTypeArgsLen, - argument_names, num_args_checked, ic_data_array_); + InstanceCallInstr* call = new (Z) InstanceCallInstr( + position, name, kind, arguments, kTypeArgsLen, argument_names, + num_args_checked, ic_data_array_, GetNextDeoptId()); Push(call); return Fragment(call); } @@ -2549,9 +2553,9 @@ Fragment FlowGraphBuilder::ClosureCall(int argument_count, Value* function = Pop(); ArgumentArray arguments = GetArguments(argument_count); const intptr_t kTypeArgsLen = 0; // Generic closures not yet supported. - ClosureCallInstr* call = - new (Z) ClosureCallInstr(function, arguments, kTypeArgsLen, - argument_names, TokenPosition::kNoSource); + ClosureCallInstr* call = new (Z) + ClosureCallInstr(function, arguments, kTypeArgsLen, argument_names, + TokenPosition::kNoSource, GetNextDeoptId()); Push(call); return Fragment(call); } @@ -2560,7 +2564,8 @@ Fragment FlowGraphBuilder::ClosureCall(int argument_count, Fragment FlowGraphBuilder::ThrowException(TokenPosition position) { Fragment instructions; instructions += Drop(); - instructions += Fragment(new (Z) ThrowInstr(position)).closed(); + instructions += + Fragment(new (Z) ThrowInstr(position, GetNextDeoptId())).closed(); // Use it's side effect of leaving a constant on the stack (does not change // the graph). NullConstant(); @@ -2576,8 +2581,9 @@ Fragment FlowGraphBuilder::RethrowException(TokenPosition position, Fragment instructions; instructions += Drop(); instructions += Drop(); - instructions += - Fragment(new (Z) ReThrowInstr(position, catch_try_index)).closed(); + instructions += Fragment(new (Z) ReThrowInstr(position, catch_try_index, + GetNextDeoptId())) + .closed(); // Use it's side effect of leaving a constant on the stack (does not change // the graph). NullConstant(); @@ -2657,8 +2663,8 @@ Fragment FlowGraphBuilder::LoadLocal(LocalVariable* variable) { Fragment FlowGraphBuilder::InitStaticField(const dart::Field& field) { - InitStaticFieldInstr* init = - new (Z) InitStaticFieldInstr(Pop(), MayCloneField(Z, field)); + InitStaticFieldInstr* init = new (Z) + InitStaticFieldInstr(Pop(), MayCloneField(Z, field), GetNextDeoptId()); return Fragment(init); } @@ -2721,7 +2727,8 @@ Fragment FlowGraphBuilder::Return(TokenPosition position) { instructions += Drop(); } - ReturnInstr* return_instr = new (Z) ReturnInstr(position, value); + ReturnInstr* return_instr = + new (Z) ReturnInstr(position, value, GetNextDeoptId()); if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr); instructions <<= return_instr; @@ -2767,7 +2774,7 @@ Fragment FlowGraphBuilder::StaticCall(TokenPosition position, const intptr_t kTypeArgsLen = 0; // Generic static calls not yet supported. StaticCallInstr* call = new (Z) StaticCallInstr(position, target, kTypeArgsLen, argument_names, - arguments, ic_data_array_); + arguments, ic_data_array_, GetNextDeoptId()); const intptr_t list_cid = GetResultCidOfListFactory(Z, target, argument_count); if (list_cid != kDynamicCid) { @@ -2881,7 +2888,7 @@ Fragment FlowGraphBuilder::StoreStaticField(TokenPosition position, Fragment FlowGraphBuilder::StringInterpolate(TokenPosition position) { Value* array = Pop(); StringInterpolateInstr* interpolate = - new (Z) StringInterpolateInstr(array, position); + new (Z) StringInterpolateInstr(array, position, GetNextDeoptId()); Push(interpolate); return Fragment(interpolate); } @@ -3931,8 +3938,8 @@ Fragment FlowGraphBuilder::CheckAssignableInCheckedMode( Fragment FlowGraphBuilder::AssertBool() { Value* value = Pop(); - AssertBooleanInstr* instr = - new (Z) AssertBooleanInstr(TokenPosition::kNoSource, value); + AssertBooleanInstr* instr = new (Z) + AssertBooleanInstr(TokenPosition::kNoSource, value, GetNextDeoptId()); Push(instr); return Fragment(instr); } @@ -4271,17 +4278,19 @@ void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) { TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() { - return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex()); + return new (Z) + TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); } JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry(intptr_t try_index) { - return new (Z) JoinEntryInstr(AllocateBlockId(), try_index); + return new (Z) JoinEntryInstr(AllocateBlockId(), try_index, GetNextDeoptId()); } JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() { - return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex()); + return new (Z) + JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId()); } @@ -5869,7 +5878,7 @@ void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) { Fragment loop(join); loop += CheckStackOverflow(); loop += condition; - entry = new (Z) GotoInstr(join); + entry = new (Z) GotoInstr(join, GetNextDeoptId()); } else { entry = condition.entry; } @@ -5905,7 +5914,7 @@ void FlowGraphBuilder::VisitDoStatement(DoStatement* node) { Fragment repeat(loop_repeat); repeat += Goto(join); - fragment_ = Fragment(new (Z) GotoInstr(join), loop_exit); + fragment_ = Fragment(new (Z) GotoInstr(join, GetNextDeoptId()), loop_exit); --loop_depth_; } diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h index ae0db180c64..cc3f0069abb 100644 --- a/runtime/vm/kernel_to_il.h +++ b/runtime/vm/kernel_to_il.h @@ -1042,6 +1042,7 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { void InlineBailout(const char* reason); TranslationHelper translation_helper_; + Thread* thread_; Zone* zone_; // The node we are currently compiling (e.g. FunctionNode, Constructor, @@ -1056,6 +1057,11 @@ class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor { intptr_t next_block_id_; intptr_t AllocateBlockId() { return next_block_id_++; } + intptr_t GetNextDeoptId() { + // TODO(rmacnak): Record current scope / context level. + return thread_->GetNextDeoptId(); + } + intptr_t next_function_id_; intptr_t AllocateFunctionId() { return next_function_id_++; } diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc index df8a650484c..588fa8702f1 100644 --- a/runtime/vm/regexp_assembler.cc +++ b/runtime/vm/regexp_assembler.cc @@ -13,7 +13,7 @@ BlockLabel::BlockLabel() : block_(NULL), is_bound_(false), is_linked_(false), pos_(-1) { if (!FLAG_interpret_irregexp) { // Only needed by the compiled IR backend. - block_ = new JoinEntryInstr(-1, -1); + block_ = new JoinEntryInstr(-1, -1, Thread::Current()->GetNextDeoptId()); } } diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc index 23aa5233dbe..2bdc701b831 100644 --- a/runtime/vm/regexp_assembler_ir.cc +++ b/runtime/vm/regexp_assembler_ir.cc @@ -80,6 +80,7 @@ IRRegExpMacroAssembler::IRRegExpMacroAssembler( const ZoneGrowableArray& ic_data_array, Zone* zone) : RegExpMacroAssembler(zone), + thread_(Thread::Current()), specialization_cid_(specialization_cid), parsed_function_(parsed_function), ic_data_array_(ic_data_array), @@ -122,14 +123,17 @@ IRRegExpMacroAssembler::IRRegExpMacroAssembler( // Create and generate all preset blocks. entry_block_ = new (zone) GraphEntryInstr( *parsed_function_, - new (zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex), + new (zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, + GetNextDeoptId()), Compiler::kNoOSRDeoptId); - start_block_ = new (zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex); - success_block_ = - new (zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex); - backtrack_block_ = - new (zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex); - exit_block_ = new (zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex); + start_block_ = new (zone) + JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); + success_block_ = new (zone) + JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); + backtrack_block_ = new (zone) + JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); + exit_block_ = new (zone) + JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); GenerateEntryBlock(); GenerateSuccessBlock(); @@ -252,8 +256,8 @@ void IRRegExpMacroAssembler::GenerateSuccessBlock() { Value* type = Bind(new (Z) ConstantInstr( TypeArguments::ZoneHandle(Z, TypeArguments::null()))); Value* length = Bind(Uint64Constant(saved_registers_count_)); - Value* array = - Bind(new (Z) CreateArrayInstr(TokenPosition::kNoSource, type, length)); + Value* array = Bind(new (Z) CreateArrayInstr(TokenPosition::kNoSource, type, + length, GetNextDeoptId())); StoreLocal(result_, array); // Store captured offsets in the `matches` parameter. @@ -276,8 +280,8 @@ void IRRegExpMacroAssembler::GenerateSuccessBlock() { PRINT(PushLocal(result_)); // Return true on success. - AppendInstruction( - new (Z) ReturnInstr(TokenPosition::kNoSource, Bind(LoadLocal(result_)))); + AppendInstruction(new (Z) ReturnInstr( + TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); } @@ -286,8 +290,8 @@ void IRRegExpMacroAssembler::GenerateExitBlock() { TAG(); // Return false on failure. - AppendInstruction( - new (Z) ReturnInstr(TokenPosition::kNoSource, Bind(LoadLocal(result_)))); + AppendInstruction(new (Z) ReturnInstr( + TokenPosition::kNoSource, Bind(LoadLocal(result_)), GetNextDeoptId())); } @@ -489,8 +493,9 @@ ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, InstanceCallDescriptor::FromToken(intermediate_operator), lhs, rhs)); Value* rhs_value = Bind(BoolConstant(true)); - return new (Z) StrictCompareInstr(TokenPosition::kNoSource, strict_comparison, - lhs_value, rhs_value, true); + return new (Z) + StrictCompareInstr(TokenPosition::kNoSource, strict_comparison, lhs_value, + rhs_value, true, GetNextDeoptId()); } ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, @@ -538,9 +543,9 @@ StaticCallInstr* IRRegExpMacroAssembler::StaticCall( const Function& function, ZoneGrowableArray* arguments) const { const intptr_t kTypeArgsLen = 0; - return new (Z) - StaticCallInstr(TokenPosition::kNoSource, function, kTypeArgsLen, - Object::null_array(), arguments, ic_data_array_); + return new (Z) StaticCallInstr(TokenPosition::kNoSource, function, + kTypeArgsLen, Object::null_array(), arguments, + ic_data_array_, GetNextDeoptId()); } @@ -587,10 +592,10 @@ InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( const InstanceCallDescriptor& desc, ZoneGrowableArray* arguments) const { const intptr_t kTypeArgsLen = 0; - return new (Z) - InstanceCallInstr(TokenPosition::kNoSource, desc.name, desc.token_kind, - arguments, kTypeArgsLen, Object::null_array(), - desc.checked_argument_count, ic_data_array_); + return new (Z) InstanceCallInstr( + TokenPosition::kNoSource, desc.name, desc.token_kind, arguments, + kTypeArgsLen, Object::null_array(), desc.checked_argument_count, + ic_data_array_, GetNextDeoptId()); } @@ -1571,8 +1576,8 @@ void IRRegExpMacroAssembler::CheckStackLimit() { PushArgumentInstr* capacity_push = PushArgument(Bind(Sub( length_push, PushArgument(Bind(Uint64Constant(stack_limit_slack())))))); PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); - BranchInstr* branch = - new (Z) BranchInstr(Comparison(kGT, capacity_push, stack_pointer_push)); + BranchInstr* branch = new (Z) BranchInstr( + Comparison(kGT, capacity_push, stack_pointer_push), GetNextDeoptId()); CloseBlockWith(branch); BlockLabel grow_stack; @@ -1728,7 +1733,7 @@ void IRRegExpMacroAssembler::BranchOrBacktrack(ComparisonInstr* comparison, // If the condition is not true, fall through to a new block. BlockLabel fallthrough; - BranchInstr* branch = new (Z) BranchInstr(comparison); + BranchInstr* branch = new (Z) BranchInstr(comparison, GetNextDeoptId()); *branch->true_successor_address() = TargetWithJoinGoto(true_successor_block); *branch->false_successor_address() = TargetWithJoinGoto(fallthrough.block()); @@ -1739,11 +1744,11 @@ void IRRegExpMacroAssembler::BranchOrBacktrack(ComparisonInstr* comparison, TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto( JoinEntryInstr* dst) { - TargetEntryInstr* target = - new (Z) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex); + TargetEntryInstr* target = new (Z) + TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex, GetNextDeoptId()); blocks_.Add(target); - target->AppendInstruction(new (Z) GotoInstr(dst)); + target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); return target; } @@ -1751,11 +1756,12 @@ TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto( IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto( JoinEntryInstr* dst) { - IndirectEntryInstr* target = new (Z) IndirectEntryInstr( - block_id_.Alloc(), indirect_id_.Alloc(), kInvalidTryIndex); + IndirectEntryInstr* target = + new (Z) IndirectEntryInstr(block_id_.Alloc(), indirect_id_.Alloc(), + kInvalidTryIndex, GetNextDeoptId()); blocks_.Add(target); - target->AppendInstruction(new (Z) GotoInstr(dst)); + target->AppendInstruction(new (Z) GotoInstr(dst, GetNextDeoptId())); return target; } @@ -1763,8 +1769,8 @@ IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto( void IRRegExpMacroAssembler::CheckPreemption() { TAG(); - AppendInstruction(new (Z) - CheckStackOverflowInstr(TokenPosition::kNoSource, 0)); + AppendInstruction(new (Z) CheckStackOverflowInstr(TokenPosition::kNoSource, 0, + GetNextDeoptId())); } diff --git a/runtime/vm/regexp_assembler_ir.h b/runtime/vm/regexp_assembler_ir.h index ae709522012..8dbb4abe992 100644 --- a/runtime/vm/regexp_assembler_ir.h +++ b/runtime/vm/regexp_assembler_ir.h @@ -132,6 +132,8 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { void FinalizeRegistersArray(); private: + intptr_t GetNextDeoptId() const { return thread_->GetNextDeoptId(); } + // Generate the contents of preset blocks. The entry block is the entry point // of the generated code. void GenerateEntryBlock(); @@ -359,6 +361,8 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { intptr_t next_id; }; + Thread* thread_; + // Which mode to generate code for (ASCII or UC16). Mode mode_; diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc index 75b94dd9236..3a9b2d8414b 100644 --- a/runtime/vm/simulator_dbc.cc +++ b/runtime/vm/simulator_dbc.cc @@ -2955,33 +2955,36 @@ RawObject* Simulator::Call(const Code& code, { BYTECODE(CreateArrayOpt, A_B_C); - const intptr_t length = Smi::Value(RAW_CAST(Smi, FP[rB])); - if (LIKELY(static_cast(length) <= Array::kMaxElements)) { - const intptr_t fixed_size_plus_alignment_padding = - sizeof(RawArray) + kObjectAlignment - 1; - const intptr_t instance_size = - (fixed_size_plus_alignment_padding + length * kWordSize) & - ~(kObjectAlignment - 1); - const uword start = - thread->heap()->new_space()->TryAllocate(instance_size); - if (LIKELY(start != 0)) { - const intptr_t cid = kArrayCid; - uword tags = 0; - if (LIKELY(instance_size <= RawObject::SizeTag::kMaxSizeTag)) { - tags = RawObject::SizeTag::update(instance_size, tags); + if (LIKELY(!FP[rB]->IsHeapObject())) { + const intptr_t length = Smi::Value(RAW_CAST(Smi, FP[rB])); + if (LIKELY(static_cast(length) <= Array::kMaxElements)) { + const intptr_t fixed_size_plus_alignment_padding = + sizeof(RawArray) + kObjectAlignment - 1; + const intptr_t instance_size = + (fixed_size_plus_alignment_padding + length * kWordSize) & + ~(kObjectAlignment - 1); + const uword start = + thread->heap()->new_space()->TryAllocate(instance_size); + if (LIKELY(start != 0)) { + const intptr_t cid = kArrayCid; + uword tags = 0; + if (LIKELY(instance_size <= RawObject::SizeTag::kMaxSizeTag)) { + tags = RawObject::SizeTag::update(instance_size, tags); + } + tags = RawObject::ClassIdTag::update(cid, tags); + *reinterpret_cast(start + Instance::tags_offset()) = tags; + *reinterpret_cast(start + Array::length_offset()) = + FP[rB]; + *reinterpret_cast( + start + Array::type_arguments_offset()) = FP[rC]; + RawObject** data = + reinterpret_cast(start + Array::data_offset()); + for (intptr_t i = 0; i < length; i++) { + data[i] = null_value; + } + FP[rA] = reinterpret_cast(start + kHeapObjectTag); + pc += 4; } - tags = RawObject::ClassIdTag::update(cid, tags); - *reinterpret_cast(start + Instance::tags_offset()) = tags; - *reinterpret_cast(start + Array::length_offset()) = FP[rB]; - *reinterpret_cast(start + Array::type_arguments_offset()) = - FP[rC]; - RawObject** data = - reinterpret_cast(start + Array::data_offset()); - for (intptr_t i = 0; i < length; i++) { - data[i] = null_value; - } - FP[rA] = reinterpret_cast(start + kHeapObjectTag); - pc += 4; } } DISPATCH(); diff --git a/tests/language/vm/create_array_instr_deopt2_test.dart b/tests/language/vm/create_array_instr_deopt2_test.dart new file mode 100644 index 00000000000..437aa4c2704 --- /dev/null +++ b/tests/language/vm/create_array_instr_deopt2_test.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2017, 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=10 --no-use-osr --no-background-compilation --enable_inlining_annotations + +const NeverInline = "NeverInline"; + +foo(n) { + return new List(n); +} + +@NeverInline +bar(n) { + try { + return foo(n); + } catch (e) {} +} + +main() { + for (var i = 0; i < 20; i++) { + bar(5); + } + bar(""); +} diff --git a/tests/language/vm/create_array_instr_deopt_test.dart b/tests/language/vm/create_array_instr_deopt_test.dart new file mode 100644 index 00000000000..ed832842b8e --- /dev/null +++ b/tests/language/vm/create_array_instr_deopt_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2017, 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=10 --no-use-osr --no-background-compilation --enable_inlining_annotations + +const NeverInline = "NeverInline"; + +@NeverInline +foo(n) { + try { + return new List(n); + } catch (e) {} +} + +main() { + for (var i = 0; i < 20; i++) { + foo(5); + } + foo(""); +}