mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[VM] Bare instructions - Part 6: Get rid of CODE_REG indirection in CallThroughCode/CallThroughFunction stubs
If the --use-bare-instructions flag is enabled we will: * Not load CODE_REG inside CallThroughCode (polymorphic case) * Not load CODE_REG inside CallThroughFunction (megamorphic case) * Store the EntryPoint of the function in the MegamorphicCache tables (instead of a Function pointer) Issue https://github.com/dart-lang/sdk/issues/33274 Change-Id: I8aca689dc4e92ece897972da4ae202338527ac62 Reviewed-on: https://dart-review.googlesource.com/c/86928 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
parent
25851db73d
commit
5054079c7a
6 changed files with 122 additions and 32 deletions
|
@ -2340,6 +2340,32 @@ class MegamorphicCacheDeserializationCluster : public DeserializationCluster {
|
|||
cache->ptr()->filled_entry_count_ = d->Read<int32_t>();
|
||||
}
|
||||
}
|
||||
|
||||
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_use_bare_instructions) {
|
||||
// By default, every megamorphic call site will load the target
|
||||
// [Function] from the hash table and call indirectly via loading the
|
||||
// entrypoint from the function.
|
||||
//
|
||||
// In --use-bare-instruction we reduce the extra indirection via the
|
||||
// [Function] object by storing the entry point directly into the hashmap.
|
||||
//
|
||||
// Currently our AOT compiler will emit megamorphic calls in certain
|
||||
// situations (namely in slow-path code of CheckedSmi* instructions).
|
||||
//
|
||||
// TODO(compiler-team): Change the CheckedSmi* slow path code to use
|
||||
// normal switchable calls instead of megamorphic calls. (This is also a
|
||||
// memory balance beause [MegamorphicCache]s are per-selector while
|
||||
// [ICData] are per-callsite.)
|
||||
auto& cache = MegamorphicCache::Handle(zone);
|
||||
for (intptr_t i = start_index_; i < stop_index_; ++i) {
|
||||
cache ^= refs.At(i);
|
||||
cache.SwitchToBareInstructions();
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
|
|
@ -15259,8 +15259,8 @@ void MegamorphicCache::EnsureCapacity() const {
|
|||
const Array& new_buckets =
|
||||
Array::Handle(Array::New(kEntryLength * new_capacity));
|
||||
|
||||
Function& target = Function::Handle(
|
||||
MegamorphicCacheTable::miss_handler(Isolate::Current()));
|
||||
auto& target =
|
||||
Object::Handle(MegamorphicCacheTable::miss_handler(Isolate::Current()));
|
||||
for (intptr_t i = 0; i < new_capacity; ++i) {
|
||||
SetEntry(new_buckets, i, smi_illegal_cid(), target);
|
||||
}
|
||||
|
@ -15273,15 +15273,14 @@ void MegamorphicCache::EnsureCapacity() const {
|
|||
for (intptr_t i = 0; i < old_capacity; ++i) {
|
||||
class_id ^= GetClassId(old_buckets, i);
|
||||
if (class_id.Value() != kIllegalCid) {
|
||||
target ^= GetTargetFunction(old_buckets, i);
|
||||
target = GetTargetFunction(old_buckets, i);
|
||||
Insert(class_id, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MegamorphicCache::Insert(const Smi& class_id,
|
||||
const Function& target) const {
|
||||
void MegamorphicCache::Insert(const Smi& class_id, const Object& target) const {
|
||||
ASSERT(static_cast<double>(filled_entry_count() + 1) <=
|
||||
(kLoadFactor * static_cast<double>(mask() + 1)));
|
||||
const Array& backing_array = Array::Handle(buckets());
|
||||
|
@ -15305,6 +15304,23 @@ const char* MegamorphicCache::ToCString() const {
|
|||
name.ToCString());
|
||||
}
|
||||
|
||||
void MegamorphicCache::SwitchToBareInstructions() {
|
||||
NoSafepointScope no_safepoint_scope;
|
||||
|
||||
intptr_t capacity = mask() + 1;
|
||||
for (intptr_t i = 0; i < capacity; ++i) {
|
||||
const intptr_t target_index = i * kEntryLength + kTargetFunctionIndex;
|
||||
RawObject** slot = &Array::DataOf(buckets())[target_index];
|
||||
const intptr_t cid = (*slot)->GetClassIdMayBeSmi();
|
||||
if (cid == kFunctionCid) {
|
||||
RawCode* code = Function::CurrentCodeOf(Function::RawCast(*slot));
|
||||
*slot = Smi::FromAlignedAddress(Code::EntryPoint(code));
|
||||
} else {
|
||||
ASSERT(cid == kSmiCid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RawSubtypeTestCache* SubtypeTestCache::New() {
|
||||
ASSERT(Object::subtypetestcache_class() != Class::null());
|
||||
SubtypeTestCache& result = SubtypeTestCache::Handle();
|
||||
|
|
|
@ -2273,7 +2273,11 @@ class Function : public Object {
|
|||
|
||||
// Return the most recently compiled and installed code for this function.
|
||||
// It is not the only Code object that points to this function.
|
||||
RawCode* CurrentCode() const { return raw_ptr()->code_; }
|
||||
RawCode* CurrentCode() const { return CurrentCodeOf(raw()); }
|
||||
|
||||
static RawCode* CurrentCodeOf(const RawFunction* function) {
|
||||
return function->ptr()->code_;
|
||||
}
|
||||
|
||||
RawCode* unoptimized_code() const {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
@ -5541,7 +5545,9 @@ class MegamorphicCache : public Object {
|
|||
|
||||
void EnsureCapacity() const;
|
||||
|
||||
void Insert(const Smi& class_id, const Function& target) const;
|
||||
void Insert(const Smi& class_id, const Object& target) const;
|
||||
|
||||
void SwitchToBareInstructions();
|
||||
|
||||
static intptr_t InstanceSize() {
|
||||
return RoundedAllocationSize(sizeof(RawMegamorphicCache));
|
||||
|
@ -5566,7 +5572,7 @@ class MegamorphicCache : public Object {
|
|||
static inline void SetEntry(const Array& array,
|
||||
intptr_t index,
|
||||
const Smi& class_id,
|
||||
const Function& target);
|
||||
const Object& target);
|
||||
|
||||
static inline RawObject* GetClassId(const Array& array, intptr_t index);
|
||||
static inline RawObject* GetTargetFunction(const Array& array,
|
||||
|
@ -9257,8 +9263,20 @@ intptr_t Library::UrlHash() const {
|
|||
void MegamorphicCache::SetEntry(const Array& array,
|
||||
intptr_t index,
|
||||
const Smi& class_id,
|
||||
const Function& target) {
|
||||
const Object& target) {
|
||||
ASSERT(target.IsFunction() || target.IsSmi());
|
||||
array.SetAt((index * kEntryLength) + kClassIdIndex, class_id);
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
if (target.IsFunction()) {
|
||||
const auto& function = Function::Cast(target);
|
||||
const auto& entry_point = Smi::Handle(
|
||||
Smi::FromAlignedAddress(Code::EntryPoint(function.CurrentCode())));
|
||||
array.SetAt((index * kEntryLength) + kTargetFunctionIndex, entry_point);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
array.SetAt((index * kEntryLength) + kTargetFunctionIndex, target);
|
||||
}
|
||||
|
||||
|
|
|
@ -2680,10 +2680,18 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
|||
// proper target for the given name and arguments descriptor. If the
|
||||
// illegal class id was found, the target is a cache miss handler that can
|
||||
// be invoked as a normal Dart function.
|
||||
__ ldr(R0, FieldAddress(IP, base + kWordSize));
|
||||
__ ldr(R4, FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
|
||||
__ Branch(FieldAddress(R0, Function::entry_point_offset()));
|
||||
const auto target_address = FieldAddress(IP, base + kWordSize);
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ Branch(target_address);
|
||||
} else {
|
||||
__ ldr(R0, target_address);
|
||||
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ Branch(FieldAddress(R0, Function::entry_point_offset()));
|
||||
}
|
||||
|
||||
// Probe failed, check if it is a miss.
|
||||
__ Bind(&probe_failed);
|
||||
|
@ -2704,7 +2712,8 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
|||
// R4: arguments descriptor
|
||||
void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
|
||||
Label loop, found, miss;
|
||||
__ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R9, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
|
||||
__ AddImmediate(R8, Array::data_offset() - kHeapObjectTag);
|
||||
// R8: first IC entry
|
||||
|
@ -2737,8 +2746,8 @@ void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
|
|||
|
||||
void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
|
||||
Label loop, found, miss;
|
||||
__ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
|
||||
__ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
|
||||
__ AddImmediate(R8, Array::data_offset() - kHeapObjectTag);
|
||||
// R8: first IC entry
|
||||
__ LoadTaggedClassIdMayBeSmi(R1, R0);
|
||||
|
@ -2759,7 +2768,9 @@ void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
|
|||
__ Bind(&found);
|
||||
const intptr_t code_offset = ICData::CodeIndexFor(1) * kWordSize;
|
||||
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
|
||||
__ ldr(CODE_REG, Address(R8, code_offset));
|
||||
if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
|
||||
__ ldr(CODE_REG, Address(R8, code_offset));
|
||||
}
|
||||
__ Branch(Address(R8, entry_offset));
|
||||
|
||||
__ Bind(&miss);
|
||||
|
|
|
@ -2945,10 +2945,18 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
|||
// proper target for the given name and arguments descriptor. If the
|
||||
// illegal class id was found, the target is a cache miss handler that can
|
||||
// be invoked as a normal Dart function.
|
||||
__ ldr(R0, FieldAddress(TMP, base + kWordSize));
|
||||
__ ldr(R4, FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
|
||||
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
|
||||
const auto target_address = FieldAddress(TMP, base + kWordSize);
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ ldr(R1, target_address);
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
|
||||
} else {
|
||||
__ ldr(R0, target_address);
|
||||
__ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
|
||||
}
|
||||
__ br(R1);
|
||||
|
||||
// Probe failed, check if it is a miss.
|
||||
|
@ -2975,7 +2983,8 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
|||
// R4: arguments descriptor
|
||||
void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
|
||||
Label loop, found, miss;
|
||||
__ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(ARGS_DESC_REG,
|
||||
FieldAddress(R5, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
|
||||
__ AddImmediate(R8, Array::data_offset() - kHeapObjectTag);
|
||||
// R8: first IC entry
|
||||
|
@ -3010,8 +3019,8 @@ void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
|
|||
|
||||
void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
|
||||
Label loop, found, miss;
|
||||
__ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
|
||||
__ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
|
||||
__ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
|
||||
__ AddImmediate(R8, Array::data_offset() - kHeapObjectTag);
|
||||
// R8: first IC entry
|
||||
__ LoadTaggedClassIdMayBeSmi(R1, R0);
|
||||
|
@ -3033,7 +3042,9 @@ void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
|
|||
const intptr_t code_offset = ICData::CodeIndexFor(1) * kWordSize;
|
||||
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
|
||||
__ ldr(R1, Address(R8, entry_offset));
|
||||
__ ldr(CODE_REG, Address(R8, code_offset));
|
||||
if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
|
||||
__ ldr(CODE_REG, Address(R8, code_offset));
|
||||
}
|
||||
__ br(R1);
|
||||
|
||||
__ Bind(&miss);
|
||||
|
|
|
@ -2952,12 +2952,19 @@ void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
|
|||
// proper target for the given name and arguments descriptor. If the
|
||||
// illegal class id was found, the target is a cache miss handler that can
|
||||
// be invoked as a normal Dart function.
|
||||
__ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize));
|
||||
__ movq(R10,
|
||||
FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
|
||||
__ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
|
||||
__ jmp(RCX);
|
||||
const auto target_address = FieldAddress(RDI, RCX, TIMES_8, base + kWordSize);
|
||||
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
|
||||
__ movq(R10,
|
||||
FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ jmp(target_address);
|
||||
} else {
|
||||
__ movq(RAX, target_address);
|
||||
__ movq(R10,
|
||||
FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
|
||||
__ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
|
||||
__ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
|
||||
__ jmp(RCX);
|
||||
}
|
||||
|
||||
// Probe failed, check if it is a miss.
|
||||
__ Bind(&probe_failed);
|
||||
|
@ -3044,9 +3051,10 @@ void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
|
|||
__ Bind(&found);
|
||||
const intptr_t code_offset = ICData::CodeIndexFor(1) * kWordSize;
|
||||
const intptr_t entry_offset = ICData::EntryPointIndexFor(1) * kWordSize;
|
||||
__ movq(RCX, Address(R13, entry_offset));
|
||||
__ movq(CODE_REG, Address(R13, code_offset));
|
||||
__ jmp(RCX);
|
||||
if (!(FLAG_precompiled_mode && FLAG_use_bare_instructions)) {
|
||||
__ movq(CODE_REG, Address(R13, code_offset));
|
||||
}
|
||||
__ jmp(Address(R13, entry_offset));
|
||||
|
||||
__ Bind(&miss);
|
||||
__ LoadIsolate(RAX);
|
||||
|
|
Loading…
Reference in a new issue