[vm, compiler] Implement exactness tracking for all architectures.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/34170
Change-Id: Ibc6924e138a3c885478f17e66555992ea7e134b6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322062
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2023-08-22 18:22:29 +00:00
committed by Commit Queue
parent 8c2f088481
commit 4fb7b66b8c
12 changed files with 264 additions and 60 deletions
@@ -1469,7 +1469,6 @@ void FlowGraphCompiler::GenerateNonLazyDeoptableStubCall(
static const Code& StubEntryFor(const ICData& ic_data, bool optimized) {
switch (ic_data.NumArgsTested()) {
case 1:
#if defined(TARGET_ARCH_X64)
if (ic_data.is_tracking_exactness()) {
if (optimized) {
return StubCode::OneArgOptimizedCheckInlineCacheWithExactnessCheck();
@@ -1477,10 +1476,6 @@ static const Code& StubEntryFor(const ICData& ic_data, bool optimized) {
return StubCode::OneArgCheckInlineCacheWithExactnessCheck();
}
}
#else
// TODO(dartbug.com/34170) Port exactness tracking to other platforms.
ASSERT(!ic_data.is_tracking_exactness());
#endif
return optimized ? StubCode::OneArgOptimizedCheckInlineCache()
: StubCode::OneArgCheckInlineCache();
case 2:
+19
View File
@@ -6358,6 +6358,25 @@ Instruction* CheckConditionInstr::Canonicalize(FlowGraph* graph) {
return this;
}
LocationSummary* CheckConditionInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
comparison()->InitializeLocationSummary(zone, opt);
comparison()->locs()->set_out(0, Location::NoLocation());
return comparison()->locs();
}
void CheckConditionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler::Label if_true;
compiler::Label* if_false =
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnknown);
BranchLabels labels = {&if_true, if_false, &if_true};
Condition true_condition = comparison()->EmitComparisonCode(compiler, labels);
if (true_condition != kInvalidCondition) {
__ BranchIf(InvertCondition(true_condition), if_false);
}
__ Bind(&if_true);
}
bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) {
return LoadFieldInstr::IsFixedLengthArrayCid(cid);
}
-1
View File
@@ -2749,7 +2749,6 @@ void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
DEFINE_UNIMPLEMENTED_INSTRUCTION(GuardFieldTypeInstr)
DEFINE_UNIMPLEMENTED_INSTRUCTION(CheckConditionInstr)
LocationSummary* LoadCodeUnitsInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
-1
View File
@@ -2271,7 +2271,6 @@ static void LoadValueCid(FlowGraphCompiler* compiler,
}
DEFINE_UNIMPLEMENTED_INSTRUCTION(GuardFieldTypeInstr)
DEFINE_UNIMPLEMENTED_INSTRUCTION(CheckConditionInstr)
LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
-1
View File
@@ -1922,7 +1922,6 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
DEFINE_UNIMPLEMENTED_INSTRUCTION(GuardFieldTypeInstr)
DEFINE_UNIMPLEMENTED_INSTRUCTION(CheckConditionInstr)
LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
-1
View File
@@ -2493,7 +2493,6 @@ static void LoadValueCid(FlowGraphCompiler* compiler,
}
DEFINE_UNIMPLEMENTED_INSTRUCTION(GuardFieldTypeInstr)
DEFINE_UNIMPLEMENTED_INSTRUCTION(CheckConditionInstr)
LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
-19
View File
@@ -5601,25 +5601,6 @@ void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
}
LocationSummary* CheckConditionInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
comparison()->InitializeLocationSummary(zone, opt);
comparison()->locs()->set_out(0, Location::NoLocation());
return comparison()->locs();
}
void CheckConditionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler::Label if_true;
compiler::Label* if_false =
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnknown);
BranchLabels labels = {&if_true, if_false, &if_true};
Condition true_condition = comparison()->EmitComparisonCode(compiler, labels);
if (true_condition != kInvalidCondition) {
__ j(InvertCondition(true_condition), if_false);
}
__ Bind(&if_true);
}
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
+60 -9
View File
@@ -2249,7 +2249,6 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
GenerateUsageCounterIncrement(/* scratch */ R8);
}
ASSERT(exactness == kIgnoreExactness); // Unimplemented.
__ CheckCodePointer();
ASSERT(num_args == 1 || num_args == 2);
#if defined(DEBUG)
@@ -2293,7 +2292,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
// R8: points at the IC data array.
if (type == kInstanceCall) {
__ LoadTaggedClassIdMayBeSmi(R0, R0);
__ LoadTaggedClassIdMayBeSmi(NOTFP, R0);
__ ldr(
ARGS_DESC_REG,
FieldAddress(R9, target::CallSiteData::arguments_descriptor_offset()));
@@ -2318,7 +2317,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
// R1: argument_count - 1 (smi).
__ ldr(R0, Address(SP, R1, LSL, 1)); // R1 (argument_count - 1) is Smi.
__ LoadTaggedClassIdMayBeSmi(R0, R0);
__ LoadTaggedClassIdMayBeSmi(NOTFP, R0);
if (num_args == 2) {
__ sub(R1, R1, Operand(target::ToRawSmi(1)));
@@ -2326,7 +2325,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
__ LoadTaggedClassIdMayBeSmi(R1, R1);
}
}
// R0: first argument class ID as Smi.
// NOTFP: first argument class ID as Smi.
// R1: second argument class ID as Smi.
// R4: args descriptor
@@ -2342,7 +2341,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
Label update;
__ ldr(R2, Address(R8, kIcDataOffset));
__ cmp(R0, Operand(R2)); // Class id match?
__ cmp(NOTFP, Operand(R2)); // Class id match?
if (num_args == 2) {
__ b(&update, NE); // Continue.
__ ldr(R2, Address(R8, kIcDataOffset + target::kWordSize));
@@ -2418,13 +2417,45 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
target::ICData::TargetIndexFor(num_args) * target::kWordSize;
const intptr_t count_offset =
target::ICData::CountIndexFor(num_args) * target::kWordSize;
const intptr_t exactness_offset =
target::ICData::ExactnessIndexFor(num_args) * target::kWordSize;
Label call_target_function_through_unchecked_entry;
if (exactness == kCheckExactness) {
Label exactness_ok;
ASSERT(num_args == 1);
__ ldr(R1, Address(R8, kIcDataOffset + exactness_offset));
__ CompareImmediate(
R1, target::ToRawSmi(
StaticTypeExactnessState::HasExactSuperType().Encode()));
__ BranchIf(LESS, &exactness_ok);
__ BranchIf(EQUAL, &call_target_function_through_unchecked_entry);
// Check trivial exactness.
// Note: UntaggedICData::receivers_static_type_ is guaranteed to be not null
// because we only emit calls to this stub when it is not null.
__ ldr(R2,
FieldAddress(R9, target::ICData::receivers_static_type_offset()));
__ ldr(R2, FieldAddress(R2, target::Type::arguments_offset()));
// R1 contains an offset to type arguments in words as a smi,
// hence TIMES_2. R0 is guaranteed to be non-smi because it is expected
// to have type argument.
__ LoadIndexedPayload(TMP, R0, 0, R1, TIMES_2);
__ CompareObjectRegisters(R2, TMP);
__ BranchIf(EQUAL, &call_target_function_through_unchecked_entry);
// Update exactness state (not-exact anymore).
__ LoadImmediate(
R1, target::ToRawSmi(StaticTypeExactnessState::NotExact().Encode()));
__ str(R1, Address(R8, kIcDataOffset + exactness_offset));
__ Bind(&exactness_ok);
}
__ LoadFromOffset(FUNCTION_REG, R8, kIcDataOffset + target_offset);
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update caller's counter");
__ LoadFromOffset(R1, R8, kIcDataOffset + count_offset);
// Ignore overflow.
__ adds(R1, R1, Operand(target::ToRawSmi(1)));
__ add(R1, R1, Operand(target::ToRawSmi(1))); // Ignore overflow.
__ StoreIntoSmiField(Address(R8, kIcDataOffset + count_offset), R1);
}
@@ -2440,6 +2471,22 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
FieldAddress(FUNCTION_REG, target::Function::entry_point_offset()));
}
if (exactness == kCheckExactness) {
__ Bind(&call_target_function_through_unchecked_entry);
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update ICData counter");
__ LoadFromOffset(R1, R8, kIcDataOffset + count_offset);
__ add(R1, R1, Operand(target::ToRawSmi(1))); // Ignore overflow.
__ StoreIntoSmiField(Address(R8, kIcDataOffset + count_offset), R1);
}
__ Comment("Call target (via unchecked entry point)");
__ LoadFromOffset(FUNCTION_REG, R8, kIcDataOffset + target_offset);
__ ldr(CODE_REG,
FieldAddress(FUNCTION_REG, target::Function::code_offset()));
__ Branch(FieldAddress(FUNCTION_REG, target::Function::entry_point_offset(
CodeEntryKind::kUnchecked)));
}
#if !defined(PRODUCT)
if (optimized == kUnoptimized) {
__ Bind(&stepping);
@@ -2481,7 +2528,9 @@ void StubCodeCompiler::GenerateOneArgCheckInlineCacheStub() {
// R9: ICData
// LR: return address
void StubCodeCompiler::GenerateOneArgCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
kUnoptimized, kInstanceCall, kCheckExactness);
}
// R0: receiver
@@ -2536,7 +2585,9 @@ void StubCodeCompiler::GenerateOneArgOptimizedCheckInlineCacheStub() {
// LR: return address
void StubCodeCompiler::
GenerateOneArgOptimizedCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, kOptimized,
kInstanceCall, kCheckExactness);
}
// R0: receiver
+71 -10
View File
@@ -2562,7 +2562,6 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
GenerateUsageCounterIncrement(/*scratch=*/R6);
}
ASSERT(exactness == kIgnoreExactness); // Unimplemented.
ASSERT(num_args == 1 || num_args == 2);
#if defined(DEBUG)
{
@@ -2608,7 +2607,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
// R6: points directly to the first ic data array element.
if (type == kInstanceCall) {
__ LoadTaggedClassIdMayBeSmi(R0, R0);
__ LoadTaggedClassIdMayBeSmi(R3, R0);
__ LoadFieldFromOffset(ARGS_DESC_REG, R5,
target::CallSiteData::arguments_descriptor_offset());
if (num_args == 2) {
@@ -2631,7 +2630,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
__ sub(R7, R7, Operand(1));
// R0 <- [SP + (R7 << 3)]
__ ldr(R0, Address(SP, R7, UXTX, Address::Scaled));
__ LoadTaggedClassIdMayBeSmi(R0, R0);
__ LoadTaggedClassIdMayBeSmi(R3, R0);
if (num_args == 2) {
__ AddImmediate(R1, R7, -1);
// R1 <- [SP + (R1 << 3)]
@@ -2639,7 +2638,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
__ LoadTaggedClassIdMayBeSmi(R1, R1);
}
}
// R0: first argument class ID as Smi.
// R3: first argument class ID as Smi.
// R1: second argument class ID as Smi.
// R4: args descriptor
@@ -2655,7 +2654,7 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
Label update;
__ LoadCompressedSmiFromOffset(R2, R6, 0);
__ CompareObjectRegisters(R0, R2); // Class id match?
__ CompareObjectRegisters(R3, R2); // Class id match?
if (num_args == 2) {
__ b(&update, NE); // Continue.
__ LoadCompressedSmiFromOffset(R2, R6, target::kCompressedWordSize);
@@ -2732,18 +2731,57 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
}
__ Bind(&found);
__ Comment("Update caller's counter");
// R6: pointer to an IC data check group.
const intptr_t target_offset =
target::ICData::TargetIndexFor(num_args) * target::kCompressedWordSize;
const intptr_t count_offset =
target::ICData::CountIndexFor(num_args) * target::kCompressedWordSize;
const intptr_t exactness_offset =
target::ICData::ExactnessIndexFor(num_args) * target::kCompressedWordSize;
Label call_target_function_through_unchecked_entry;
if (exactness == kCheckExactness) {
Label exactness_ok;
ASSERT(num_args == 1);
__ LoadCompressedSmi(R1, Address(R6, exactness_offset));
__ CompareImmediate(
R1,
target::ToRawSmi(
StaticTypeExactnessState::HasExactSuperType().Encode()),
kObjectBytes);
__ BranchIf(LESS, &exactness_ok);
__ BranchIf(EQUAL, &call_target_function_through_unchecked_entry);
// Check trivial exactness.
// Note: UntaggedICData::receivers_static_type_ is guaranteed to be not null
// because we only emit calls to this stub when it is not null.
__ LoadCompressed(
R2, FieldAddress(R5, target::ICData::receivers_static_type_offset()));
__ LoadCompressed(R2, FieldAddress(R2, target::Type::arguments_offset()));
// R1 contains an offset to type arguments in words as a smi,
// hence TIMES_4. R0 is guaranteed to be non-smi because it is expected
// to have type arguments.
#if defined(DART_COMPRESSED_POINTERS)
__ sxtw(R1, R1);
#endif
__ LoadIndexedPayload(R3, R0, 0, R1, TIMES_COMPRESSED_HALF_WORD_SIZE,
kObjectBytes);
__ CompareObjectRegisters(R2, R3);
__ BranchIf(EQUAL, &call_target_function_through_unchecked_entry);
// Update exactness state (not-exact anymore).
__ LoadImmediate(
R1, target::ToRawSmi(StaticTypeExactnessState::NotExact().Encode()));
__ StoreToOffset(R1, R6, exactness_offset, kObjectBytes);
__ Bind(&exactness_ok);
}
__ LoadCompressedFromOffset(FUNCTION_REG, R6, target_offset);
if (FLAG_optimization_counter_threshold >= 0) {
// Update counter, ignore overflow.
__ Comment("Update caller's counter");
__ LoadCompressedSmiFromOffset(R1, R6, count_offset);
__ adds(R1, R1, Operand(target::ToRawSmi(1)), kObjectBytes);
// Ignore overflow.
__ add(R1, R1, Operand(target::ToRawSmi(1)), kObjectBytes);
__ StoreToOffset(R1, R6, count_offset, kObjectBytes);
}
@@ -2761,6 +2799,25 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
}
__ br(R2);
if (exactness == kCheckExactness) {
__ Bind(&call_target_function_through_unchecked_entry);
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update ICData counter");
__ LoadCompressedSmiFromOffset(R1, R6, count_offset);
// Ignore overflow.
__ add(R1, R1, Operand(target::ToRawSmi(1)), kObjectBytes);
__ StoreToOffset(R1, R6, count_offset, kObjectBytes);
}
__ Comment("Call target (via unchecked entry point)");
__ LoadCompressedFromOffset(FUNCTION_REG, R6, target_offset);
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
target::Function::code_offset());
__ LoadFieldFromOffset(
R2, FUNCTION_REG,
target::Function::entry_point_offset(CodeEntryKind::kUnchecked));
__ br(R2);
}
#if !defined(PRODUCT)
if (optimized == kUnoptimized) {
__ Bind(&stepping);
@@ -2802,7 +2859,9 @@ void StubCodeCompiler::GenerateOneArgCheckInlineCacheStub() {
// R5: ICData
// LR: return address
void StubCodeCompiler::GenerateOneArgCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
kUnoptimized, kInstanceCall, kCheckExactness);
}
// R0: receiver
@@ -2857,7 +2916,9 @@ void StubCodeCompiler::GenerateOneArgOptimizedCheckInlineCacheStub() {
// LR: return address
void StubCodeCompiler::
GenerateOneArgOptimizedCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, kOptimized,
kInstanceCall, kCheckExactness);
}
// R0: receiver
+54 -4
View File
@@ -1922,7 +1922,6 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStubForEntryKind(
GenerateUsageCounterIncrement(/* scratch */ EAX);
}
ASSERT(exactness == kIgnoreExactness); // Unimplemented.
ASSERT(num_args == 1 || num_args == 2);
#if defined(DEBUG)
{
@@ -1991,6 +1990,8 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStubForEntryKind(
target::ICData::TargetIndexFor(num_args) * target::kWordSize;
const intptr_t count_offset =
target::ICData::CountIndexFor(num_args) * target::kWordSize;
const intptr_t exactness_offset =
target::ICData::ExactnessIndexFor(num_args) * target::kWordSize;
const intptr_t entry_size = target::ICData::TestEntryLengthFor(
num_args, exactness == kCheckExactness) *
target::kWordSize;
@@ -2067,8 +2068,40 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStubForEntryKind(
}
__ Bind(&found);
// EBX: Pointer to an IC data check group.
Label call_target_function_through_unchecked_entry;
if (exactness == kCheckExactness) {
Label exactness_ok;
ASSERT(num_args == 1);
__ movl(EDI, Address(EBX, exactness_offset));
__ cmpl(EDI, Immediate(target::ToRawSmi(
StaticTypeExactnessState::HasExactSuperType().Encode())));
__ j(LESS, &exactness_ok);
__ j(EQUAL, &call_target_function_through_unchecked_entry);
// Check trivial exactness.
// Note: UntaggedICData::receivers_static_type_ is guaranteed to be not null
// because we only emit calls to this stub when it is not null.
__ movl(EAX, FieldAddress(ARGS_DESC_REG,
target::ArgumentsDescriptor::count_offset()));
__ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); // Receiver
// EDI contains an offset to type arguments in words as a smi,
// hence TIMES_2. EAX is guaranteed to be non-smi because it is expected
// to have type arguments.
__ movl(EDI,
FieldAddress(EAX, EDI, TIMES_2, 0)); // Receiver's type arguments
__ movl(EAX,
FieldAddress(ECX, target::ICData::receivers_static_type_offset()));
__ cmpl(EDI, FieldAddress(EAX, target::Type::arguments_offset()));
__ j(EQUAL, &call_target_function_through_unchecked_entry);
// Update exactness state (not-exact anymore).
__ movl(Address(EBX, exactness_offset),
Immediate(target::ToRawSmi(
StaticTypeExactnessState::NotExact().Encode())));
__ Bind(&exactness_ok);
}
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update caller's counter");
// Ignore overflow.
@@ -2082,6 +2115,19 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStubForEntryKind(
__ jmp(FieldAddress(FUNCTION_REG,
target::Function::entry_point_offset(entry_kind)));
if (exactness == kCheckExactness) {
__ Bind(&call_target_function_through_unchecked_entry);
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update ICData counter");
// Ignore overflow.
__ addl(Address(EBX, count_offset), Immediate(target::ToRawSmi(1)));
}
__ Comment("Call target (via unchecked entry point)");
__ LoadCompressed(FUNCTION_REG, Address(EBX, target_offset));
__ jmp(FieldAddress(FUNCTION_REG, target::Function::entry_point_offset(
CodeEntryKind::kUnchecked)));
}
#if !defined(PRODUCT)
if (optimized == kUnoptimized) {
__ Bind(&stepping);
@@ -2110,7 +2156,9 @@ void StubCodeCompiler::GenerateOneArgCheckInlineCacheStub() {
// ECX: ICData
// ESP[0]: return address
void StubCodeCompiler::GenerateOneArgCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
kUnoptimized, kInstanceCall, kCheckExactness);
}
void StubCodeCompiler::GenerateAllocateMintSharedWithFPURegsStub() {
@@ -2173,7 +2221,9 @@ void StubCodeCompiler::GenerateOneArgOptimizedCheckInlineCacheStub() {
// ESP[0]: return address
void StubCodeCompiler::
GenerateOneArgOptimizedCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, kOptimized,
kInstanceCall, kCheckExactness);
}
// EBX: receiver
@@ -2349,7 +2349,6 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
GenerateUsageCounterIncrement(/*scratch=*/T0);
}
ASSERT(exactness == kIgnoreExactness); // Unimplemented.
ASSERT(num_args == 1 || num_args == 2);
#if defined(DEBUG)
{
@@ -2509,19 +2508,51 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
}
__ Bind(&found);
__ Comment("Update caller's counter");
// A1: pointer to an IC data check group.
const intptr_t target_offset =
target::ICData::TargetIndexFor(num_args) * target::kCompressedWordSize;
const intptr_t count_offset =
target::ICData::CountIndexFor(num_args) * target::kCompressedWordSize;
const intptr_t exactness_offset =
target::ICData::ExactnessIndexFor(num_args) * target::kCompressedWordSize;
Label call_target_function_through_unchecked_entry;
if (exactness == kCheckExactness) {
Label exactness_ok;
ASSERT(num_args == 1);
__ LoadCompressedSmi(T1, Address(A1, exactness_offset));
__ LoadImmediate(
TMP, target::ToRawSmi(
StaticTypeExactnessState::HasExactSuperType().Encode()));
__ blt(T1, TMP, &exactness_ok);
__ beq(T1, TMP, &call_target_function_through_unchecked_entry);
// Check trivial exactness.
// Note: UntaggedICData::receivers_static_type_ is guaranteed to be not null
// because we only emit calls to this stub when it is not null.
__ LoadCompressed(
T2, FieldAddress(S5, target::ICData::receivers_static_type_offset()));
__ LoadCompressed(T2, FieldAddress(T2, target::Type::arguments_offset()));
// T1 contains an offset to type arguments in words as a smi,
// hence TIMES_4. A0 is guaranteed to be non-smi because it is expected
// to have type arguments.
__ LoadIndexedPayload(TMP, A0, 0, T1, TIMES_COMPRESSED_HALF_WORD_SIZE,
kObjectBytes);
__ beq(T2, TMP, &call_target_function_through_unchecked_entry);
// Update exactness state (not-exact anymore).
__ LoadImmediate(
TMP, target::ToRawSmi(StaticTypeExactnessState::NotExact().Encode()));
__ StoreToOffset(TMP, A1, exactness_offset, kObjectBytes);
__ Bind(&exactness_ok);
}
__ LoadCompressedFromOffset(FUNCTION_REG, A1, target_offset);
if (FLAG_optimization_counter_threshold >= 0) {
// Update counter, ignore overflow.
__ Comment("Update caller's counter");
__ LoadCompressedSmiFromOffset(TMP, A1, count_offset);
__ addi(TMP, TMP, target::ToRawSmi(1));
__ StoreToOffset(TMP, A1, count_offset);
__ addi(TMP, TMP, target::ToRawSmi(1)); // Ignore overflow.
__ StoreToOffset(TMP, A1, count_offset, kObjectBytes);
}
__ Comment("Call target");
@@ -2538,6 +2569,24 @@ void StubCodeCompiler::GenerateNArgsCheckInlineCacheStub(
}
__ jr(A7); // FUNCTION_REG: Function, argument to lazy compile stub.
if (exactness == kCheckExactness) {
__ Bind(&call_target_function_through_unchecked_entry);
if (FLAG_optimization_counter_threshold >= 0) {
__ Comment("Update ICData counter");
__ LoadCompressedSmiFromOffset(TMP, A1, count_offset);
__ addi(TMP, TMP, target::ToRawSmi(1)); // Ignore overflow.
__ StoreToOffset(TMP, A1, count_offset, kObjectBytes);
}
__ Comment("Call target (via unchecked entry point)");
__ LoadCompressedFromOffset(FUNCTION_REG, A1, target_offset);
__ LoadCompressedFieldFromOffset(CODE_REG, FUNCTION_REG,
target::Function::code_offset());
__ LoadFieldFromOffset(
A7, FUNCTION_REG,
target::Function::entry_point_offset(CodeEntryKind::kUnchecked));
__ jr(A7);
}
#if !defined(PRODUCT)
if (optimized == kUnoptimized) {
__ Bind(&stepping);
@@ -2579,7 +2628,9 @@ void StubCodeCompiler::GenerateOneArgCheckInlineCacheStub() {
// S5: ICData
// RA: return address
void StubCodeCompiler::GenerateOneArgCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
kUnoptimized, kInstanceCall, kCheckExactness);
}
// A0: receiver
@@ -2634,7 +2685,9 @@ void StubCodeCompiler::GenerateOneArgOptimizedCheckInlineCacheStub() {
// RA: return address
void StubCodeCompiler::
GenerateOneArgOptimizedCheckInlineCacheWithExactnessCheckStub() {
__ Stop("Unimplemented");
GenerateNArgsCheckInlineCacheStub(
1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, kOptimized,
kInstanceCall, kCheckExactness);
}
// A0: receiver
-2
View File
@@ -16610,7 +16610,6 @@ void CallSiteData::set_arguments_descriptor(const Array& value) const {
void ICData::SetReceiversStaticType(const AbstractType& type) const {
untag()->set_receivers_static_type(type.ptr());
#if defined(TARGET_ARCH_X64)
if (!type.IsNull() && type.HasTypeClass() && (NumArgsTested() == 1) &&
type.IsInstantiated() && !type.IsFutureOrType()) {
const Class& cls = Class::Handle(type.type_class());
@@ -16618,7 +16617,6 @@ void ICData::SetReceiversStaticType(const AbstractType& type) const {
set_tracking_exactness(true);
}
}
#endif // defined(TARGET_ARCH_X64)
}
#endif