[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:
committed by
Commit Queue
parent
8c2f088481
commit
4fb7b66b8c
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user