Cleanup: Make CheckClassId instruction more general so it

can be used uniformly in the polymorphic inliner.

R=kustermann@google.com
BUG=

Review-Url: https://codereview.chromium.org/2891713002 .
This commit is contained in:
Erik Corry 2017-05-19 08:49:37 +02:00
parent bd01ce38ce
commit 4aa5e1d7aa
18 changed files with 142 additions and 75 deletions

View file

@ -590,6 +590,12 @@ namespace dart {
// If the class id in FP[rA] matches the class id D, then skip the
// following instruction.
//
// - CheckClassIdRange rA, D
//
// Next instruction is a Nop with S, the size of the class-id range.
// If the class id in FP[rA] is between the D D + S, then skip the
// following instruction.
//
// - CheckBitTest rA, D
//
// Skips the next 3 instructions if the object at FP[rA] is a valid class for
@ -841,6 +847,7 @@ namespace dart {
V(CheckSmi, A, reg, ___, ___) \
V(CheckEitherNonSmi, A_D, reg, reg, ___) \
V(CheckClassId, A_D, reg, num, ___) \
V(CheckClassIdRange, A_D, reg, num, ___) \
V(CheckBitTest, A_D, reg, num, ___) \
V(CheckCids, A_B_C, reg, num, num) \
V(CheckCidsByRange, A_B_C, reg, num, num) \

View file

@ -1523,13 +1523,13 @@ int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
int bias) {
intptr_t cid_start = range.cid_start;
intptr_t cid_end = range.cid_end;
if (cid_start == cid_end) {
if (range.IsSingleCid()) {
__ CompareImmediate(R2, cid_start - bias);
__ b(next_label, NE);
} else {
__ AddImmediate(R2, R2, bias - cid_start);
bias = cid_start;
__ CompareImmediate(R2, cid_end - cid_start);
__ CompareImmediate(R2, range.Extent());
__ b(next_label, HI); // Unsigned higher.
}
return bias;

View file

@ -1487,13 +1487,13 @@ int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
int bias) {
intptr_t cid_start = range.cid_start;
intptr_t cid_end = range.cid_end;
if (cid_start == cid_end) {
if (range.IsSingleCid()) {
__ CompareImmediate(R2, cid_start - bias);
__ b(next_label, NE);
} else {
__ AddImmediate(R2, bias - cid_start);
bias = cid_start;
__ CompareImmediate(R2, cid_end - cid_start);
__ CompareImmediate(R2, range.Extent());
__ b(next_label, HI); // Unsigned higher.
}
return bias;

View file

@ -1457,13 +1457,13 @@ int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
int bias) {
intptr_t cid_start = range.cid_start;
intptr_t cid_end = range.cid_end;
if (cid_start == cid_end) {
if (range.IsSingleCid()) {
__ cmpl(EDI, Immediate(cid_start - bias));
__ j(NOT_EQUAL, next_label);
} else {
__ addl(EDI, Immediate(bias - cid_start));
bias = cid_start;
__ cmpl(EDI, Immediate(cid_end - cid_start));
__ cmpl(EDI, Immediate(range.Extent()));
__ j(ABOVE, next_label); // Unsigned higher.
}
return bias;

View file

@ -1558,7 +1558,7 @@ int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
int bias) {
intptr_t cid_start = range.cid_start;
intptr_t cid_end = range.cid_end;
if (cid_start == cid_end) {
if (range.IsSingleCid()) {
__ BranchNotEqual(T2, Immediate(cid_start - bias), next_label);
} else {
__ AddImmediate(T2, T2, bias - cid_start);

View file

@ -1477,13 +1477,13 @@ int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
int bias) {
intptr_t cid_start = range.cid_start;
intptr_t cid_end = range.cid_end;
if (cid_start == cid_end) {
if (range.IsSingleCid()) {
__ cmpl(RDI, Immediate(cid_start - bias));
__ j(NOT_EQUAL, next_label);
} else {
__ addl(RDI, Immediate(bias - cid_start));
bias = cid_start;
__ cmpl(RDI, Immediate(cid_end - cid_start));
__ cmpl(RDI, Immediate(range.Extent()));
__ j(ABOVE, next_label); // Unsigned higher.
}
return bias;

View file

@ -1554,7 +1554,7 @@ bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) {
bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) {
if ((!FLAG_precompiled_mode ||
owner_->inliner_->use_speculative_inlining()) &&
target_info.cid_start == target_info.cid_end &&
target_info.IsSingleCid() &&
TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) {
owner_->inlined_ = true;
return true;
@ -1585,7 +1585,7 @@ bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) {
RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z));
redefinition->set_ssa_temp_index(
owner_->caller_graph()->alloc_ssa_temp_index());
if (target_info.cid_start == target_info.cid_end) {
if (target_info.IsSingleCid()) {
redefinition->UpdateType(CompileType::FromCid(target_info.cid_start));
}
redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry());
@ -1704,31 +1704,25 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
new (Z) LoadClassIdInstr(new (Z) Value(receiver));
load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index());
cursor = AppendInstruction(cursor, load_cid);
bool follow_with_deopt = false;
for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
const CidRange& variant = inlined_variants_[i];
bool test_is_range = (variant.cid_start != variant.cid_end);
bool test_is_range = !variant.IsSingleCid();
bool is_last_test = (i == inlined_variants_.length() - 1);
// 1. Guard the body with a class id check. We don't need any check if
// it's the last test and global analysis has told us that the call is
// complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an
// arbitrary CidRangeTarget. Currently we don't go into this branch if the
// last test is a range test - instead we set the follow_with_deopt flag.
if (is_last_test && (!test_is_range || call_->complete()) &&
non_inlined_variants_->is_empty()) {
// complete.
if (is_last_test && non_inlined_variants_->is_empty()) {
// If it is the last variant use a check class id instruction which can
// deoptimize, followed unconditionally by the body. Omit the check if
// we know that we have covered all possible classes.
if (!call_->complete()) {
ASSERT(!test_is_range); // See condition above.
RedefinitionInstr* cid_redefinition =
new RedefinitionInstr(new (Z) Value(load_cid));
cid_redefinition->set_ssa_temp_index(
owner_->caller_graph()->alloc_ssa_temp_index());
cursor = AppendInstruction(cursor, cid_redefinition);
CheckClassIdInstr* check_class_id =
new (Z) CheckClassIdInstr(new (Z) Value(cid_redefinition),
variant.cid_start, call_->deopt_id());
CheckClassIdInstr* check_class_id = new (Z) CheckClassIdInstr(
new (Z) Value(cid_redefinition), variant, call_->deopt_id());
check_class_id->InheritDeoptTarget(zone(), call_);
cursor = AppendInstruction(cursor, check_class_id);
}
@ -1770,7 +1764,6 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
}
cursor = NULL;
} else {
if (is_last_test && test_is_range) follow_with_deopt = true;
// For all variants except the last, use a branch on the loaded class
// id.
const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start));
@ -1917,14 +1910,6 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
exit_collector_->AddExit(fallback_return);
cursor = NULL;
} else {
if (follow_with_deopt) {
DeoptimizeInstr* deopt = new DeoptimizeInstr(
ICData::kDeoptPolymorphicInstanceCallTestFail, call_->deopt_id());
deopt->InheritDeoptTarget(zone(), call_);
cursor = AppendInstruction(cursor, deopt);
cursor = NULL;
}
// Remove push arguments of the call.
for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) {
PushArgumentInstr* push = call_->PushArgumentAt(i);

View file

@ -249,8 +249,8 @@ void FlowGraphTypePropagator::VisitCheckClassId(CheckClassIdInstr* check) {
LoadClassIdInstr* load_cid =
check->value()->definition()->OriginalDefinition()->AsLoadClassId();
if (load_cid != NULL) {
SetCid(load_cid->object()->definition(), check->cid());
if (load_cid != NULL && check->cids().IsSingleCid()) {
SetCid(load_cid->object()->definition(), check->cids().cid_start);
}
}

View file

@ -212,7 +212,7 @@ static void PrintTargetsHelper(BufferFormatter* f,
if (i > 0) {
f->Print(" | ");
}
if (range.cid_start == range.cid_end) {
if (range.IsSingleCid()) {
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(range.cid_start));
f->Print("%s", String::Handle(cls.Name()).ToCString());
@ -249,7 +249,7 @@ static void PrintCidsHelper(BufferFormatter* f,
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(range.cid_start));
f->Print("%s etc. ", String::Handle(cls.Name()).ToCString());
if (range.cid_start == range.cid_end) {
if (range.IsSingleCid()) {
f->Print(" cid %" Pd, range.cid_start);
} else {
f->Print(" cid %" Pd "-%" Pd, range.cid_start, range.cid_end);
@ -1055,8 +1055,17 @@ void CheckClassIdInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(cid()));
f->Print(", %s", String::Handle(cls.ScrubbedName()).ToCString());
Class::Handle(Isolate::Current()->class_table()->At(cids().cid_start));
const String& name = String::Handle(cls.ScrubbedName());
if (cids().IsSingleCid()) {
f->Print(", %s", name.ToCString());
} else {
const Class& cls2 =
Class::Handle(Isolate::Current()->class_table()->At(cids().cid_end));
const String& name2 = String::Handle(cls2.ScrubbedName());
f->Print(", cid %" Pd "-%" Pd " %s-%s", cids().cid_start, cids().cid_end,
name.ToCString(), name2.ToCString());
}
}

View file

@ -144,8 +144,8 @@ bool Value::Equals(Value* other) const {
static int OrderById(CidRange* const* a, CidRange* const* b) {
// Negative if 'a' should sort before 'b'.
ASSERT((*a)->cid_start == (*a)->cid_end);
ASSERT((*b)->cid_start == (*b)->cid_end);
ASSERT((*a)->IsSingleCid());
ASSERT((*b)->IsSingleCid());
return (*a)->cid_start - (*b)->cid_start;
}
@ -203,7 +203,7 @@ intptr_t Cids::ComputeHighestCid() const {
bool Cids::HasClassId(intptr_t cid) const {
for (int i = 0; i < length(); i++) {
if (cid_ranges_[i]->cid_start <= cid && cid <= cid_ranges_[i]->cid_end) {
if (cid_ranges_[i]->Contains(cid)) {
return true;
}
}
@ -277,7 +277,7 @@ void Cids::CreateHelper(Zone* zone,
bool Cids::IsMonomorphic() const {
if (length() != 1) return false;
return cid_ranges_[0]->cid_start == cid_ranges_[0]->cid_end;
return cid_ranges_[0]->IsSingleCid();
}
@ -301,7 +301,7 @@ CheckClassInstr::CheckClassInstr(Value* value,
ASSERT(number_of_checks > 0);
SetInputAt(0, value);
// Otherwise use CheckSmiInstr.
ASSERT(number_of_checks != 1 || cids[0].cid_start != cids[0].cid_end ||
ASSERT(number_of_checks != 1 || !cids[0].IsSingleCid() ||
cids[0].cid_start != kSmiCid);
}
@ -322,8 +322,10 @@ EffectSet CheckClassInstr::Dependencies() const {
EffectSet CheckClassIdInstr::Dependencies() const {
// Externalization of strings via the API can change the class-id.
return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization()
: EffectSet::None();
for (intptr_t i = cids_.cid_start; i <= cids_.cid_end; i++) {
if (Field::IsExternalizableCid(i)) return EffectSet::Externalization();
}
return EffectSet::None();
}
@ -376,16 +378,14 @@ intptr_t CheckClassInstr::ComputeCidMask() const {
intptr_t min = cids_.ComputeLowestCid();
intptr_t mask = 0;
for (intptr_t i = 0; i < cids_.length(); ++i) {
intptr_t cid_start = cids_[i].cid_start;
intptr_t cid_end = cids_[i].cid_end;
intptr_t run;
uintptr_t range = 1ul + cid_end - cid_start;
uintptr_t range = 1ul + cids_[i].Extent();
if (range >= kBitsPerWord) {
run = -1;
} else {
run = (1 << range) - 1;
}
mask |= run << (cid_start - min);
mask |= run << (cids_[i].cid_start - min);
}
return mask;
}
@ -2688,7 +2688,8 @@ Instruction* CheckClassInstr::Canonicalize(FlowGraph* flow_graph) {
Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) {
if (value()->BindsToConstant()) {
const Object& constant_value = value()->BoundConstant();
if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) {
if (constant_value.IsSmi() &&
cids_.Contains(Smi::Cast(constant_value).Value())) {
return NULL;
}
}

View file

@ -557,6 +557,11 @@ struct CidRange : public ZoneAllocated {
: ZoneAllocated(), cid_start(o.cid_start), cid_end(o.cid_end) {}
CidRange(intptr_t cid_start_arg, intptr_t cid_end_arg)
: cid_start(cid_start_arg), cid_end(cid_end_arg) {}
bool IsSingleCid() const { return cid_start == cid_end; }
bool Contains(intptr_t cid) { return cid_start <= cid && cid <= cid_end; }
int32_t Extent() const { return cid_end - cid_start; }
intptr_t cid_start;
intptr_t cid_end;
};
@ -7772,13 +7777,13 @@ class CheckSmiInstr : public TemplateInstruction<1, NoThrow, Pure> {
class CheckClassIdInstr : public TemplateInstruction<1, NoThrow> {
public:
CheckClassIdInstr(Value* value, intptr_t cid, intptr_t deopt_id)
: TemplateInstruction(deopt_id), cid_(cid) {
CheckClassIdInstr(Value* value, CidRange cids, intptr_t deopt_id)
: TemplateInstruction(deopt_id), cids_(cids) {
SetInputAt(0, value);
}
Value* value() const { return inputs_[0]; }
intptr_t cid() const { return cid_; }
const CidRange& cids() const { return cids_; }
DECLARE_INSTRUCTION(CheckClassId)
@ -7794,7 +7799,9 @@ class CheckClassIdInstr : public TemplateInstruction<1, NoThrow> {
PRINT_OPERANDS_TO_SUPPORT
private:
intptr_t cid_;
bool Contains(intptr_t cid) const;
CidRange cids_;
DISALLOW_COPY_AND_ASSIGN(CheckClassIdInstr);
};

View file

@ -6404,7 +6404,8 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(0, cids_.IsSingleCid() ? Location::RequiresRegister()
: Location::WritableRegister());
return summary;
}
@ -6412,8 +6413,14 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
__ CompareImmediate(value, Smi::RawValue(cid_));
__ b(deopt, NE);
if (cids_.IsSingleCid()) {
__ CompareImmediate(value, Smi::RawValue(cids_.cid_start));
__ b(deopt, NE);
} else {
__ AddImmediate(value, -Smi::RawValue(cids_.cid_start));
__ CompareImmediate(value, Smi::RawValue(cids_.Extent()));
__ b(deopt, HI); // Unsigned higher.
}
}

View file

@ -5560,7 +5560,8 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(0, cids_.IsSingleCid() ? Location::RequiresRegister()
: Location::WritableRegister());
return summary;
}
@ -5568,8 +5569,14 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
__ CompareImmediate(value, Smi::RawValue(cid_));
__ b(deopt, NE);
if (cids_.IsSingleCid()) {
__ CompareImmediate(value, Smi::RawValue(cids_.cid_start));
__ b(deopt, NE);
} else {
__ AddImmediate(value, -Smi::RawValue(cids_.cid_start));
__ CompareImmediate(value, Smi::RawValue(cids_.cid_end - cids_.cid_start));
__ b(deopt, HI); // Unsigned higher.
}
}

View file

@ -252,7 +252,7 @@ EMIT_NATIVE_CODE(PolymorphicInstanceCall,
}
bool using_ranges = false;
for (intptr_t i = 0; i < length; i++) {
if (targets_[i].cid_start != targets_[i].cid_end) {
if (!targets_[i].IsSingleCid()) {
using_ranges = true;
break;
}
@ -266,12 +266,10 @@ EMIT_NATIVE_CODE(PolymorphicInstanceCall,
}
for (intptr_t i = 0; i < length; i++) {
const Function& target = *targets_.TargetAt(i)->target;
intptr_t cid_start = targets_[i].cid_start;
intptr_t cid_end = targets_[i].cid_end;
__ Nop(compiler->ToEmbeddableCid(cid_start, this));
__ Nop(compiler->ToEmbeddableCid(targets_[i].cid_start, this));
if (using_ranges) {
__ Nop(compiler->ToEmbeddableCid(1 + cid_end - cid_start, this));
__ Nop(compiler->ToEmbeddableCid(1 + targets_[i].Extent(), this));
}
__ Nop(__ AddConstant(target));
}
@ -1490,7 +1488,14 @@ EMIT_NATIVE_CODE(CheckEitherNonSmi, 2) {
EMIT_NATIVE_CODE(CheckClassId, 1) {
__ CheckClassId(locs()->in(0).reg(), compiler->ToEmbeddableCid(cid_, this));
if (cids_.IsSingleCid()) {
__ CheckClassId(locs()->in(0).reg(),
compiler->ToEmbeddableCid(cids_.cid_start, this));
} else {
__ CheckClassIdRange(locs()->in(0).reg(),
compiler->ToEmbeddableCid(cids_.cid_start, this));
__ Nop(__ AddConstant(Smi::Handle(Smi::New(cids_.Extent()))));
}
compiler->EmitDeopt(deopt_id(), ICData::kDeoptCheckClass);
}
@ -1523,7 +1528,7 @@ EMIT_NATIVE_CODE(CheckClass, 1) {
int smi_adjustment = 0;
int length = cids_.length();
for (intptr_t i = 0; i < length; i++) {
if (cids_[i].cid_start != cids_[i].cid_end) {
if (!cids_[i].IsSingleCid()) {
using_ranges = true;
} else if (cids_[i].cid_start == kSmiCid) {
ASSERT(cids_[i].cid_end == kSmiCid); // We are in the else clause.
@ -1550,7 +1555,7 @@ EMIT_NATIVE_CODE(CheckClass, 1) {
}
__ Nop(compiler->ToEmbeddableCid(cid_start, this));
if (using_ranges) {
__ Nop(compiler->ToEmbeddableCid(1 + cid_end - cid_start, this));
__ Nop(compiler->ToEmbeddableCid(1 + cids_[i].Extent(), this));
}
}
}

View file

@ -5928,7 +5928,8 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(0, cids_.IsSingleCid() ? Location::RequiresRegister()
: Location::WritableRegister());
return summary;
}
@ -5936,8 +5937,14 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
__ cmpl(value, Immediate(Smi::RawValue(cid_)));
__ j(NOT_ZERO, deopt);
if (cids_.IsSingleCid()) {
__ cmpl(value, Immediate(Smi::RawValue(cids_.cid_start)));
__ j(NOT_ZERO, deopt);
} else {
__ AddImmediate(value, Immediate(-Smi::RawValue(cids_.cid_start)));
__ cmpl(value, Immediate(Smi::RawValue(cids_.Extent())));
__ j(ABOVE, deopt);
}
}

View file

@ -5171,7 +5171,9 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(0, cids_.IsSingleCid() ? Location::RequiresRegister()
: Location::WritableRegister());
return summary;
}
@ -5179,7 +5181,18 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
__ BranchNotEqual(value, Immediate(Smi::RawValue(cid_)), deopt);
if (cids_.IsSingleCid()) {
__ BranchNotEqual(value, Immediate(Smi::RawValue(cids_.cid_start)), deopt);
} else {
__ AddImmediate(value, value, -Smi::RawValue(cids_.cid_start));
// TODO(erikcorry): We should use sltiu instead of the temporary TMP if
// the range is small enough.
__ LoadImmediate(TMP, cids_.Extent());
// Reverse comparison so we get 1 if biased_cid > tmp ie cid is out of
// range.
__ sltu(TMP, TMP, value);
__ bne(TMP, ZR, deopt);
}
}

View file

@ -5909,7 +5909,8 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
const intptr_t kNumTemps = 0;
LocationSummary* summary = new (zone)
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(0, cids_.IsSingleCid() ? Location::RequiresRegister()
: Location::WritableRegister());
return summary;
}
@ -5917,8 +5918,14 @@ LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
__ CompareImmediate(value, Immediate(Smi::RawValue(cid_)));
__ j(NOT_ZERO, deopt);
if (cids_.IsSingleCid()) {
__ CompareImmediate(value, Immediate(Smi::RawValue(cids_.cid_start)));
__ j(NOT_ZERO, deopt);
} else {
__ AddImmediate(value, Immediate(-Smi::RawValue(cids_.cid_start)));
__ cmpq(value, Immediate(Smi::RawValue(cids_.Extent())));
__ j(ABOVE, deopt);
}
}

View file

@ -3253,6 +3253,18 @@ RawObject* Simulator::Call(const Code& code,
DISPATCH();
}
{
BYTECODE(CheckClassIdRange, A_D);
const intptr_t actual_cid =
reinterpret_cast<intptr_t>(FP[rA]) >> kSmiTagSize;
const uintptr_t cid_start = rD;
const uintptr_t cid_range = Bytecode::DecodeD(*pc);
// Unsigned comparison. Skip either just the nop or both the nop and the
// following instruction.
pc += (actual_cid - cid_start <= cid_range) ? 2 : 1;
DISPATCH();
}
{
BYTECODE(CheckBitTest, A_D);
const intptr_t raw_value = reinterpret_cast<intptr_t>(FP[rA]);