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 .
This commit is contained in:
@@ -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_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<intptr_t> cids_; // Sorted, lowest first.
|
||||
bool licm_hoisted_;
|
||||
bool is_dense_switch_;
|
||||
const TokenPosition token_pos_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CheckClassInstr);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user