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:
Florian Schneider
2016-04-01 09:59:27 -07:00
parent 618f46da9c
commit f6c19ee595
3 changed files with 21 additions and 7 deletions
+15 -6
View File
@@ -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_;
}
+2
View File
@@ -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);
+4 -1
View File
@@ -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.