From f032571cb7e88f08aeb02e0ddb4b829e492209e0 Mon Sep 17 00:00:00 2001 From: wupengyong Date: Tue, 2 Jul 2024 15:38:59 +0800 Subject: [PATCH] Execute TranslateClasses in other thread Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IA7GHA?from=project-issue Test: Build & Boot devices Signed-off-by: wupengyong Change-Id: I463165678ac1b3079e7e22fc19088deae70563a6 --- ecmascript/ecma_vm.cpp | 2 + ecmascript/ecma_vm.h | 16 ++++ ecmascript/js_runtime_options.cpp | 12 ++- ecmascript/js_runtime_options.h | 12 +++ ecmascript/jspandafile/js_pandafile.cpp | 92 +++++++++++++++++++ ecmascript/jspandafile/js_pandafile.h | 44 +++++++++ .../jspandafile/js_pandafile_manager.cpp | 6 +- .../jspandafile/panda_file_translator.cpp | 41 +++++++++ .../jspandafile/panda_file_translator.h | 2 + 9 files changed, 225 insertions(+), 2 deletions(-) diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index cc205d97ec..511aadf5c4 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -198,6 +198,7 @@ void EcmaVM::PreFork() heap_->AdjustSpaceSizeForAppSpawn(); heap_->GetReadOnlySpace()->SetReadOnly(); heap_->DisableParallelGC(); + SetPostForked(false); SharedHeap::GetInstance()->DisableParallelGC(thread_); } @@ -207,6 +208,7 @@ void EcmaVM::PostFork() heap_->SetHeapMode(HeapMode::SHARE); GetAssociatedJSThread()->PostFork(); Taskpool::GetCurrentTaskpool()->Initialize(); + SetPostForked(true); LOG_ECMA(INFO) << "multi-thread check enabled: " << options_.EnableThreadCheck(); #if defined(JIT_ESCAPE_ENABLE) || defined(AOT_ESCAPE_ENABLE) SignalAllReg(); diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index c2fbe93bf4..2e72e1e616 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -131,6 +131,21 @@ public: return initialized_; } + void SetPostForked(bool isPostForked) + { + isPostForked_ = isPostForked; + } + + bool IsPostForked() const + { + return isPostForked_; + } + + bool IsAsynTranslateClasses() + { + return IsPostForked() && GetJSOptions().IsAsyncLoadAbc(); + } + ObjectFactory *GetFactory() const { return factory_; @@ -838,6 +853,7 @@ private: JSRuntimeOptions options_; bool icEnabled_ {true}; bool initialized_ {false}; + bool isPostForked_ {false}; GCStats *gcStats_ {nullptr}; GCKeyStats *gcKeyStats_ {nullptr}; EcmaStringTable *stringTable_ {nullptr}; diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index e816b62501..f6fb7d5297 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -185,7 +185,8 @@ const std::string PUBLIC_API HELP_OPTION_MSG = "--compiler-opt-induction-variable: Enable induciton variable analysis for aot compiler. Default: 'false'\n" "--compiler-trace-induction-variable: Enable tracing induction variable for aot compiler. Default: 'false'\n" "--compiler-memory-analysis: Enable memory analysis for aot compiler. Default: 'true'\n" - "--compiler-enable-jit-fast-compile: Enable jit fast compile. Default: 'false'\n\n"; + "--compiler-enable-jit-fast-compile: Enable jit fast compile. Default: 'false'\n" + "--async-load-abc: Enable asynchronous load abc. Default: 'true'\n\n"; bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) { @@ -312,6 +313,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-baselinejit-hotness-threshold", required_argument, nullptr, OPTION_COMPILER_BASELINEJIT_HOTNESS_THRESHOLD}, {"compiler-force-baselinejit-compile-main", required_argument, nullptr, OPTION_COMPILER_FORCE_BASELINEJIT_COMPILE_MAIN}, {"compiler-enable-jit-fast-compile", required_argument, nullptr, OPTION_COMPILER_ENABLE_JIT_FAST_COMPILE}, + {"async-load-abc", required_argument, nullptr, OPTION_ASYNC_LOAD_ABC}, {nullptr, 0, nullptr, 0}, }; @@ -1188,6 +1190,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_ASYNC_LOAD_ABC: + ret = ParseBoolParam(&argBool); + if (ret) { + SetAsyncLoadAbc(argBool); + } else { + return false; + } + break; default: LOG_ECMA(ERROR) << "Invalid option\n"; return false; diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 0075e84e48..94a5419b92 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -196,6 +196,7 @@ enum CommandValues { OPTION_ENABLE_AOT_CRASH_ESCAPE, OPTION_COMPILER_ENABLE_JIT_FAST_COMPILE, OPTION_COMPILER_BASELINE_PGO, + OPTION_ASYNC_LOAD_ABC, }; static_assert(OPTION_SPLIT_ONE == 64); @@ -1808,6 +1809,16 @@ public: return enableFrameworkAOT_; } + void SetAsyncLoadAbc(bool value) + { + asyncLoadAbc_ = value; + } + + bool IsAsyncLoadAbc() const + { + return asyncLoadAbc_; + } + public: static constexpr int32_t MAX_APP_COMPILE_METHOD_SIZE = 1_KB; @@ -1974,6 +1985,7 @@ private: bool enableJitFrame_{false}; bool disableCodeSign_{false}; bool enableBaselinePgo_{false}; + bool asyncLoadAbc_ {true}; }; } // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index 663a5d4964..1c097ed976 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -131,6 +131,7 @@ uint32_t JSPandaFile::GetOrInsertConstantPool(ConstPoolType type, uint32_t offse void JSPandaFile::InitializeUnMergedPF() { Span classIndexes = pf_->GetClasses(); + numClasses_ = classIndexes.size(); JSRecordInfo info; for (const uint32_t index : classIndexes) { panda_file::File::EntityId classId(index); @@ -172,6 +173,7 @@ void JSPandaFile::InitializeUnMergedPF() void JSPandaFile::InitializeMergedPF() { Span classIndexes = pf_->GetClasses(); + numClasses_ = classIndexes.size(); for (const uint32_t index : classIndexes) { panda_file::File::EntityId classId(index); if (pf_->IsExternal(classId)) { @@ -449,4 +451,94 @@ void JSPandaFile::ClearNameMap() recordNameMap_.clear(); } } + +size_t JSPandaFile::GetClassAndMethodIndex(size_t *methodIdx) +{ + LockHolder lock(classIndexMutex_); + size_t result = 0; + Span classIndexes = GetClasses(); + uint32_t index = 0; + do { + result = classIndex_++; + if (result >= numClasses_) { + return result; + } + index = classIndexes[result]; + } while (IsExternal(panda_file::File::EntityId(index))); + + *methodIdx = methodIndex_; + panda_file::File::EntityId classId(classIndexes[result]); + panda_file::ClassDataAccessor cda(*pf_, classId); + methodIndex_ += cda.GetMethodsNumber(); + return result; +} + +bool JSPandaFile::TranslateClassesTask::Run([[maybe_unused]] uint32_t threadIndex) +{ + jsPandaFile_->TranslateClass(thread_, *methodNamePtr_); + jsPandaFile_->ReduceTaskCount(); + return true; +} + +void JSPandaFile::TranslateClass(JSThread *thread, const CString &methodName) +{ + size_t methodIdx = 0; + size_t classIdx = GetClassAndMethodIndex(&methodIdx); + while (classIdx < numClasses_) { + PandaFileTranslator::TranslateClass(thread, this, methodName, methodIdx, classIdx); + classIdx = GetClassAndMethodIndex(&methodIdx); + } +} + +void JSPandaFile::PostInitializeMethodTask(JSThread *thread, const std::shared_ptr &methodNamePtr) +{ + IncreaseTaskCount(); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(thread->GetThreadId(), thread, this, methodNamePtr)); +} + +void JSPandaFile::IncreaseTaskCount() +{ + LockHolder holder(waitTranslateClassFinishedMutex_); + runningTaskCount_++; +} + +void JSPandaFile::WaitTranslateClassTaskFinished() +{ + LockHolder holder(waitTranslateClassFinishedMutex_); + while (runningTaskCount_ > 0) { + waitTranslateClassFinishedCV_.Wait(&waitTranslateClassFinishedMutex_); + } +} + +void JSPandaFile::ReduceTaskCount() +{ + LockHolder holder(waitTranslateClassFinishedMutex_); + runningTaskCount_--; + if (runningTaskCount_ == 0) { + waitTranslateClassFinishedCV_.SignalAll(); + } +} + +void JSPandaFile::SetAllMethodLiteralToMap() +{ + // async to optimize SetAllMethodLiteralToMap later + MethodLiteral *methodLiterals = GetMethodLiterals(); + size_t methodIdx = 0; + while (methodIdx < numMethods_) { + MethodLiteral *methodLiteral = methodLiterals + (methodIdx++); + SetMethodLiteralToMap(methodLiteral); + } +} + +void JSPandaFile::TranslateClasses(JSThread *thread, const CString &methodName) +{ + const std::shared_ptr methodNamePtr = std::make_shared(methodName); + for (int i = 0; i < Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); i++) { + PostInitializeMethodTask(thread, methodNamePtr); + } + TranslateClass(thread, methodName); + WaitTranslateClassTaskFinished(); + SetAllMethodLiteralToMap(); +} } // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index 0d00340339..b8072f7d82 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -21,6 +21,7 @@ #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/mem/c_containers.h" +#include "ecmascript/taskpool/task.h" #include "libpandafile/file-inl.h" #include "libpandafile/file_items.h" @@ -89,6 +90,23 @@ public: JSPandaFile(const panda_file::File *pf, const CString &descriptor); ~JSPandaFile(); + class TranslateClassesTask : public Task { + public: + TranslateClassesTask(int32_t id, JSThread *thread, JSPandaFile *jsPandaFile, + const std::shared_ptr &methodNamePtr) + : Task(id), thread_(thread), jsPandaFile_(jsPandaFile), methodNamePtr_(methodNamePtr) {}; + ~TranslateClassesTask() override = default; + bool Run(uint32_t threadIndex) override; + + NO_COPY_SEMANTIC(TranslateClassesTask); + NO_MOVE_SEMANTIC(TranslateClassesTask); + + private: + JSThread *thread_ {nullptr}; + JSPandaFile *jsPandaFile_ {nullptr}; + std::shared_ptr methodNamePtr_; + }; + const CString &GetJSPandaFileDesc() const { return desc_; @@ -440,10 +458,29 @@ public: } void ClearNameMap(); + + void TranslateClasses(JSThread *thread, const CString &methodName); + private: void InitializeUnMergedPF(); void InitializeMergedPF(); + void WaitTranslateClassTaskFinished(); + + void NotifyTranslateClassTaskCompleted(); + + void IncreaseTaskCount(); + + void TranslateClass(JSThread *thread, const CString &methodName); + + void PostInitializeMethodTask(JSThread *thread, const std::shared_ptr &methodNamePtr); + + void ReduceTaskCount(); + + void SetAllMethodLiteralToMap(); + + size_t GetClassAndMethodIndex(size_t *methodIdx); + static constexpr size_t VERSION_SIZE = 4; static constexpr std::array OLD_VERSION {0, 0, 0, 2}; @@ -457,9 +494,16 @@ private: CUnorderedMap recordNameMap_; Mutex methodNameMapMutex_; Mutex recordNameMapMutex_; + Mutex waitTranslateClassFinishedMutex_; + Mutex classIndexMutex_; + ConditionVariable waitTranslateClassFinishedCV_; + uint32_t runningTaskCount_ {0}; + size_t classIndex_ {0}; + size_t methodIndex_ {0}; CUnorderedMap constpoolMap_; uint32_t numMethods_ {0}; + uint32_t numClasses_ {0}; MethodLiteral *methodLiterals_ {nullptr}; CString desc_; uint32_t anFileInfoIndex_ {INVALID_INDEX}; diff --git a/ecmascript/jspandafile/js_pandafile_manager.cpp b/ecmascript/jspandafile/js_pandafile_manager.cpp index 9cbc5b410d..f39e6bad63 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.cpp +++ b/ecmascript/jspandafile/js_pandafile_manager.cpp @@ -544,7 +544,11 @@ std::shared_ptr JSPandaFileManager::GenerateJSPandaFile(JSThread *t methodName = JSPandaFile::ENTRY_FUNCTION_NAME; } } - PandaFileTranslator::TranslateClasses(thread, newJsPandaFile.get(), methodName); + if (newJsPandaFile->IsNewVersion() && vm->IsAsynTranslateClasses()) { + newJsPandaFile->TranslateClasses(thread, methodName); + } else { + PandaFileTranslator::TranslateClasses(thread, newJsPandaFile.get(), methodName); + } { LockHolder lock(jsPandaFileLock_); diff --git a/ecmascript/jspandafile/panda_file_translator.cpp b/ecmascript/jspandafile/panda_file_translator.cpp index 35b51f710b..130e8c387a 100644 --- a/ecmascript/jspandafile/panda_file_translator.cpp +++ b/ecmascript/jspandafile/panda_file_translator.cpp @@ -102,6 +102,47 @@ void PandaFileTranslator::TranslateClasses(const JSThread *thread, JSPandaFile * } } +void PandaFileTranslator::TranslateClass(const JSThread *thread, JSPandaFile *jsPandaFile, + const CString &methodName, size_t methodIdx, size_t classIdx) +{ + ASSERT(jsPandaFile != nullptr && jsPandaFile->GetMethodLiterals() != nullptr); + MethodLiteral *methodLiterals = jsPandaFile->GetMethodLiterals(); + const panda_file::File *pf = jsPandaFile->GetPandaFile(); + Span classIndexes = jsPandaFile->GetClasses(); + const uint32_t index = classIndexes[classIdx]; + panda_file::File::EntityId classId(index); + panda_file::ClassDataAccessor cda(*pf, classId); + CString recordName = JSPandaFile::ParseEntryPoint(utf::Mutf8AsCString(cda.GetDescriptor())); + bool isUpdateMainMethodIndex = false; + cda.EnumerateMethods([thread, jsPandaFile, methodLiterals, &methodIdx, pf, &methodName, + &recordName, &isUpdateMainMethodIndex] + (panda_file::MethodDataAccessor &mda) { + auto methodId = mda.GetMethodId(); + CString name = reinterpret_cast(jsPandaFile->GetStringData(mda.GetNameId()).data); + auto methodOffset = methodId.GetOffset(); + if (jsPandaFile->IsBundlePack()) { + if (!isUpdateMainMethodIndex && name == methodName) { + jsPandaFile->UpdateMainMethodIndex(methodOffset); + isUpdateMainMethodIndex = true; + } + } else { + if (!isUpdateMainMethodIndex && JSPandaFile::IsEntryOrPatch(name)) { + jsPandaFile->UpdateMainMethodIndex(methodOffset, recordName); + isUpdateMainMethodIndex = true; + } + } + + MethodLiteral *methodLiteral = methodLiterals + (methodIdx++); + InitializeMemory(methodLiteral, methodId); + methodLiteral->Initialize(jsPandaFile, thread); + // IsNewVersion + panda_file::IndexAccessor indexAccessor(*pf, methodId); + panda_file::FunctionKind funcKind = indexAccessor.GetFunctionKind(); + FunctionKind kind = JSPandaFile::GetFunctionKind(funcKind); + methodLiteral->SetFunctionKind(kind); + }); +} + JSHandle PandaFileTranslator::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile, std::string_view entryPoint) { diff --git a/ecmascript/jspandafile/panda_file_translator.h b/ecmascript/jspandafile/panda_file_translator.h index 9c52a4739c..60dd77793c 100644 --- a/ecmascript/jspandafile/panda_file_translator.h +++ b/ecmascript/jspandafile/panda_file_translator.h @@ -38,6 +38,8 @@ public: static JSHandle GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile, std::string_view entryPoint); static void TranslateClasses(const JSThread *thread, JSPandaFile *jsPandaFile, const CString &methodName); + static void TranslateClass(const JSThread *thread, JSPandaFile *jsPandaFile, const CString &methodName, + size_t methodIdx, size_t classIdx); private: static JSHandle GenerateProgramInternal(EcmaVM *vm, MethodLiteral *mainMethodLiteral,