[vm] Move megamorphic miss handling into the megamorphic call stub.

This removes the only stub code with a function owner.

Change-Id: I629eb3a1b231430afaf0a2777032bba8eaddd2aa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148124
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Ryan Macnak 2020-05-15 20:28:21 +00:00 committed by commit-bot@chromium.org
parent 42a1f29d5b
commit 6b91f92154
15 changed files with 42 additions and 207 deletions

View file

@ -1755,11 +1755,6 @@ void ClassFinalizer::ClearAllCode(bool including_nonchanging_cids) {
auto object_store = isolate->object_store();
auto& null_code = Code::Handle(zone);
object_store->set_build_method_extractor_code(null_code);
auto& miss_function =
Function::Handle(zone, object_store->megamorphic_call_miss_function());
miss_function.ClearCode();
object_store->SetMegamorphicCallMissHandler(null_code, miss_function);
}
#endif // !DART_PRECOMPILED_RUNTIME
}

View file

@ -293,9 +293,6 @@ void Precompiler::DoCompileAll() {
stub_code =
StubCode::GetBuildMethodExtractorStub(global_object_pool_builder());
I->object_store()->set_build_method_extractor_code(stub_code);
MegamorphicCacheTable::ReInitMissHandlerCode(
isolate_, global_object_pool_builder());
}
CollectDynamicFunctionNames();

View file

