From cf4544c379f10f1e3b70e158080295c9f3f154b8 Mon Sep 17 00:00:00 2001 From: Artem Udovichenko Date: Tue, 2 Aug 2022 19:29:03 +0300 Subject: [PATCH 1/2] Rework IC to support more slots for an instruction Upcoming quickener reduces instruction sizes. So instruction length is not enough to store IC values. IC is implemented now as follow: * Each JSFunction contains ProfileTypeInfo as previously but its size is calculated as sum of IC sizes for each instruction requires IC. * JSMethod contains in ofsset mapping. Its an array. Instruction offset is an index in this array. Value is an index of IC in ProfiletypeInfo. I.e. previously we get IC as follow: ProfileTypeInfo &ic = func->GetProfileTypeInfo()[inst.GetBytecodeOffset()]; Now: ic_index = func->GetMethod()->GetOffsetMapping()[inst.GetBytecodeOffset()]; ProfileTypeInfo &ic = func->GetProfileTypeInfo()[ic_index]; Change-Id: Ib73267855d87a9a474b56033dbf9e7c46e5c87c8 Signed-off-by: Artem Udovichenko --- irtoc_scripts/common.irt | 1 + irtoc_scripts/interpreter_handlers.irt | 10 +++- runtime/asm_defines/asm_defines.def | 2 + runtime/asm_defines/defines.h | 1 + .../class_linker/panda_file_translator.cpp | 47 +++++++++++++------ runtime/class_linker/panda_file_translator.h | 7 +-- runtime/class_linker/program_object-inl.h | 7 ++- runtime/ecma_vm.cpp | 9 +++- runtime/ic/ic_runtime_stub-inl.h | 19 +++++++- runtime/ic/ic_runtime_stub.h | 16 +++++++ runtime/interpreter/slow_runtime_stub.cpp | 20 ++++---- runtime/js_method.cpp | 5 ++ runtime/js_method.h | 35 ++++++++------ 13 files changed, 130 insertions(+), 49 deletions(-) diff --git a/irtoc_scripts/common.irt b/irtoc_scripts/common.irt index b6cf45fa9..f810c8936 100644 --- a/irtoc_scripts/common.irt +++ b/irtoc_scripts/common.irt @@ -51,6 +51,7 @@ module Constants JS_OBJECT_PROPERTIES_FIELD = "runtime->GetFieldByOffset(cross_values::GetJsobjectPropertiesOffset(graph->GetArch()))" JS_OBJECT_ELEMENTS_FIELD = "runtime->GetFieldByOffset(cross_values::GetJsobjectElementsOffset(graph->GetArch()))" JS_ARRAY_LENGTH_FIELD = "runtime->GetFieldByOffset(cross_values::GetJsarrayLengthOffset(graph->GetArch()))" + JS_FUNCTION_METHOD_FIELD = "runtime->GetFieldByOffset(cross_values::GetJsfunctionMethodOffset(graph->GetArch()))" JS_FUNCTION_PROFILE_TYPE_INFO_FIELD = "runtime->GetFieldByOffset(cross_values::GetJsfunctionProfileTypeInfoOffset(graph->GetArch()))" JS_PROPERTY_BOX_VALUE_FIELD = "runtime->GetFieldByOffset(cross_values::GetJspropertyBoxValueOffset(graph->GetArch()))" JS_TRANSITION_HANDLER_HANDLER_INFO_FEILD = "runtime->GetFieldByOffset(cross_values::GetJstransitionHandlerHandlerInfoOffset(graph->GetArch()))" diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index 31f6d2898..e89452af8 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -1039,10 +1039,17 @@ macro(:get_ic) do || LoadObject(get_this_func()).ObjField(Constants::JS_FUNCTION_PROFILE_TYPE_INFO_FIELD).any end +macro(:map_ic_slot) do |ic_slot| + method_ptr := LoadObject(get_this_func()).ObjField(Constants::JS_FUNCTION_METHOD_FIELD).ptr + mapping := Load(method_ptr, "JSMETHOD_IC_OFFSET_MAPPING_OFFSET").ptr + Load(mapping, ic_slot).u8 +end + macro(:access_global_var_ic) do |key, value, ic_slot, access| ic := get_ic() IfImm(cmpanyundefined(ic)).Imm(0).CC(:CC_EQ).b { - handler := LoadArray(anytoheapobj(ic), ic_slot).any + ic_idx := map_ic_slot(ic_slot) + handler := LoadArray(anytoheapobj(ic), ic_idx).any IfImm(cmpanyheapobj(handler)).Imm(0).CC(:CC_NE).b { r = access.call(anytoheapobj(handler), value) r00 := r @@ -1229,6 +1236,7 @@ macro(:access_obj_ic) do |obj, value, ic_slot, access| Goto(:Miss) } + ic_slot := map_ic_slot(ic_slot) ic_cls := LoadArray(anytoheapobj(ic), ic_slot).any IfImm(cmpanyheapobj(ic_cls)).Imm(0).CC(:CC_EQ).b { Goto(:Miss) diff --git a/runtime/asm_defines/asm_defines.def b/runtime/asm_defines/asm_defines.def index bb99f6c06..c1c0cd340 100644 --- a/runtime/asm_defines/asm_defines.def +++ b/runtime/asm_defines/asm_defines.def @@ -27,6 +27,7 @@ DEFINE_VALUE(JSHCLASS_HCLASS_OFFSET, panda::ecmascript::JSHClass::GetHClassOffse DEFINE_VALUE(JSOBJECT_PROPERTIES_OFFSET, panda::ecmascript::JSObject::PROPERTIES_OFFSET) DEFINE_VALUE(JSOBJECT_ELEMENTS_OFFSET, panda::ecmascript::JSObject::ELEMENTS_OFFSET) DEFINE_VALUE(JSARRAY_LENGTH_OFFSET, panda::ecmascript::JSArray::LENGTH_OFFSET) +DEFINE_VALUE(JSFUNCTION_METHOD_OFFSET, panda::ecmascript::JSFunction::METHOD_OFFSET) DEFINE_VALUE(JSFUNCTION_PROFILE_TYPE_INFO_OFFSET, panda::ecmascript::JSFunction::PROFILE_TYPE_INFO_OFFSET) DEFINE_VALUE(JSPROPERTY_BOX_VALUE_OFFSET, panda::ecmascript::PropertyBox::VALUE_OFFSET) DEFINE_VALUE(JSTRANSITION_HANDLER_HANDLER_INFO_OFFSET, panda::ecmascript::TransitionHandler::HANDLER_INFO_OFFSET) @@ -43,3 +44,4 @@ DEFINE_VALUE(IC_HANDLER_INLINED_PROPS_BIT_START_BIT, panda::ecmascript::HandlerB DEFINE_VALUE(IC_HANDLER_INLINED_PROPS_BIT_MASK, panda::ecmascript::HandlerBase::InlinedPropsBit::MaxValue()) DEFINE_VALUE(IC_HANDLER_HANDLER_KIND_FIELD, static_cast(panda::ecmascript::HandlerBase::HandlerKind::FIELD)) DEFINE_VALUE(HCLASS_DATA_OFFSET, HClass::GetDataOffset()) +DEFINE_VALUE(JSMETHOD_IC_OFFSET_MAPPING_OFFSET, panda::ecmascript::JSMethod::GetICOffsetMappingOffset()) diff --git a/runtime/asm_defines/defines.h b/runtime/asm_defines/defines.h index 975128eb9..e6bdbc86d 100644 --- a/runtime/asm_defines/defines.h +++ b/runtime/asm_defines/defines.h @@ -27,5 +27,6 @@ #include "plugins/ecmascript/runtime/js_for_in_iterator.h" #include "plugins/ecmascript/runtime/tagged_array.h" #include "plugins/ecmascript/runtime/tagged_queue.h" +#include "plugins/ecmascript/runtime/js_method.h" #endif // PLUGINS_ECMASCRIPT_RUNTIME_ASM_DEFINES_DEFINES_H diff --git a/runtime/class_linker/panda_file_translator.cpp b/runtime/class_linker/panda_file_translator.cpp index d5b8862f8..7d90a5784 100644 --- a/runtime/class_linker/panda_file_translator.cpp +++ b/runtime/class_linker/panda_file_translator.cpp @@ -22,6 +22,7 @@ #include "plugins/ecmascript/runtime/class_info_extractor.h" #include "plugins/ecmascript/runtime/class_linker/program_object-inl.h" #include "plugins/ecmascript/runtime/global_env.h" +#include "plugins/ecmascript/runtime/ic/profile_type_info.h" #include "plugins/ecmascript/runtime/interpreter/interpreter.h" #include "plugins/ecmascript/runtime/js_array.h" #include "plugins/ecmascript/runtime/js_function.h" @@ -29,6 +30,7 @@ #include "plugins/ecmascript/runtime/literal_data_extractor.h" #include "plugins/ecmascript/runtime/object_factory.h" #include "plugins/ecmascript/runtime/tagged_array.h" +#include "plugins/ecmascript/runtime/ic/ic_runtime_stub.h" #include "libpandabase/mem/mem.h" #include "libpandabase/utils/logger.h" #include "libpandabase/utils/utf.h" @@ -43,6 +45,15 @@ PandaFileTranslator::PandaFileTranslator(EcmaVM *vm) { } +PandaFileTranslator::~PandaFileTranslator() +{ + for (uint32_t i = 0; i < numMethods_; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + methods_[i].~JSMethod(); + } + ecmaVm_->GetRegionFactory()->FreeBuffer(methods_); +} + JSHandle PandaFileTranslator::TranslatePandaFile(EcmaVM *vm, const panda_file::File &pf, const CString &methodName) { @@ -319,8 +330,9 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf) mainFunc->SetConstantPool(thread_, constpool.GetTaggedValue()); program->SetMainFunction(thread_, mainFunc.GetTaggedValue()); program->SetMethodsData(methods_); - methods_ = nullptr; program->SetNumberMethods(numMethods_); + methods_ = nullptr; + numMethods_ = 0; // link program constpool->Set(thread_, constpoolIndex_, program.GetTaggedValue()); } @@ -474,43 +486,48 @@ void PandaFileTranslator::TranslateBytecode(uint32_t insSz, const uint8_t *insAr break; } } + UpdateICOffset(const_cast(method), insSz, bcIns); bcIns = bcIns.GetNext(); - UpdateICOffset(const_cast(method), bcIns); } } -void PandaFileTranslator::UpdateICOffset(JSMethod *method, const BytecodeInstruction &inst) const +void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint32_t insSz, const BytecodeInstruction &inst) const { - uint32_t offset = method->GetSlotSize(); - if (UNLIKELY(offset == JSMethod::MAX_SLOT_SIZE)) { - return; - } - auto opcode = inst.GetOpcode(); uint32_t bc_offset = inst.GetAddress() - method->GetInstructions(); + uint32_t slotSize = 0; switch (opcode) { case BytecodeInstruction::Opcode::ECMA_TRYLDGLOBALBYNAME_PREF_ID32: case BytecodeInstruction::Opcode::ECMA_TRYSTGLOBALBYNAME_PREF_ID32: case BytecodeInstruction::Opcode::ECMA_LDGLOBALVAR_PREF_ID32: case BytecodeInstruction::Opcode::ECMA_STGLOBALVAR_PREF_ID32: + slotSize = ICRuntimeStub::SlotSizeForGlobalICByName(); + break; case BytecodeInstruction::Opcode::ECMA_LDOBJBYVALUE_PREF_V8_V8: case BytecodeInstruction::Opcode::ECMA_STOBJBYVALUE_PREF_V8_V8: case BytecodeInstruction::Opcode::ECMA_STOWNBYVALUE_PREF_V8_V8: + slotSize = ICRuntimeStub::SlotSizeForICByValue(); + break; case BytecodeInstruction::Opcode::ECMA_LDOBJBYNAME_PREF_ID32_V8: case BytecodeInstruction::Opcode::ECMA_STOBJBYNAME_PREF_ID32_V8: case BytecodeInstruction::Opcode::ECMA_STOWNBYNAME_PREF_ID32_V8: - case BytecodeInstruction::Opcode::ECMA_LDSUPERBYVALUE_PREF_V8_V8: - case BytecodeInstruction::Opcode::ECMA_STSUPERBYVALUE_PREF_V8_V8: - case BytecodeInstruction::Opcode::ECMA_LDSUPERBYNAME_PREF_ID32_V8: - case BytecodeInstruction::Opcode::ECMA_STSUPERBYNAME_PREF_ID32_V8: - case BytecodeInstruction::Opcode::ECMA_LDMODVARBYNAME_PREF_ID32_V8: - case BytecodeInstruction::Opcode::ECMA_STMODULEVAR_PREF_ID32: - method->SetSlotSize(bc_offset + inst.GetSize()); + slotSize = ICRuntimeStub::SlotSizeForICByName(); break; default: return; } + uint8_t *icOffsetMapping = method->GetICOffsetMapping(); + if (icOffsetMapping == nullptr && insSz < ProfileTypeInfo::INVALID_SLOT_INDEX) { + icOffsetMapping = mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->AllocArray(insSz); + memset_s(icOffsetMapping, insSz, 0, insSz); + method->SetICOffsetMapping(icOffsetMapping); + } + if (icOffsetMapping != nullptr) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + icOffsetMapping[bc_offset] = method->GetSlotSize(); + method->AddSlotSize(slotSize); + } } uint32_t PandaFileTranslator::GetOrInsertConstantPool(ConstPoolType type, uint32_t offset) diff --git a/runtime/class_linker/panda_file_translator.h b/runtime/class_linker/panda_file_translator.h index 1c77bb5a7..a93464ad8 100644 --- a/runtime/class_linker/panda_file_translator.h +++ b/runtime/class_linker/panda_file_translator.h @@ -32,10 +32,7 @@ public: enum FixInstructionIndex : uint8_t { FIX_ONE = 1, FIX_TWO = 2, FIX_FOUR = 4 }; explicit PandaFileTranslator(EcmaVM *vm); - ~PandaFileTranslator() - { - ecmaVm_->GetRegionFactory()->FreeBuffer(methods_); - } + ~PandaFileTranslator(); NO_COPY_SEMANTIC(PandaFileTranslator); NO_MOVE_SEMANTIC(PandaFileTranslator); static JSHandle TranslatePandaFile(EcmaVM *vm, const panda_file::File &pf, const CString &methodName); @@ -101,7 +98,7 @@ private: const uint8_t *descriptor, panda_file::MethodDataAccessor &mda); void TranslateBytecode(uint32_t insSz, const uint8_t *insArr, const panda_file::File &pf, const JSMethod *method); void FixInstructionId32(const BytecodeInstruction &inst, uint32_t index, uint32_t fixOrder = 0) const; - void UpdateICOffset(JSMethod *method, const BytecodeInstruction &inst) const; + void UpdateICOffset(JSMethod *method, uint32_t insSz, const BytecodeInstruction &inst) const; void DefineClassInConstPool(const JSHandle &constpool) const; void SetMethods(Span methods, const uint32_t numMethods) diff --git a/runtime/class_linker/program_object-inl.h b/runtime/class_linker/program_object-inl.h index f96c1a625..0a8ce3f8d 100644 --- a/runtime/class_linker/program_object-inl.h +++ b/runtime/class_linker/program_object-inl.h @@ -34,7 +34,12 @@ JSTaggedValue ConstantPool::GetObjectFromCache(uint32_t index) const void Program::FreeMethodData(RegionFactory *factory) { - factory->FreeBuffer(GetMethodsData()); + JSMethod *methods = GetMethodsData(); + for (uint32_t i = 0; i < GetNumberMethods(); ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + methods[i].~JSMethod(); + } + factory->FreeBuffer(methods); } } // namespace panda::ecmascript #endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index fe51b3544..1b48de9ec 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -79,6 +79,8 @@ namespace panda::ecmascript { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) static const std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; +// NOLINTNEXTLINE(fuchsia-statically-constructed-objects) +static const std::string_view ENTRY_METHOD_POINTER = "func_main_0"; JSRuntimeOptions EcmaVM::options_; // NOLINT(fuchsia-statically-constructed-objects) void EcmaRendezvous::SafepointBegin() @@ -997,7 +999,12 @@ std::unique_ptr EcmaVM::OpenPandaFile(std::string_view l auto pf = panda_file::OpenPandaFile(location, "", open_mode); // PandaFileTranslator can trigger GC. ScopedManagedCodeThread s(thread_); - PandaFileTranslator::QuickPandaFile(this, *pf); + [[maybe_unused]] EcmaHandleScope handleScope(GetJSThread()); + auto program = PandaFileTranslator::TranslatePandaFile(this, *pf, ENTRY_METHOD_POINTER.data()); + { + os::memory::LockHolder lock(pandaFileWithProgramLock_); + pandaFileWithProgram_.emplace_back(program.GetObject(), pf.get(), false); + } return pf; } diff --git a/runtime/ic/ic_runtime_stub-inl.h b/runtime/ic/ic_runtime_stub-inl.h index ce4114ea4..6998d9b8a 100644 --- a/runtime/ic/ic_runtime_stub-inl.h +++ b/runtime/ic/ic_runtime_stub-inl.h @@ -42,6 +42,15 @@ bool ICRuntimeStub::HaveICForFunction(JSThread *thread) return !func->GetProfileTypeInfo().IsUndefined(); } +uint32_t ICRuntimeStub::MapSlotId(JSThread *thread, uint32_t slotId) +{ + auto *func = JSFunction::Cast(GetThisFunc(thread).GetHeapObject()); + uint8_t *mapping = func->GetMethod()->GetICOffsetMapping(); + ASSERT(mapping != nullptr); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return mapping[slotId]; +} + ProfileTypeInfo *ICRuntimeStub::GetRuntimeProfileTypeInfo(JSThread *thread) { auto *func = JSFunction::Cast(GetThisFunc(thread).GetHeapObject()); @@ -54,6 +63,7 @@ JSTaggedValue ICRuntimeStub::LoadGlobalICByName(JSThread *thread, JSTaggedValue { INTERPRETER_TRACE(thread, LoadGlobalICByName); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue handler = profileTypeInfo->Get(slotId); if (handler.IsHeapObject()) { @@ -77,6 +87,7 @@ JSTaggedValue ICRuntimeStub::StoreGlobalICByName(JSThread *thread, JSTaggedValue { INTERPRETER_TRACE(thread, StoreGlobalICByName); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue handler = profileTypeInfo->Get(slotId); if (handler.IsHeapObject()) { @@ -116,6 +127,7 @@ JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, JSTaggedValue receiv { INTERPRETER_TRACE(thread, LoadICByName); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue hclassValue = profileTypeInfo->Get(slotId); if (hclassValue.IsHole()) { @@ -137,7 +149,7 @@ JSTaggedValue ICRuntimeStub::LoadICByName(JSThread *thread, JSTaggedValue receiv } index += 2U; hclassValue = profileTypeInfo->Get(index); - } while (index < slotId + 4U); + } while (index < slotId + SlotSizeForICByName()); } return LoadMissedICByName(thread, profileTypeInfo, receiver, key, slotId); } @@ -146,6 +158,7 @@ JSTaggedValue ICRuntimeStub::LoadICByValue(JSThread *thread, JSTaggedValue recei { INTERPRETER_TRACE(thread, LoadICByValue); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue firstValue = profileTypeInfo->Get(slotId); if (firstValue.IsHole()) { @@ -174,6 +187,7 @@ JSTaggedValue ICRuntimeStub::StoreICByValue(JSThread *thread, JSTaggedValue rece { INTERPRETER_TRACE(thread, StoreICByValue); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue firstValue = profileTypeInfo->Get(slotId); if (firstValue.IsHole()) { @@ -204,6 +218,7 @@ JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, JSTaggedValue recei { INTERPRETER_TRACE(thread, StoreICByName); ASSERT(HaveICForFunction(thread)); + slotId = MapSlotId(thread, slotId); ProfileTypeInfo *profileTypeInfo = GetRuntimeProfileTypeInfo(thread); JSTaggedValue hclassValue = profileTypeInfo->Get(slotId); if (hclassValue.IsHole()) { @@ -225,7 +240,7 @@ JSTaggedValue ICRuntimeStub::StoreICByName(JSThread *thread, JSTaggedValue recei } index += 2U; hclassValue = profileTypeInfo->Get(index); - } while (index < slotId + 4U); + } while (index < slotId + SlotSizeForICByName()); } return StoreMissedICByName(thread, profileTypeInfo, receiver, key, value, slotId); } diff --git a/runtime/ic/ic_runtime_stub.h b/runtime/ic/ic_runtime_stub.h index 9bb4a1b9e..811e4d1fb 100644 --- a/runtime/ic/ic_runtime_stub.h +++ b/runtime/ic/ic_runtime_stub.h @@ -25,6 +25,21 @@ class ProfileTypeInfo; class ICRuntimeStub { public: + static inline constexpr uint32_t SlotSizeForGlobalICByName() + { + return 1U; + } + + static inline constexpr uint32_t SlotSizeForICByName() + { + return 4U; + } + + static inline constexpr uint32_t SlotSizeForICByValue() + { + return 3U; + } + ARK_INLINE static inline bool HaveICForFunction(JSThread *thread); ARK_INLINE static inline JSTaggedValue LoadGlobalICByName(JSThread *thread, JSTaggedValue globalValue, JSTaggedValue key, uint32_t slotId, @@ -62,6 +77,7 @@ public: ARK_INLINE static inline uint32_t TryToElementsIndex(JSTaggedValue key); private: + static inline uint32_t MapSlotId(JSThread *thread, uint32_t slotId); static inline ProfileTypeInfo *GetRuntimeProfileTypeInfo(JSThread *thread); ARK_NOINLINE static JSTaggedValue LoadMissedICByName(JSThread *thread, ProfileTypeInfo *profileTypeArray, JSTaggedValue receiver, JSTaggedValue key, uint32_t slotId); diff --git a/runtime/interpreter/slow_runtime_stub.cpp b/runtime/interpreter/slow_runtime_stub.cpp index 17baf84df..3add8462e 100644 --- a/runtime/interpreter/slow_runtime_stub.cpp +++ b/runtime/interpreter/slow_runtime_stub.cpp @@ -1882,17 +1882,17 @@ void SlowRuntimeStub::ThrowDeleteSuperProperty(JSThread *thread) JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, JSFunction *func, JSMethod *method) { INTERPRETER_TRACE(thread, NotifyInlineCache); - uint32_t icSlotSize = method->GetSlotSize(); - if (icSlotSize > 0 && icSlotSize < ProfileTypeInfo::INVALID_SLOT_INDEX) { - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - [[maybe_unused]] EcmaHandleScope handleScope(thread); - - JSHandle funcHandle(thread, func); - JSHandle profileTypeInfo = factory->NewProfileTypeInfo(icSlotSize); - funcHandle->SetProfileTypeInfo(thread, profileTypeInfo.GetTaggedValue()); - return profileTypeInfo.GetTaggedValue(); + if (method->GetICOffsetMapping() == nullptr) { + return JSTaggedValue::Undefined(); } - return JSTaggedValue::Undefined(); + uint32_t icSlotSize = method->GetSlotSize(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle funcHandle(thread, func); + JSHandle profileTypeInfo = factory->NewProfileTypeInfo(icSlotSize); + funcHandle->SetProfileTypeInfo(thread, profileTypeInfo.GetTaggedValue()); + return profileTypeInfo.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, diff --git a/runtime/js_method.cpp b/runtime/js_method.cpp index 510c42960..c180ec224 100644 --- a/runtime/js_method.cpp +++ b/runtime/js_method.cpp @@ -18,6 +18,11 @@ #include "libpandafile/method_data_accessor-inl.h" namespace panda::ecmascript { +JSMethod::~JSMethod() +{ + mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->Free(icOffsetMapping_); +} + // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. CString JSMethod::ParseFunctionName() const { diff --git a/runtime/js_method.h b/runtime/js_method.h index ab212165c..85471ddee 100644 --- a/runtime/js_method.h +++ b/runtime/js_method.h @@ -55,7 +55,7 @@ public: } JSMethod() = delete; - ~JSMethod() = default; + ~JSMethod(); JSMethod(const JSMethod &) = delete; JSMethod(JSMethod &&) = delete; JSMethod &operator=(const JSMethod &) = delete; @@ -86,23 +86,29 @@ public: return slotSize_; } - void UpdateSlotSize(uint32_t size) + void AddSlotSize(uint32_t size) { - uint64_t end = GetSlotSize() + size; - if (end >= MAX_SLOT_SIZE) { - slotSize_ = MAX_SLOT_SIZE; - return; - } - slotSize_ = static_cast(end); + slotSize_ += size; } - void SetSlotSize(uint32_t size) + uint8_t *GetICOffsetMapping() { - if (size >= MAX_SLOT_SIZE) { - slotSize_ = MAX_SLOT_SIZE; - return; - } - slotSize_ = size; + return icOffsetMapping_; + } + + const uint8_t *GetICOffsetMapping() const + { + return icOffsetMapping_; + } + + void SetICOffsetMapping(uint8_t *mapping) + { + icOffsetMapping_ = mapping; + } + + static constexpr size_t GetICOffsetMappingOffset() + { + return MEMBER_OFFSET(JSMethod, icOffsetMapping_); } uint32_t GetCallType() const @@ -120,6 +126,7 @@ private: const uint8_t *bytecodeArray_ {nullptr}; uint32_t bytecodeArraySize_ {0}; uint32_t slotSize_ {0}; + uint8_t *icOffsetMapping_ {nullptr}; uint32_t callType_ {UINT32_MAX}; // UINT32_MAX means not found }; } // namespace panda::ecmascript -- Gitee From 7a914bb63b0f6da6d6f89ad2109601ae0c79e422 Mon Sep 17 00:00:00 2001 From: Artem Udovichenko Date: Thu, 4 Aug 2022 18:16:32 +0300 Subject: [PATCH 2/2] Eliminate dtor call Change-Id: Id153cdb8a89b888cf464c5ef11c2ac73010f9835 --- .../class_linker/panda_file_translator.cpp | 56 +++++-------------- runtime/class_linker/panda_file_translator.h | 19 +------ runtime/class_linker/program_object-inl.h | 10 +--- runtime/class_linker/program_object.h | 5 +- runtime/dump.cpp | 6 +- runtime/ecma_vm.cpp | 4 +- runtime/global_env_constants.cpp | 1 - runtime/snapshot/mem/snapshot_serialize.cpp | 4 +- 8 files changed, 27 insertions(+), 78 deletions(-) diff --git a/runtime/class_linker/panda_file_translator.cpp b/runtime/class_linker/panda_file_translator.cpp index 7d90a5784..f1a5d999f 100644 --- a/runtime/class_linker/panda_file_translator.cpp +++ b/runtime/class_linker/panda_file_translator.cpp @@ -45,15 +45,6 @@ PandaFileTranslator::PandaFileTranslator(EcmaVM *vm) { } -PandaFileTranslator::~PandaFileTranslator() -{ - for (uint32_t i = 0; i < numMethods_; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - methods_[i].~JSMethod(); - } - ecmaVm_->GetRegionFactory()->FreeBuffer(methods_); -} - JSHandle PandaFileTranslator::TranslatePandaFile(EcmaVM *vm, const panda_file::File &pf, const CString &methodName) { @@ -77,10 +68,9 @@ static T *InitializeMemory(T *mem, Args... args) const JSMethod *PandaFileTranslator::FindMethods(uint32_t offset) const { - Span methods = GetMethods(); auto pred = [offset](const JSMethod &method) { return method.GetFileId().GetOffset() == offset; }; - auto it = std::find_if(methods.begin(), methods.end(), pred); - if (it != methods.end()) { + auto it = std::find_if(methods_->begin(), methods_->end(), pred); + if (it != methods_->end()) { return &*it; } return nullptr; @@ -88,22 +78,8 @@ const JSMethod *PandaFileTranslator::FindMethods(uint32_t offset) const void PandaFileTranslator::TranslateClasses(const panda_file::File &pf, const CString &methodName) { - RegionFactory *factory = ecmaVm_->GetRegionFactory(); Span classIndexes = pf.GetClasses(); - uint32_t numMethods = 0; - - for (const uint32_t index : classIndexes) { - panda_file::File::EntityId classId(index); - if (pf.IsExternal(classId)) { - continue; - } - panda_file::ClassDataAccessor cda(pf, classId); - numMethods += cda.GetMethodsNumber(); - } - - auto methodsData = factory->AllocateBuffer(sizeof(JSMethod) * numMethods); - Span methods {static_cast(methodsData), numMethods}; - size_t methodIdx = 0; + methods_ = MakePandaUnique>(); panda_file::File::StringData sd = {static_cast(methodName.size()), reinterpret_cast(methodName.c_str())}; @@ -123,23 +99,19 @@ void PandaFileTranslator::TranslateClasses(const panda_file::File &pf, const CSt compiler::AotClass aot_class = (aot_pfile != nullptr) ? aot_pfile->GetClass(classId.GetOffset()) : compiler::AotClass::Invalid(); - cda.EnumerateMethods( - [this, &aot_class, &sd, &methods, &methodIdx, &pf, &descriptor](panda_file::MethodDataAccessor &mda) { - TranslateMethod(aot_class, sd, methods, &methodIdx, pf, descriptor, mda); - }); + cda.EnumerateMethods([this, &aot_class, &sd, &pf, &descriptor](panda_file::MethodDataAccessor &mda) { + TranslateMethod(aot_class, sd, pf, descriptor, mda); + }); } - - SetMethods(methods, numMethods); } void PandaFileTranslator::TranslateMethod(const compiler::AotClass &aot_class, const panda_file::File::StringData &sd, - Span &methods, size_t *methodIdx, const panda_file::File &pf, - const uint8_t *descriptor, panda_file::MethodDataAccessor &mda) + const panda_file::File &pf, const uint8_t *descriptor, + panda_file::MethodDataAccessor &mda) { auto codeId = mda.GetCodeId(); ASSERT(codeId.has_value()); - JSMethod *method = &methods[(*methodIdx)++]; panda_file::CodeDataAccessor codeDataAccessor(pf, codeId.value()); uint32_t codeSize = codeDataAccessor.GetCodeSize(); @@ -159,11 +131,12 @@ void PandaFileTranslator::TranslateMethod(const compiler::AotClass &aot_class, c ASSERT(klass != nullptr); // Very important assert. - InitializeMemory(method, klass, &pf, mda.GetMethodId(), codeDataAccessor.GetCodeId(), mda.GetAccessFlags(), - codeDataAccessor.GetNumArgs(), reinterpret_cast(pda.GetShorty().Data())); + methods_->emplace_back(klass, &pf, mda.GetMethodId(), codeDataAccessor.GetCodeId(), mda.GetAccessFlags(), + codeDataAccessor.GetNumArgs(), reinterpret_cast(pda.GetShorty().Data())); + JSMethod *method = &methods_->back(); if (aot_class.IsValid()) { - auto entry = aot_class.FindMethodCodeEntry(*methodIdx - 1); + auto entry = aot_class.FindMethodCodeEntry(methods_->size() - 1); if (entry != nullptr) { method->SetCompiledEntryPoint(entry); } else { @@ -329,10 +302,7 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf) factory_->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR); mainFunc->SetConstantPool(thread_, constpool.GetTaggedValue()); program->SetMainFunction(thread_, mainFunc.GetTaggedValue()); - program->SetMethodsData(methods_); - program->SetNumberMethods(numMethods_); - methods_ = nullptr; - numMethods_ = 0; + program->SetMethodsData(methods_.release()); // link program constpool->Set(thread_, constpoolIndex_, program.GetTaggedValue()); } diff --git a/runtime/class_linker/panda_file_translator.h b/runtime/class_linker/panda_file_translator.h index a93464ad8..4803cbc74 100644 --- a/runtime/class_linker/panda_file_translator.h +++ b/runtime/class_linker/panda_file_translator.h @@ -32,7 +32,7 @@ public: enum FixInstructionIndex : uint8_t { FIX_ONE = 1, FIX_TWO = 2, FIX_FOUR = 4 }; explicit PandaFileTranslator(EcmaVM *vm); - ~PandaFileTranslator(); + ~PandaFileTranslator() = default; NO_COPY_SEMANTIC(PandaFileTranslator); NO_MOVE_SEMANTIC(PandaFileTranslator); static JSHandle TranslatePandaFile(EcmaVM *vm, const panda_file::File &pf, const CString &methodName); @@ -94,31 +94,18 @@ private: Program *GenerateProgram(const panda_file::File &pf); void TranslateClasses(const panda_file::File &pf, const CString &methodName); void TranslateMethod(const compiler::AotClass &aot_class, const panda_file::File::StringData &sd, - Span &methods, size_t *methodIdx, const panda_file::File &pf, - const uint8_t *descriptor, panda_file::MethodDataAccessor &mda); + const panda_file::File &pf, const uint8_t *descriptor, panda_file::MethodDataAccessor &mda); void TranslateBytecode(uint32_t insSz, const uint8_t *insArr, const panda_file::File &pf, const JSMethod *method); void FixInstructionId32(const BytecodeInstruction &inst, uint32_t index, uint32_t fixOrder = 0) const; void UpdateICOffset(JSMethod *method, uint32_t insSz, const BytecodeInstruction &inst) const; void DefineClassInConstPool(const JSHandle &constpool) const; - void SetMethods(Span methods, const uint32_t numMethods) - { - methods_ = methods.data(); - numMethods_ = numMethods; - } - - Span GetMethods() const - { - return {methods_, numMethods_}; - } - EcmaVM *ecmaVm_; ObjectFactory *factory_; JSThread *thread_; uint32_t constpoolIndex_ {0}; - uint32_t numMethods_ {0}; uint32_t mainMethodIndex_ {0}; - JSMethod *methods_ {nullptr}; + PandaUniquePtr> methods_; std::unordered_map constpoolMap_; std::set translated_code_; diff --git a/runtime/class_linker/program_object-inl.h b/runtime/class_linker/program_object-inl.h index 0a8ce3f8d..47f284e12 100644 --- a/runtime/class_linker/program_object-inl.h +++ b/runtime/class_linker/program_object-inl.h @@ -32,14 +32,10 @@ JSTaggedValue ConstantPool::GetObjectFromCache(uint32_t index) const return Get(index); } -void Program::FreeMethodData(RegionFactory *factory) +void Program::FreeMethodData() { - JSMethod *methods = GetMethodsData(); - for (uint32_t i = 0; i < GetNumberMethods(); ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - methods[i].~JSMethod(); - } - factory->FreeBuffer(methods); + mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->Delete(GetMethodsData()); + SetMethodsData(nullptr); } } // namespace panda::ecmascript #endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H diff --git a/runtime/class_linker/program_object.h b/runtime/class_linker/program_object.h index 17996eae4..dd0bc0999 100644 --- a/runtime/class_linker/program_object.h +++ b/runtime/class_linker/program_object.h @@ -31,10 +31,9 @@ public: ACCESSORS(Location, LOCATION_OFFSET, CONSTANT_POOL_OFFSET) ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, MAIN_FUNCTION_OFFSET) ACCESSORS(MainFunction, MAIN_FUNCTION_OFFSET, METHODS_DATA_OFFSET) - SET_GET_NATIVE_FIELD(MethodsData, JSMethod, METHODS_DATA_OFFSET, NUMBER_METHODS_OFFSET) - SET_GET_PRIMITIVE_FIELD(NumberMethods, uint32_t, NUMBER_METHODS_OFFSET, SIZE); + SET_GET_NATIVE_FIELD(MethodsData, PandaList, METHODS_DATA_OFFSET, SIZE) - inline void FreeMethodData(RegionFactory *factory); + inline void FreeMethodData(); DECL_VISIT_OBJECT(LOCATION_OFFSET, METHODS_DATA_OFFSET) DECL_DUMP() diff --git a/runtime/dump.cpp b/runtime/dump.cpp index 36b7f3fdf..50c6be37a 100644 --- a/runtime/dump.cpp +++ b/runtime/dump.cpp @@ -947,8 +947,8 @@ void Program::Dump([[maybe_unused]] JSThread *thread, std::ostream &os) const os << " - MainFunction: "; GetMainFunction().D(); os << "\n"; - os << " - MethodsData: " << GetMethodsData() << "\n"; - os << " - NumberMethods: " << GetNumberMethods() << "\n"; + PandaList *methods = GetMethodsData(); + os << " - NumberMethods: " << methods->size() << "\n"; } void ConstantPool::Dump(JSThread *thread, std::ostream &os) const @@ -2477,7 +2477,7 @@ void Program::DumpForSnapshot([[maybe_unused]] JSThread *thread, vec.emplace_back(std::make_pair(CString("ConstantPool"), GetConstantPool())); vec.emplace_back(std::make_pair(CString("MainFunction"), GetMainFunction())); // MethodsData is another native field, and we don't dump it for JS heap. - vec.emplace_back(std::make_pair(CString("NumberMethods"), JSTaggedValue(GetNumberMethods()))); + vec.emplace_back(std::make_pair(CString("NumberMethods"), JSTaggedValue(GetMethodsData()->size()))); } void ConstantPool::DumpForSnapshot([[maybe_unused]] JSThread *thread, diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index 1b48de9ec..1bb33f3c1 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -809,7 +809,7 @@ void EcmaVM::ProcessPrograms(const WeakRootVisitor &v0) if (object != nullptr) { auto fwd = v0(object); if (fwd == nullptr) { - object->FreeMethodData(regionFactory_.get()); + object->FreeMethodData(); auto pf = std::get<1>(*iter); extractorCache_.erase(pf); delete pf; @@ -879,7 +879,7 @@ void EcmaVM::ClearBufferData() os::memory::LockHolder lock(pandaFileWithProgramLock_); for (auto iter = pandaFileWithProgram_.begin(); iter != pandaFileWithProgram_.end();) { - std::get<0>(*iter)->FreeMethodData(regionFactory_.get()); + std::get<0>(*iter)->FreeMethodData(); iter = pandaFileWithProgram_.erase(iter); } pandaFileWithProgram_.clear(); diff --git a/runtime/global_env_constants.cpp b/runtime/global_env_constants.cpp index 016a5c4fe..496267fec 100644 --- a/runtime/global_env_constants.cpp +++ b/runtime/global_env_constants.cpp @@ -150,7 +150,6 @@ void GlobalEnvConstants::InitRootsClass([[maybe_unused]] JSThread *thread, JSHCl .GetTaggedValue()); JSHClass *programClass = *factory->NewEcmaDynClass(dynClassClass, Program::SIZE, JSType::PROGRAM); programClass->GetHClass()->MarkFieldAsNative(Program::METHODS_DATA_OFFSET); - programClass->GetHClass()->MarkFieldAsNative(Program::NUMBER_METHODS_OFFSET); SetConstant(ConstantIndex::PROGRAM_CLASS_INDEX, JSTaggedValue(programClass)); SetConstant(ConstantIndex::ECMA_MODULE_CLASS_INDEX, factory->NewEcmaDynClass(dynClassClass, EcmaModule::SIZE, JSType::ECMA_MODULE).GetTaggedValue()); diff --git a/runtime/snapshot/mem/snapshot_serialize.cpp b/runtime/snapshot/mem/snapshot_serialize.cpp index 69d83bd37..4f07d05d7 100644 --- a/runtime/snapshot/mem/snapshot_serialize.cpp +++ b/runtime/snapshot/mem/snapshot_serialize.cpp @@ -1195,8 +1195,7 @@ void SnapShotSerialize::DynProgramSerialize(TaggedObject *objectHeader, uintptr_ auto fieldAddr = reinterpret_cast(startAddr + i * TAGGED_SIZE); SetObjectSlotField(snapshotObj, beginOffset + i * TAGGED_SIZE, HandleTaggedField(fieldAddr, queue, data)); } - SetObjectSlotField(snapshotObj, Program::METHODS_DATA_OFFSET, 0); // methods - SetObjectSlotField(snapshotObj, Program::NUMBER_METHODS_OFFSET, 0); // method_number + SetObjectSlotField(snapshotObj, Program::METHODS_DATA_OFFSET, 0); // methods } void SnapShotSerialize::DynProgramDeserialize(uint64_t *objectHeader, [[maybe_unused]] size_t objectSize) @@ -1216,7 +1215,6 @@ void SnapShotSerialize::DynProgramDeserialize(uint64_t *objectHeader, [[maybe_un auto program = reinterpret_cast(objectHeader); program->SetMethodsData(nullptr); - program->SetNumberMethods(0); } void SnapShotSerialize::SerializePandaFileMethod() -- Gitee