From f6c19ee595ca9495c8b9520259b1cb55b2e152a6 Mon Sep 17 00:00:00 2001 From: Florian Schneider Date: Fri, 1 Apr 2016 09:59:27 -0700 Subject: [PATCH] VM: Improve single-target polymorphic calls. Use the existing class-id check for dense ranges in more places. Previously we would fall back to megamorphic lookup with >4 cids, even though we can check cid ranges up to word-size efficiently. Next step is to generalize the dense class id checks to multiple word-sizes. BUG= R=vegorov@google.com Review URL: https://codereview.chromium.org/1847293002 . --- runtime/vm/intermediate_language.cc | 21 +++++++++++++++------ runtime/vm/intermediate_language.h | 2 ++ runtime/vm/jit_optimizer.cc | 5 ++++- 3 files changed, 21 insertions(+), 7 deletions(-) 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.