From c621f23352c4dcbbb8643850a1d4b9076dd0a41b Mon Sep 17 00:00:00 2001 From: wangyue Date: Mon, 15 Apr 2024 17:03:42 +0400 Subject: [PATCH] add jit escape while crash time more than three Signed-off-by: wangyue Change-Id: I9adfbfb57712403db7db7b28df0e32cdd3c9973e --- ecmascript/dfx/stackinfo/js_stackinfo.cpp | 16 ++++-- ecmascript/dfx/stackinfo/js_stackinfo.h | 3 +- ecmascript/ecma_context.cpp | 4 ++ ecmascript/ecma_vm.cpp | 10 ++++ ecmascript/napi/include/jsnapi_expo.h | 3 +- ecmascript/napi/jsnapi_expo.cpp | 66 ++++++++++++++++------- ecmascript/ohos/aot_crash_info.h | 20 +++++++ ecmascript/ohos/jit_tools.h | 32 +++++++++++ etc/arkcompiler.para.dac | 1 + js_runtime_config.gni | 1 + 10 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 ecmascript/ohos/jit_tools.h diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.cpp b/ecmascript/dfx/stackinfo/js_stackinfo.cpp index 9cd579b4a1..1d4c3e0ba4 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.cpp +++ b/ecmascript/dfx/stackinfo/js_stackinfo.cpp @@ -151,8 +151,12 @@ uint64_t GetMicrosecondsTimeStamp() return time.tv_sec * USEC_PER_SEC + time.tv_nsec / NSEC_PER_USEC; } -void BuildCrashInfo() +void JsStackInfo::BuildCrashInfo(bool isJscrash, uintptr_t pc) { + if (JsStackInfo::loader != nullptr && !JsStackInfo::loader->IsEnableAOT() && + JsStackInfo::options != nullptr && !JsStackInfo::options->IsEnableJIT()) { + return; + } std::string realOutPath; std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(ohos::AotCrashInfo::GetSandBoxPath()); if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) { @@ -162,7 +166,7 @@ void BuildCrashInfo() ohos::AotCrashInfo aotCrashInfo; std::string soBuildId = aotCrashInfo.GetRuntimeBuildId(); if (soBuildId == "") { - LOG_ECMA(INFO) << "can't get so buildId"; + LOG_ECMA(ERROR) << "can't get so buildId"; return; } realOutPath = realOutPath + "/" + ohos::AotCrashInfo::GetCrashFileName(); @@ -180,7 +184,9 @@ void BuildCrashInfo() ifile.close(); } ohos::CrashType type; - if (JsStackInfo::loader->IsEnableAOT()) { + if (isJscrash) { + type = ohos::CrashType::JS; + } else if (pc != 0 && JsStackInfo::loader->InsideAOT(pc)) { type = ohos::CrashType::AOT; } else { type = ohos::CrashType::OTHERS; @@ -279,13 +285,15 @@ void CrashCallback(char *buf __attribute__((unused)), size_t len __attribute__(( // 3. do not do much things inside callback, stack size is limited // 4. do not use normal log if (JsStackInfo::loader == nullptr) { + JsStackInfo::BuildCrashInfo(false); return; } if (!JsStackInfo::loader->InsideStub(pc) && !JsStackInfo::loader->InsideAOT(pc)) { + JsStackInfo::BuildCrashInfo(false); return; } LOG_ECMA(ERROR) << std::hex << "CrashCallback pc:" << pc << " fp:" << fp; - BuildCrashInfo(); + JsStackInfo::BuildCrashInfo(false, pc); FrameIterator frame(reinterpret_cast(fp)); bool isBuiltinStub = (frame.GetFrameType() == FrameType::OPTIMIZED_FRAME); Method *method = frame.CheckAndGetMethod(); diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.h b/ecmascript/dfx/stackinfo/js_stackinfo.h index 55161dc137..010e1bf786 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.h +++ b/ecmascript/dfx/stackinfo/js_stackinfo.h @@ -110,9 +110,10 @@ public: static std::vector BuildJsStackInfo(JSThread *thread, bool currentStack = false); static std::string BuildMethodTrace(Method *method, uint32_t pcOffset, bool enableStackSourceFile = true); static AOTFileManager *loader; + static JSRuntimeOptions *options; + static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0); }; void CrashCallback(char *buf, size_t len, void *ucontext); -void BuildCrashInfo(); uint64_t GetMicrosecondsTimeStamp(); } // namespace panda::ecmascript #endif // ECMASCRIPT_DFX_STACKINFO_JS_STACKINFO_H diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 99ec895d83..3d81748c26 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -48,6 +48,7 @@ #include "ecmascript/platform/log.h" #include "ecmascript/global_index_map.h" #include "ecmascript/sustaining_js_handle.h" +#include "ecmascript/dfx/stackinfo/js_stackinfo.h" namespace panda::ecmascript { using PathHelper = base::PathHelper; @@ -778,6 +779,9 @@ bool EcmaContext::ExecutePromisePendingJob() if (!thread_->HasPendingException()) { isProcessingPendingJob_ = true; job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); + if (thread_->HasPendingException()) { + JsStackInfo::BuildCrashInfo(true); + } isProcessingPendingJob_ = false; return true; } diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index b3cf132430..724e5fddcc 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -94,6 +94,7 @@ #include "ecmascript/ts_types/ts_manager.h" #include "ecmascript/ohos/enable_aot_list_helper.h" +#include "ecmascript/ohos/jit_tools.h" #ifdef JIT_SWITCH_COMPILE_MODE #include "base/startup/init/interfaces/innerkits/include/syspara/parameters.h" @@ -103,6 +104,7 @@ namespace panda::ecmascript { using RandomGenerator = base::RandomGenerator; using PGOProfilerManager = pgo::PGOProfilerManager; AOTFileManager *JsStackInfo::loader = nullptr; +JSRuntimeOptions *JsStackInfo::options = nullptr; EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options) { @@ -125,6 +127,9 @@ EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options) if (JsStackInfo::loader == nullptr) { JsStackInfo::loader = vm->GetAOTFileManager(); } + if (JsStackInfo::options == nullptr) { + JsStackInfo::options = &(vm->GetJSOptions()); + } #if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS) if (SetThreadInfoCallback != nullptr) { SetThreadInfoCallback(CrashCallback); @@ -173,6 +178,11 @@ void EcmaVM::PostFork() bool isEnableJit = options_.IsEnableJIT() && options_.GetEnableAsmInterpreter(); if (ohos::EnableAotListHelper::GetJitInstance()->IsEnableJit(bundleName) && options_.GetEnableAsmInterpreter()) { Jit::GetInstance()->SetEnableOrDisable(options_, isEnableJit); + bool jitEscapeDisable = panda::ecmascript::ohos::GetJitEscapeEanble(); + if ((!jitEscapeDisable) && JSNApi::IsJitEscape()) { + isEnableJit = false; + options_.SetEnableJIT(false); + } if (isEnableJit) { EnableJit(); } diff --git a/ecmascript/napi/include/jsnapi_expo.h b/ecmascript/napi/include/jsnapi_expo.h index 38aef5df57..16dacde24e 100644 --- a/ecmascript/napi/include/jsnapi_expo.h +++ b/ecmascript/napi/include/jsnapi_expo.h @@ -1402,6 +1402,7 @@ public: static Local CreateLocal(const EcmaVM *vm, JSValueRef src); + static bool IsJitEscape(); private: static int vmCount_; static bool initialize_; @@ -1417,7 +1418,7 @@ private: static uintptr_t ClearWeak(const EcmaVM *vm, uintptr_t localAddress); static bool IsWeak(const EcmaVM *vm, uintptr_t localAddress); static void DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr); - static bool IsAotCrash(); + static bool IsAotEscape(); template friend class Global; template diff --git a/ecmascript/napi/jsnapi_expo.cpp b/ecmascript/napi/jsnapi_expo.cpp index e2061978a8..0c7ff22942 100644 --- a/ecmascript/napi/jsnapi_expo.cpp +++ b/ecmascript/napi/jsnapi_expo.cpp @@ -106,6 +106,7 @@ #include "ecmascript/platform/mutex.h" #include "ecmascript/platform/log.h" #include "ecmascript/jit/jit.h" +#include "ecmascript/dfx/stackinfo/js_stackinfo.h" namespace panda { using ecmascript::AccessorData; @@ -198,6 +199,8 @@ using ModulePathHelper = ecmascript::ModulePathHelper; using JsDebuggerManager = ecmascript::tooling::JsDebuggerManager; using FrameIterator = ecmascript::FrameIterator; using Concurrent = ecmascript::Concurrent; +using CrashInfo = ecmascript::ohos::AotCrashInfo; +using CrashType = ecmascript::ohos::CrashType; namespace { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) @@ -2454,6 +2457,9 @@ Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, info->SetCallArg(i, arg.GetTaggedValue()); } JSTaggedValue result = JSFunction::Call(info); + if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); + } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); @@ -3691,44 +3697,51 @@ void JSNApi::SetDeviceDisconnectCallback(EcmaVM *vm, DeviceDisconnectCallback cb vm->SetDeviceDisconnectCallback(cb); } -bool JSNApi::IsAotCrash() +std::map CollectCrashSum() { + std::map escapeMap; std::string realOutPath; - std::string arkProfilePath = ecmascript::ohos::AotCrashInfo::GetSandBoxPath(); + std::string arkProfilePath = CrashInfo::GetSandBoxPath(); std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(arkProfilePath); if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) { - return false; + return escapeMap; } - realOutPath = realOutPath + "/" + ecmascript::ohos::AotCrashInfo::GetCrashFileName(); - ecmascript::ohos::AotCrashInfo aotCrashInfo; + realOutPath = realOutPath + "/" + CrashInfo::GetCrashFileName(); + CrashInfo aotCrashInfo; std::string soBuildId = aotCrashInfo.GetRuntimeBuildId(); std::ifstream ifile(realOutPath.c_str()); - int aotCrashCount = 0; - int othersCrashCount = 0; if (ifile.is_open()) { std::string iline; while (ifile >> iline) { - std::string buildId = ecmascript::ohos::AotCrashInfo::GetBuildId(iline); - ecmascript::ohos::CrashType type = ecmascript::ohos::AotCrashInfo::GetCrashType(iline); - if (type == ecmascript::ohos::CrashType::AOT && buildId == soBuildId) { - aotCrashCount++; - } - if (type == ecmascript::ohos::CrashType::OTHERS && buildId == soBuildId) { - othersCrashCount++; + std::string buildId = CrashInfo::GetBuildId(iline); + CrashType type = CrashInfo::GetCrashType(iline); + if (buildId == soBuildId) { + escapeMap[type]++; } } ifile.close(); - if (aotCrashCount >= ecmascript::ohos::AotCrashInfo::GetAotCrashCount() - || othersCrashCount >= ecmascript::ohos::AotCrashInfo::GetOthersCrashCount()) { - return true; - } } - return false; + return escapeMap; +} + +bool JSNApi::IsAotEscape() +{ + auto escapeMap = CollectCrashSum(); + return escapeMap[CrashType::AOT] >= CrashInfo::GetAotCrashCount() || + escapeMap[CrashType::OTHERS] >= CrashInfo::GetOthersCrashCount(); +} + +bool JSNApi::IsJitEscape() +{ + auto escapeMap = CollectCrashSum(); + return escapeMap[CrashType::JIT] >= CrashInfo::GetJitCrashCount() || + escapeMap[CrashType::AOT] >= CrashInfo::GetAotCrashCount() || + escapeMap[CrashType::OTHERS] >= CrashInfo::GetOthersCrashCount(); } void JSNApi::LoadAotFile(EcmaVM *vm, const std::string &moduleName) { - if (IsAotCrash()) { + if (IsAotEscape()) { LOG_ECMA(INFO) << "Stop load AOT because there are more crashes"; return; } @@ -3760,6 +3773,7 @@ bool JSNApi::ExecuteInContext(EcmaVM *vm, const std::string &fileName, const std EcmaContext::MountContext(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileName.c_str(), entry, needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName @@ -3777,6 +3791,7 @@ bool JSNApi::Execute(EcmaVM *vm, const std::string &fileName, const std::string ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileName.c_str(), entry, needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName @@ -3795,6 +3810,7 @@ bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::s ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename @@ -3813,6 +3829,7 @@ int JSNApi::ExecuteWithSingletonPatternFlag(EcmaVM *vm, const std::string &bundl moduleName.c_str(), ohmurl.c_str(), isSingletonPattern); if (!result) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Execute with singleton-pattern flag failed with bundle name is'" << bundleName @@ -3830,6 +3847,7 @@ bool JSNApi::ExecuteModuleBuffer(EcmaVM *vm, const uint8_t *data, int32_t size, ecmascript::ThreadManagedScope scope(thread); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBuffer(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute module buffer file '" << filename; @@ -3851,6 +3869,7 @@ bool JSNApi::ExecuteSecure(EcmaVM *vm, uint8_t *data, int32_t size, const std::s if (!ecmascript::JSPandaFileExecutor::ExecuteFromBufferSecure(thread, data, size, entry, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename @@ -3873,6 +3892,7 @@ bool JSNApi::ExecuteModuleBufferSecure(EcmaVM *vm, uint8_t* data, int32_t size, if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBufferSecure(thread, data, size, filename.c_str(), needUpdate)) { if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); thread->GetCurrentEcmaContext()->HandleUncaughtException(); } LOG_ECMA(ERROR) << "Cannot execute module buffer file '" << filename; @@ -3970,6 +3990,9 @@ void JSNApi::ExecutePendingJob(const EcmaVM *vm) CROSS_THREAD_AND_EXCEPTION_CHECK(vm); ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); EcmaVM::ConstCast(vm)->GetJSThread()->GetCurrentEcmaContext()->ExecutePromisePendingJob(); + if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); + } } uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress) @@ -4182,6 +4205,9 @@ bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, false); ecmascript::ThreadManagedScope scope(vm->GetJSThread()); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, ENTRY_POINTER, file.c_str())) { + if (thread->HasPendingException()) { + ecmascript::JsStackInfo::BuildCrashInfo(true); + } std::cerr << "Cannot execute panda file from memory" << std::endl; return false; } diff --git a/ecmascript/ohos/aot_crash_info.h b/ecmascript/ohos/aot_crash_info.h index 6db49623f9..ad15b9daa8 100644 --- a/ecmascript/ohos/aot_crash_info.h +++ b/ecmascript/ohos/aot_crash_info.h @@ -23,11 +23,15 @@ namespace panda::ecmascript::ohos { V(AOT) \ V(OTHERS) \ V(NONE) \ + V(JIT) \ + V(JS) \ enum class CrashType { AOT, + JIT, OTHERS, NONE, + JS, }; class AotCrashInfo { constexpr static const char *const SANDBOX_ARK_PROFILE_PATH = "/data/storage/ark-profile"; @@ -38,6 +42,8 @@ class AotCrashInfo { constexpr static int OTHERS_CRASH_COUNT = 3; constexpr static int CRASH_LOG_SIZE = 3; constexpr static int NT_GNU_BUILD_ID = 3; + constexpr static int JIT_CRASH_COUNT = 1; + constexpr static int JS_CRASH_COUNT = 3; public: explicit AotCrashInfo() = default; @@ -49,6 +55,10 @@ public: if (splitCrashInfo.size() == CRASH_LOG_SIZE) { if (splitCrashInfo[CRASH_LOG_SIZE - 1] == GetCrashTypeStr(CrashType::AOT)) { return CrashType::AOT; + } else if (splitCrashInfo[CRASH_LOG_SIZE - 1] == GetCrashTypeStr(CrashType::JIT)) { + return CrashType::JIT; + } else if (splitCrashInfo[CRASH_LOG_SIZE - 1] == GetCrashTypeStr(CrashType::JS)) { + return CrashType::JS; } else if (splitCrashInfo[CRASH_LOG_SIZE - 1] == GetCrashTypeStr(CrashType::OTHERS)) { return CrashType::OTHERS; } @@ -71,6 +81,16 @@ public: return AOT_CRASH_COUNT; } + static int GetJitCrashCount() + { + return JIT_CRASH_COUNT; + } + + static int GetJsCrashCount() + { + return JS_CRASH_COUNT; + } + static int GetOthersCrashCount() { return OTHERS_CRASH_COUNT; diff --git a/ecmascript/ohos/jit_tools.h b/ecmascript/ohos/jit_tools.h new file mode 100644 index 0000000000..748bc493be --- /dev/null +++ b/ecmascript/ohos/jit_tools.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ECMASCRIPT_JIT_TOOLS_H +#define ECMASCRIPT_JIT_TOOLS_H + +#ifdef JIT_ESCAPE_ENABLE +#include "base/startup/init/interfaces/innerkits/include/syspara/parameters.h" +#endif + +namespace panda::ecmascript::ohos { + +bool GetJitEscapeEanble() +{ +#ifdef JIT_ESCAPE_ENABLE + return OHOS::system::GetBoolParameter("ark.jit.escape.disable", false); +#endif + return true; +} +} +#endif // ECMASCRIPT_JIT_TOOLS_H diff --git a/etc/arkcompiler.para.dac b/etc/arkcompiler.para.dac index 6c3baf886c..afc163e39d 100644 --- a/etc/arkcompiler.para.dac +++ b/etc/arkcompiler.para.dac @@ -12,6 +12,7 @@ # limitations under the License. ark.profile. = shell:shell:0775 +ark.jit.escape.disable = shell:shell:0775 persist.ark.properties = shell:shell:0775 persist.ark.longpausetime = shell:shell:0775 persist.ark.asminterpreter = shell:shell:0775 diff --git a/js_runtime_config.gni b/js_runtime_config.gni index 742ce56729..1cdf28a35b 100644 --- a/js_runtime_config.gni +++ b/js_runtime_config.gni @@ -207,6 +207,7 @@ template("libark_jsruntime_common_set") { is_ohos && is_standard_system) { external_deps += [ "init:libbegetutil" ] defines += [ "JIT_SWITCH_COMPILE_MODE" ] + defines += [ "JIT_ESCAPE_ENABLE" ] } if (enable_target_compilation) { -- Gitee