diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index 59cb8ab3e58..b9382a9e390 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -133,6 +133,7 @@ CheckClassInstr::CheckClassInstr(Value* value, unary_checks_(unary_checks), cids_(unary_checks.NumberOfChecks()), licm_hoisted_(false), + is_dense_switch_(IsDenseCidRange(unary_checks)), token_pos_(token_pos) { ASSERT(unary_checks.IsZoneHandle()); // Expected useful check data. @@ -231,14 +232,22 @@ bool CheckClassInstr::DeoptIfNotNull() const { } +bool CheckClassInstr::IsDenseCidRange(const ICData& unary_checks) { + if (unary_checks.GetReceiverClassIdAt(0) == kSmiCid) return false; + if (unary_checks.NumberOfChecks() <= 2) return false; + intptr_t max = 0; + intptr_t min = kIntptrMax; + for (intptr_t i = 0; i < unary_checks.NumberOfChecks(); ++i) { + intptr_t cid = unary_checks.GetCidAt(i); + if (cid < min) min = cid; + if (cid > max) max = cid; + } + return (max - min) < kBitsPerWord; +} + bool CheckClassInstr::IsDenseSwitch() const { - if (unary_checks().GetReceiverClassIdAt(0) == kSmiCid) return false; - if (cids_.length() > 2 && - cids_[cids_.length() - 1] - cids_[0] < kBitsPerWord) { - return true; - } - return false; + return is_dense_switch_; } diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index b0705d4e801..392993ed137 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -7805,6 +7805,7 @@ class CheckClassInstr : public TemplateInstruction<1, NoThrow> { bool DeoptIfNotNull() const; bool IsDenseSwitch() const; + static bool IsDenseCidRange(const ICData& unary_checks); intptr_t ComputeCidMask() const; static bool IsDenseMask(intptr_t mask); @@ -7823,6 +7824,7 @@ class CheckClassInstr : public TemplateInstruction<1, NoThrow> { const ICData& unary_checks_; GrowableArray cids_; // Sorted, lowest first. bool licm_hoisted_; + bool is_dense_switch_; const TokenPosition token_pos_; DISALLOW_COPY_AND_ASSIGN(CheckClassInstr); diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc index d73600b2469..8a632f16d29 100644 --- a/runtime/vm/jit_optimizer.cc +++ b/runtime/vm/jit_optimizer.cc @@ -2690,10 +2690,12 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { const ICData& unary_checks = ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); + const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks); const intptr_t max_checks = (op_kind == Token::kEQ) ? FLAG_max_equality_polymorphic_checks : FLAG_max_polymorphic_checks; if ((unary_checks.NumberOfChecks() > max_checks) && + !is_dense && flow_graph()->InstanceCallNeedsClassCheck( instr, RawFunction::kRegularFunction)) { // Too many checks, it will be megamorphic which needs unary checks. @@ -2759,7 +2761,8 @@ void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { } } - if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { + if ((unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) || + (has_one_target && is_dense)) { bool call_with_checks; if (has_one_target && FLAG_polymorphic_with_deopt) { // Type propagation has not run yet, we cannot eliminate the check.