@ -64,7 +64,6 @@ class StubCodeCompiler : public AllStatic {
VM_STUB_CODE_LIST(STUB_CODE_GENERATE)
#undef STUB_CODE_GENERATE
static void GenerateMegamorphicCallMissStub(Assembler* assembler);
static void GenerateAllocationStubForClass(
Assembler* assembler,
UnresolvedPcRelativeCalls* unresolved_calls,

View file

@ -3447,8 +3447,8 @@ void StubCodeCompiler::GenerateOptimizedIdenticalWithNumberCheckStub(
// R4: arguments descriptor
// CODE_REG: target Code
void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ LoadTaggedClassIdMayBeSmi(R0, R0);
// R0: receiver cid as Smi.
__ LoadTaggedClassIdMayBeSmi(R8, R0);
// R8: receiver cid as Smi.
__ ldr(R2, FieldAddress(R9, target::MegamorphicCache::buckets_offset()));
__ ldr(R1, FieldAddress(R9, target::MegamorphicCache::mask_offset()));
// R2: cache buckets array.
@ -3457,7 +3457,7 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
// Compute the table index.
ASSERT(target::MegamorphicCache::kSpreadFactor == 7);
// Use reverse subtract to multiply with 7 == 8 - 1.
__ rsb(R3, R0, Operand(R0, LSL, 3));
__ rsb(R3, R8, Operand(R8, LSL, 3));
// R3: probe.
Label loop;
__ Bind(&loop);
@ -3468,7 +3468,7 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
Label probe_failed;
__ add(IP, R2, Operand(R3, LSL, 2));
__ ldr(R6, FieldAddress(IP, base));
__ cmp(R6, Operand(R0));
__ cmp(R6, Operand(R8));
__ b(&probe_failed, NE);
Label load_target;
@ -3496,11 +3496,15 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ Bind(&probe_failed);
ASSERT(kIllegalCid == 0);
__ tst(R6, Operand(R6));
__ b(&load_target, EQ); // branch if miss.
Label miss;
__ b(&miss, EQ); // branch if miss.
// Try next entry in the table.
__ AddImmediate(R3, target::ToRawSmi(1));
__ b(&loop);
__ Bind(&miss);
GenerateSwitchableCallMissStub(assembler);
}
void StubCodeCompiler::GenerateICCallThroughCodeStub(Assembler* assembler) {
@ -3586,8 +3590,8 @@ void StubCodeCompiler::GenerateMonomorphicSmiableCheckStub(
static void CallSwitchableCallMissRuntimeEntry(Assembler* assembler,
Register receiver_reg) {
__ LoadImmediate(IP, 0);
__ Push(IP); // Result slot
__ Push(IP); // Arg0: stub out
__ Push(IP); // Result slot
__ Push(IP); // Arg0: stub out
__ Push(receiver_reg); // Arg1: Receiver
__ CallRuntime(kSwitchableCallMissRuntimeEntry, 2);
__ Pop(R0); // Get the receiver
@ -3608,26 +3612,6 @@ void StubCodeCompiler::GenerateSwitchableCallMissStub(Assembler* assembler) {
CODE_REG, target::Code::entry_point_offset(CodeEntryKind::kNormal)));
}
// Called from megamorphic call sites and from megamorphic miss handlers.
// R9: ICData/MegamorphicCache
void StubCodeCompiler::GenerateMegamorphicCallMissStub(Assembler* assembler) {
__ EnterStubFrame();
// Load argument descriptor from ICData/MegamorphicCache.
__ ldr(R4,
FieldAddress(R9, target::CallSiteData::arguments_descriptor_offset()));
// Load the receiver.
__ ldr(R2, FieldAddress(R4, target::ArgumentsDescriptor::size_offset()));
__ add(IP, FP, Operand(R2, LSL, 1)); // R2 is Smi.
__ ldr(R8, Address(IP, target::frame_layout.param_end_from_fp *
target::kWordSize));
CallSwitchableCallMissRuntimeEntry(assembler, /*receiver_reg=*/R8);
__ LeaveStubFrame();
__ Branch(FieldAddress(
CODE_REG, target::Code::entry_point_offset(CodeEntryKind::kNormal)));
}
// Called from switchable IC calls.
// R0: receiver
// R9: SingleTargetCache

View file

@ -3557,7 +3557,7 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ BranchIfSmi(R0, &smi_case);
// Loads the cid of the object.
__ LoadClassId(R0, R0);
__ LoadClassId(R8, R0);
Label cid_loaded;
__ Bind(&cid_loaded);
@ -3567,14 +3567,14 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
// R1: mask as a smi.
// Make the cid into a smi.
__ SmiTag(R0);
// R0: class ID of the receiver (smi).
__ SmiTag(R8);
// R8: class ID of the receiver (smi).
// Compute the table index.
ASSERT(target::MegamorphicCache::kSpreadFactor == 7);
// Use lsl and sub to multiply with 7 == 8 - 1.
__ LslImmediate(R3, R0, 3);
__ sub(R3, R3, Operand(R0));
__ LslImmediate(R3, R8, 3);
__ sub(R3, R3, Operand(R8));
// R3: probe.
Label loop;
__ Bind(&loop);
@ -3585,7 +3585,7 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ add(TMP, R2, Operand(R3, LSL, 3));
__ ldr(R6, FieldAddress(TMP, base));
Label probe_failed;
__ CompareRegisters(R6, R0);
__ CompareRegisters(R6, R8);
__ b(&probe_failed, NE);
Label load_target;
@ -3614,7 +3614,8 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ Bind(&probe_failed);
ASSERT(kIllegalCid == 0);
__ tst(R6, Operand(R6));
__ b(&load_target, EQ); // branch if miss.
Label miss;
__ b(&miss, EQ); // branch if miss.
// Try next extry in the table.
__ AddImmediate(R3, target::ToRawSmi(1));
@ -3622,8 +3623,11 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
// Load cid for the Smi case.
__ Bind(&smi_case);
__ LoadImmediate(R0, kSmiCid);
__ LoadImmediate(R8, kSmiCid);
__ b(&cid_loaded);
__ Bind(&miss);
GenerateSwitchableCallMissStub(assembler);
}
// Input:
@ -3737,38 +3741,6 @@ void StubCodeCompiler::GenerateSwitchableCallMissStub(Assembler* assembler) {
__ br(R1);
}
// Called from megamorphic call sites and from megamorphic miss handlers.
// R5: ICData/MegamorphicCache
void StubCodeCompiler::GenerateMegamorphicCallMissStub(Assembler* assembler) {
__ ldr(CODE_REG,
Address(THR, target::Thread::switchable_call_miss_stub_offset()));
__ EnterStubFrame();
__ ldr(R4,
FieldAddress(R5, target::CallSiteData::arguments_descriptor_offset()));
// Load the receiver.
__ LoadFieldFromOffset(R2, R4, target::ArgumentsDescriptor::size_offset());
__ add(TMP, FP, Operand(R2, LSL, 2)); // R2 is Smi.
__ LoadFromOffset(R6, TMP,
target::frame_layout.param_end_from_fp * target::kWordSize);
__ Push(R6); // Preserver receiver
__ Push(ZR); // Result slot.
__ Push(ZR); // Arg0: stub out.
__ Push(R6); // Arg1: Receiver
__ CallRuntime(kSwitchableCallMissRuntimeEntry, 2);
__ Drop(1);
__ Pop(CODE_REG); // result = stub
__ Pop(R5); // result = IC
__ Pop(R0); // Restore receiver into R0
__ LeaveStubFrame();
__ ldr(R1, FieldAddress(CODE_REG, target::Code::entry_point_offset(
CodeEntryKind::kNormal)));
__ br(R1);
}
// Called from switchable IC calls.
// R0: receiver
// R5: SingleTargetCache

View file

@ -2854,7 +2854,8 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
// Probe failed, check if it is a miss.
__ cmpl(FieldAddress(EDI, EDX, TIMES_4, base),
Immediate(target::ToRawSmi(kIllegalCid)));
__ j(ZERO, &load_target, Assembler::kNearJump);
Label miss;
__ j(ZERO, &miss, Assembler::kNearJump);
// Try next entry in the table.
__ AddImmediate(EDX, Immediate(target::ToRawSmi(1)));
@ -2864,6 +2865,10 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ Bind(&smi_case);
__ movl(EAX, Immediate(kSmiCid));
__ jmp(&cid_loaded);
__ Bind(&miss);
__ popl(EBX); // restore receiver
GenerateSwitchableCallMissStub(assembler);
}
void StubCodeCompiler::GenerateICCallThroughCodeStub(Assembler* assembler) {
@ -2899,15 +2904,6 @@ void StubCodeCompiler::GenerateSwitchableCallMissStub(Assembler* assembler) {
__ jmp(EAX);
}
// Called from megamorphic call sites and from megamorphic miss handlers.
// EBX: receiver
// EDX: arguments descriptor(or zero if invoked from unlinked/monomorphic call)
void StubCodeCompiler::GenerateMegamorphicCallMissStub(Assembler* assembler) {
// On ia32 there is no need to load receiver from the actual arguments using
// arg descriptor because (unlike on arm, arm64) receiver is always available.
GenerateSwitchableCallMissStub(assembler);
}
void StubCodeCompiler::GenerateSingleTargetCallStub(Assembler* assembler) {
__ int3(); // AOT only.
}

View file

@ -3531,7 +3531,8 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ Bind(&probe_failed);
__ cmpq(FieldAddress(RDI, RCX, TIMES_8, base),
Immediate(target::ToRawSmi(kIllegalCid)));
__ j(ZERO, &load_target, Assembler::kNearJump);
Label miss;
__ j(ZERO, &miss, Assembler::kNearJump);
// Try next entry in the table.
__ AddImmediate(RCX, Immediate(target::ToRawSmi(1)));
@ -3541,6 +3542,9 @@ void StubCodeCompiler::GenerateMegamorphicCallStub(Assembler* assembler) {
__ Bind(&smi_case);
__ movq(RAX, Immediate(kSmiCid));
__ jmp(&cid_loaded);
__ Bind(&miss);
GenerateSwitchableCallMissStub(assembler);
}
// Input:
@ -3639,15 +3643,6 @@ void StubCodeCompiler::GenerateSwitchableCallMissStub(Assembler* assembler) {
__ jmp(RCX);
}
// Called from megamorphic call sites and from megamorphic miss handlers.
// RDX: receiver
// R10: arguments descriptor
void StubCodeCompiler::GenerateMegamorphicCallMissStub(Assembler* assembler) {
// On x64 there is no need to load receiver from the actual arguments using
// arg descriptor because (unlike on arm, arm64) receiver is always available.
GenerateSwitchableCallMissStub(assembler);
}
// Called from switchable IC calls.
// RDX: receiver
// RBX: SingleTargetCache

View file

@ -830,18 +830,11 @@ ErrorPtr Dart::InitializeIsolate(const uint8_t* snapshot_data,
DEBUG_ONLY(I->heap()->Verify(kForbidMarked));
#if defined(DART_PRECOMPILED_RUNTIME)
// AOT: The megamorphic miss function and code come from the snapshot.
ASSERT(I->object_store()->megamorphic_call_miss_code() != Code::null());
ASSERT(I->object_store()->build_method_extractor_code() != Code::null());
if (FLAG_print_llvm_constant_pool) {
PrintLLVMConstantPool(T, I);
}
#else
// JIT: The megamorphic call miss function and code come from the snapshot in
// JIT app snapshot, otherwise create them.
if (I->object_store()->megamorphic_call_miss_code() == Code::null()) {
MegamorphicCacheTable::InitMissHandler(I);
}
#if !defined(TARGET_ARCH_IA32)
if (I != Dart::vm_isolate()) {
I->object_store()->set_build_method_extractor_code(

View file

@ -44,70 +44,6 @@ MegamorphicCachePtr MegamorphicCacheTable::Lookup(Thread* thread,
return cache.raw();
}
FunctionPtr MegamorphicCacheTable::miss_handler(Isolate* isolate) {
ASSERT(isolate->object_store()->megamorphic_call_miss_function() !=
Function::null());
return isolate->object_store()->megamorphic_call_miss_function();
}
#if !defined(DART_PRECOMPILED_RUNTIME)
void MegamorphicCacheTable::InitMissHandler(Isolate* isolate) {
// The miss handler for a class ID not found in the table is invoked as a
// normal Dart function.
compiler::ObjectPoolBuilder object_pool_builder;
const Code& code = Code::Handle(StubCode::Generate(
"_stub_MegamorphicCallMiss", &object_pool_builder,
compiler::StubCodeCompiler::GenerateMegamorphicCallMissStub));
const auto& object_pool =
ObjectPool::Handle(ObjectPool::NewFromBuilder(object_pool_builder));
code.set_object_pool(object_pool.raw());
// When FLAG_lazy_dispatchers=false, this stub can be on the stack during
// exceptions, but it has a corresponding function so IsStubCode is false and
// it is considered in the search for an exception handler.
code.set_exception_handlers(Object::empty_exception_handlers());
const Class& cls =
Class::Handle(Type::Handle(Type::DartFunctionType()).type_class());
const Function& function = Function::Handle(Function::New(
Symbols::MegamorphicCallMiss(), FunctionLayout::kRegularFunction,
true, // Static, but called as a method.
false, // Not const.
false, // Not abstract.
false, // Not external.
false, // Not native.
cls, TokenPosition::kNoSource));
function.set_result_type(Type::Handle(Type::DynamicType()));
function.set_is_debuggable(false);
function.set_is_visible(false);
function.AttachCode(code); // Has a single entry point, as a static function.
// For inclusion in Snapshot::kFullJIT.
function.set_unoptimized_code(code);
ASSERT(isolate->object_store()->megamorphic_call_miss_function() ==
Function::null());
isolate->object_store()->SetMegamorphicCallMissHandler(code, function);
}
void MegamorphicCacheTable::ReInitMissHandlerCode(
Isolate* isolate,
compiler::ObjectPoolBuilder* wrapper) {
ASSERT(FLAG_precompiled_mode && FLAG_use_bare_instructions);
const Code& code = Code::Handle(StubCode::Generate(
"_stub_MegamorphicCallMiss", wrapper,
compiler::StubCodeCompiler::GenerateMegamorphicCallMissStub));
code.set_exception_handlers(Object::empty_exception_handlers());
auto object_store = isolate->object_store();
auto& function =
Function::Handle(object_store->megamorphic_call_miss_function());
function.AttachCode(code);
object_store->SetMegamorphicCallMissHandler(code, function);
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
void MegamorphicCacheTable::PrintSizes(Isolate* isolate) {
StackZone zone(Thread::Current());
intptr_t size = 0;

View file

@ -10,31 +10,13 @@
namespace dart {
namespace compiler {
class ObjectPoolBuilder;
}
class Array;
class Function;
class Isolate;
class ObjectPointerVisitor;
class String;
class Thread;
class MegamorphicCacheTable : public AllStatic {
public:
static FunctionPtr miss_handler(Isolate* isolate);
NOT_IN_PRECOMPILED(static void InitMissHandler(Isolate* isolate));
// Re-initializes the megamorphic miss handler function in the object store.
//
// Normally we initialize the megamorphic miss handler during isolate startup.
// Though if we AOT compile with bare instructions support, we need to
// re-generate the handler to ensure it uses the common object pool.
NOT_IN_PRECOMPILED(
static void ReInitMissHandlerCode(Isolate* isolate,
compiler::ObjectPoolBuilder* wrapper));
static MegamorphicCachePtr Lookup(Thread* thread,
const String& name,
const Array& descriptor);

View file

@ -16316,10 +16316,8 @@ void Code::GetInlinedFunctionsAtInstruction(
GrowableArray<TokenPosition>* token_positions) const {
const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
if (map.IsNull()) {
ASSERT(!IsFunctionCode() ||
(Isolate::Current()->object_store()->megamorphic_call_miss_code() ==
this->raw()));
return; // VM stub, allocation stub, or megamorphic call miss function.
ASSERT(!IsFunctionCode());
return; // VM stub, allocation stub, or type testing stub.
}
const Array& id_map = Array::Handle(inlined_id_to_function());
const Function& root = Function::Handle(function());
@ -16886,8 +16884,7 @@ MegamorphicCachePtr MegamorphicCache::New(const String& target_name,
const intptr_t capacity = kInitialCapacity;
const Array& buckets =
Array::Handle(Array::New(kEntryLength * capacity, Heap::kOld));
const Function& handler =
Function::Handle(MegamorphicCacheTable::miss_handler(Isolate::Current()));
const Object& handler = Object::Handle();
for (intptr_t i = 0; i < capacity; ++i) {
SetEntry(buckets, i, smi_illegal_cid(), handler);
}
@ -16915,8 +16912,7 @@ void MegamorphicCache::EnsureCapacityLocked() const {
const Array& new_buckets =
Array::Handle(Array::New(kEntryLength * new_capacity));
auto& target =
Object::Handle(MegamorphicCacheTable::miss_handler(Isolate::Current()));
auto& target = Object::Handle();
for (intptr_t i = 0; i < new_capacity; ++i) {
SetEntry(new_buckets, i, smi_illegal_cid(), target);
}
@ -16975,7 +16971,7 @@ void MegamorphicCache::SwitchToBareInstructions() {
CodePtr code = Function::CurrentCodeOf(Function::RawCast(*slot));
*slot = Smi::FromAlignedAddress(Code::EntryPointOf(code));
} else {
ASSERT(cid == kSmiCid);
ASSERT(cid == kSmiCid || cid == kNullCid);
}
}
}

View file

@ -11051,7 +11051,7 @@ void MegamorphicCache::SetEntry(const Array& array,
intptr_t index,
const Smi& class_id,
const Object& target) {
ASSERT(target.IsFunction() || target.IsSmi());
ASSERT(target.IsNull() || target.IsFunction() || target.IsSmi());
array.SetAt((index * kEntryLength) + kClassIdIndex, class_id);
#if defined(DART_PRECOMPILED_RUNTIME)
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {

View file

@ -206,8 +206,6 @@ class ObjectPointerVisitor;
RW(Code, top_type_tts_stub) \
RW(Code, unreachable_tts_stub) \
RW(Code, slow_tts_stub) \
R_(Code, megamorphic_call_miss_code) \
R_(Function, megamorphic_call_miss_function) \
RW(Array, dispatch_table_code_entries) \
RW(Array, code_order_table) \
RW(Array, obfuscation_map) \
@ -378,12 +376,6 @@ class ObjectStore {
}
}
void SetMegamorphicCallMissHandler(const Code& code, const Function& func) {
// Hold onto the code so it is traced and not detached from the function.
megamorphic_call_miss_code_ = code.raw();
megamorphic_call_miss_function_ = func.raw();
}
// Visit all object pointers.
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@ -418,7 +410,7 @@ class ObjectStore {
return reinterpret_cast<ObjectPtr*>(&global_object_pool_);
case Snapshot::kFullJIT:
case Snapshot::kFullAOT:
return reinterpret_cast<ObjectPtr*>(&megamorphic_call_miss_function_);
return reinterpret_cast<ObjectPtr*>(&slow_tts_stub_);
case Snapshot::kMessage:
case Snapshot::kNone:
case Snapshot::kInvalid:

View file

@ -425,8 +425,7 @@ void ProgramVisitor::ShareMegamorphicBuckets(Zone* zone, Isolate* isolate) {
const intptr_t capacity = 1;
const Array& buckets = Array::Handle(
zone, Array::New(MegamorphicCache::kEntryLength * capacity, Heap::kOld));
const Function& handler =
Function::Handle(zone, MegamorphicCacheTable::miss_handler(isolate));
const Function& handler = Function::Handle(zone);
MegamorphicCache::SetEntry(buckets, 0, Object::smi_illegal_cid(), handler);
for (intptr_t i = 0; i < table.Length(); i++) {

View file

@ -208,7 +208,6 @@ class ObjectPointerVisitor;
V(Map, "Map") \
V(MapLiteralFactory, "Map._fromLiteral") \
V(MegamorphicCache, "MegamorphicCache") \
V(MegamorphicCallMiss, "megamorphic_call_miss") \
V(MonomorphicSmiableCall, "MonomorphicSmiableCall") \
V(MoveNext, "moveNext") \
V(Namespace, "Namespace") \