From d7f1e9b52203bc604c904e9c52fce16fff61dfc5 Mon Sep 17 00:00:00 2001 From: dingwen Date: Thu, 22 Feb 2024 19:53:36 +0800 Subject: [PATCH] Work serialize optimization Description:Initialize snapshot env when vm initialize Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I930CL?from=project-issue Signed-off-by: dingwen Change-Id: Ib670982ac4c621973c71e19ee4777c42eb092b66 --- ecmascript/ecma_vm.cpp | 4 +- ecmascript/global_env.h | 34 ++++++++++++++ ecmascript/global_index_map.cpp | 2 +- ecmascript/mem/heap-inl.h | 2 +- ecmascript/serializer/value_serializer.cpp | 11 ----- ecmascript/snapshot/mem/snapshot_env.cpp | 53 +++++++++++----------- ecmascript/snapshot/mem/snapshot_env.h | 34 ++++++-------- 7 files changed, 81 insertions(+), 59 deletions(-) diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index dcad22a7d8..e90e0c2613 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -232,14 +232,15 @@ bool EcmaVM::Initialize() auto context = new EcmaContext(thread_); thread_->PushContext(context); [[maybe_unused]] EcmaHandleScope scope(thread_); + snapshotEnv_ = new SnapshotEnv(this); context->Initialize(); + snapshotEnv_->AddGlobalConstToMap(); thread_->SetGlueGlobalEnv(reinterpret_cast(context->GetGlobalEnv().GetTaggedType())); thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject()); thread_->SetCurrentEcmaContext(context); SingleCharTable::CreateSingleCharTable(thread_); GenerateInternalNativeMethods(); quickFixManager_ = new QuickFixManager(); - snapshotEnv_ = new SnapshotEnv(this); if (options_.GetEnableAsmInterpreter()) { thread_->GetCurrentEcmaContext()->LoadStubFile(); } @@ -343,6 +344,7 @@ EcmaVM::~EcmaVM() } if (snapshotEnv_ != nullptr) { + snapshotEnv_->ClearEnvMap(); delete snapshotEnv_; snapshotEnv_ = nullptr; } diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index 76b5618a15..1109eb7537 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -22,6 +22,7 @@ #include "ecmascript/js_handle.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/global_env_fields.h" +#include "ecmascript/snapshot/mem/snapshot_env.h" namespace panda::ecmascript { class JSThread; @@ -94,6 +95,33 @@ public: *reinterpret_cast(address) = thread; } + // For work serialize, add initialized global env object to snapshot env map + void AddValueToSnapshotEnv(const JSThread *thread, JSTaggedValue value, uint8_t index, uint32_t offset) + { + if (!value.IsInternalAccessor()) { + SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); + if (!RemoveValueFromSnapshotEnv(snapshotEnv, value, offset)) { + return; + } + size_t globalConstCount = thread->GlobalConstants()->GetConstantCount(); + snapshotEnv->Push(value.GetRawData(), index + globalConstCount); + } + } + + // For work serialize, remove old value from snapshot env map + bool RemoveValueFromSnapshotEnv(SnapshotEnv *snapshotEnv, JSTaggedValue value, uint32_t offset) + { + JSTaggedValue oldValue(Barriers::GetValue(this, offset)); + if (oldValue == value) { + return false; + } + if (oldValue.IsHeapObject() && !oldValue.IsInternalAccessor()) { + // Remove old value + snapshotEnv->Remove(oldValue.GetRawData()); + } + return true; + } + JSHandle GetSymbol(JSThread *thread, const JSHandle &string); JSHandle GetStringFunctionByName(JSThread *thread, const char *name); JSHandle GetStringPrototypeFunctionByName(JSThread *thread, const char *name); @@ -142,8 +170,11 @@ public: { \ uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ if (mode == WRITE_BARRIER && value.GetTaggedValue().IsHeapObject()) { \ + AddValueToSnapshotEnv(thread, value.GetTaggedValue(), index, offset); \ Barriers::SetObject(thread, this, offset, value.GetTaggedValue().GetRawData()); \ } else { \ + SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ + RemoveValueFromSnapshotEnv(snapshotEnv, value.GetTaggedValue(), offset); \ Barriers::SetPrimitive(this, offset, value.GetTaggedValue().GetRawData()); \ } \ } \ @@ -151,8 +182,11 @@ public: { \ uint32_t offset = HEADER_SIZE + index * JSTaggedValue::TaggedTypeSize(); \ if (mode == WRITE_BARRIER && value.IsHeapObject()) { \ + AddValueToSnapshotEnv(thread, value, index, offset); \ Barriers::SetObject(thread, this, offset, value.GetRawData()); \ } else { \ + SnapshotEnv *snapshotEnv = thread->GetEcmaVM()->GetSnapshotEnv(); \ + RemoveValueFromSnapshotEnv(snapshotEnv, value, offset); \ Barriers::SetPrimitive(this, offset, value.GetRawData()); \ } \ } diff --git a/ecmascript/global_index_map.cpp b/ecmascript/global_index_map.cpp index ab4cde05a9..1c4284ddd7 100644 --- a/ecmascript/global_index_map.cpp +++ b/ecmascript/global_index_map.cpp @@ -33,7 +33,7 @@ void GlobalIndexMap::InitGlobalIndexMap(const JSThread *thread, JSMutableHandle globalIndexMap) { if (globalIndexMap.GetTaggedValue().IsHeapObject()) { - return ; + return; } globalIndexMap.Update(PointerToIndexDictionary::Create(thread)); } diff --git a/ecmascript/mem/heap-inl.h b/ecmascript/mem/heap-inl.h index f12296eb77..1928d919e7 100644 --- a/ecmascript/mem/heap-inl.h +++ b/ecmascript/mem/heap-inl.h @@ -284,9 +284,9 @@ TaggedObject *Heap::AllocateHugeObject(size_t size) // if allocate huge object OOM, temporarily increase space size to avoid vm crash size_t oomOvershootSize = GetEcmaVM()->GetEcmaParamConfiguration().GetOutOfMemoryOvershootSize(); oldSpace_->IncreaseOutOfMemoryOvershootSize(oomOvershootSize); - object = reinterpret_cast(hugeObjectSpace_->Allocate(size, thread_)); DumpHeapSnapshotBeforeOOM(true, size, "Heap::AllocateHugeObject", false); StatisticHeapDetail(); + object = reinterpret_cast(hugeObjectSpace_->Allocate(size, thread_)); #ifndef ENABLE_DUMP_IN_FAULTLOG ThrowOutOfMemoryError(size, "Heap::AllocateHugeObject"); #endif diff --git a/ecmascript/serializer/value_serializer.cpp b/ecmascript/serializer/value_serializer.cpp index 72c8805f06..e506d99370 100644 --- a/ecmascript/serializer/value_serializer.cpp +++ b/ecmascript/serializer/value_serializer.cpp @@ -109,18 +109,7 @@ bool ValueSerializer::WriteValue(JSThread *thread, data_->SetIncompleteData(true); return false; } - if (value->IsHeapObject()) { - // Add fast path for string - if (value->IsString()) { - vm_->GetSnapshotEnv()->InitializeStringClass(); - } else { - vm_->GetSnapshotEnv()->Initialize(); - } - } SerializeJSTaggedValue(value.GetTaggedValue()); - if (value->IsHeapObject()) { - vm_->GetSnapshotEnv()->ClearEnvMap(); - } if (notSupport_) { LOG_ECMA(ERROR) << "ValueSerialize: serialize data is incomplete"; data_->SetIncompleteData(true); diff --git a/ecmascript/snapshot/mem/snapshot_env.cpp b/ecmascript/snapshot/mem/snapshot_env.cpp index 9e6bc023b8..ffe9c59c8d 100644 --- a/ecmascript/snapshot/mem/snapshot_env.cpp +++ b/ecmascript/snapshot/mem/snapshot_env.cpp @@ -19,49 +19,50 @@ #include "ecmascript/global_env.h" namespace panda::ecmascript { -void SnapshotEnv::Initialize() -{ - InitGlobalConst(); - InitGlobalEnv(); -} -void SnapshotEnv::InitializeStringClass() -{ - auto globalConst = const_cast(vm_->GetJSThread()->GlobalConstants()); - auto lineStringClass = globalConst->GetLineStringClass(); - rootObjectMap_.emplace(ToUintPtr(lineStringClass.GetTaggedObject()), globalConst->GetLineStringClassIndex()); - auto constStringClass = globalConst->GetConstantStringClass(); - rootObjectMap_.emplace(ToUintPtr(constStringClass.GetTaggedObject()), globalConst->GetConstStringClassIndex()); -} - -void SnapshotEnv::InitGlobalConst() +void SnapshotEnv::AddGlobalConstToMap() { auto globalConst = const_cast(vm_->GetJSThread()->GlobalConstants()); for (size_t index = 0; index < globalConst->GetConstantCount(); index++) { JSTaggedValue objectValue = globalConst->GetGlobalConstantObject(index); - if (objectValue.IsHeapObject()) { - rootObjectMap_.emplace(ToUintPtr(objectValue.GetTaggedObject()), index); + if (objectValue.IsHeapObject() && !objectValue.IsString()) { + rootObjectMap_.emplace(objectValue.GetRawData(), index); } } } -void SnapshotEnv::InitGlobalEnv() +JSTaggedType SnapshotEnv::RelocateRootObjectAddr(uint32_t index) { - auto globalEnv = vm_->GetGlobalEnv(); auto globalConst = const_cast(vm_->GetJSThread()->GlobalConstants()); - size_t globalEnvIndexStart = globalConst->GetConstantCount(); - for (size_t index = 0; index < globalEnv->GetGlobalEnvFieldSize(); index++) { - JSHandle objectValue = globalEnv->GetGlobalEnvObjectByIndex(index); - if (objectValue->IsHeapObject() && !objectValue->IsInternalAccessor()) { - rootObjectMap_.emplace(ToUintPtr(objectValue->GetTaggedObject()), index + globalEnvIndexStart); - } + size_t globalConstCount = globalConst->GetConstantCount(); + if (index < globalConstCount) { + JSTaggedValue obj = globalConst->GetGlobalConstantObject(index); + return obj.GetRawData(); } + JSHandle value = vm_->GetGlobalEnv()->GetNoLazyEnvObjectByIndex(index - globalConstCount); + return value->GetRawData(); } void SnapshotEnv::Iterate(const RootVisitor &v) { + std::vector> updatedObjPair; for (auto &it : rootObjectMap_) { - v(Root::ROOT_VM, ObjectSlot(reinterpret_cast(&(it.first)))); + auto objectAddr = it.first; + ObjectSlot slot(reinterpret_cast(&objectAddr)); + v(Root::ROOT_VM, slot); + // Record updated obj addr after gc + if (slot.GetTaggedType() != it.first) { + updatedObjPair.emplace_back(std::make_pair(it.first, slot.GetTaggedType())); + } + } + // Update hashmap, erase old objAddr, emplace updated objAddr + while (!updatedObjPair.empty()) { + auto pair = updatedObjPair.back(); + ASSERT(rootObjectMap_.find(pair.first) != rootObjectMap_.end()); + uint32_t index = rootObjectMap_.find(pair.first)->second; + rootObjectMap_.erase(pair.first); + rootObjectMap_.emplace(pair.second, index); + updatedObjPair.pop_back(); } } } // namespace panda::ecmascript diff --git a/ecmascript/snapshot/mem/snapshot_env.h b/ecmascript/snapshot/mem/snapshot_env.h index fbf00df147..0d23242b60 100644 --- a/ecmascript/snapshot/mem/snapshot_env.h +++ b/ecmascript/snapshot/mem/snapshot_env.h @@ -18,20 +18,17 @@ #include -#include "ecmascript/mem/object_xray.h" #include "ecmascript/mem/visitor.h" -#include "libpandabase/macros.h" namespace panda::ecmascript { class EcmaVM; class SnapshotEnv final { public: - explicit SnapshotEnv(EcmaVM *vm) : vm_(vm), objXRay_(vm) {} + explicit SnapshotEnv(EcmaVM *vm) : vm_(vm) {} ~SnapshotEnv() = default; - void Initialize(); - void InitializeStringClass(); + void AddGlobalConstToMap(); void ClearEnvMap() { @@ -40,7 +37,17 @@ public: void Iterate(const RootVisitor &v); - uint32_t FindEnvObjectIndex(uintptr_t objectAddr) const + void Push(JSTaggedType objectAddr, uint32_t index) + { + rootObjectMap_.emplace(objectAddr, index); + } + + void Remove(JSTaggedType objectAddr) + { + rootObjectMap_.erase(objectAddr); + } + + uint32_t FindEnvObjectIndex(JSTaggedType objectAddr) const { if (rootObjectMap_.find(objectAddr) != rootObjectMap_.end()) { return rootObjectMap_.find(objectAddr)->second; @@ -48,17 +55,7 @@ public: return MAX_UINT_32; } - JSTaggedType RelocateRootObjectAddr(uint32_t index) - { - auto globalConst = const_cast(vm_->GetJSThread()->GlobalConstants()); - size_t globalConstCount = globalConst->GetConstantCount(); - if (index < globalConstCount) { - JSTaggedValue obj = globalConst->GetGlobalConstantObject(index); - return obj.GetRawData(); - } - JSHandle value = vm_->GetGlobalEnv()->GetNoLazyEnvObjectByIndex(index - globalConstCount); - return value->GetRawData(); - } + JSTaggedType RelocateRootObjectAddr(uint32_t index); static constexpr size_t MAX_UINT_32 = 0xFFFFFFFF; @@ -70,8 +67,7 @@ private: void InitGlobalEnv(); EcmaVM *vm_; - ObjectXRay objXRay_; - CUnorderedMap rootObjectMap_; + std::unordered_map rootObjectMap_; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_ENV_H