From a7b0b022c21cca45a3670211c2c13c498a6c8d35 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 27 Jun 2024 00:13:45 +0800 Subject: [PATCH] Propagate hotness counter for backup method to target to avoid crash Fix #99 See https://5ec1cff.github.io/my-blog/2024/06/27/lsp-crash-analysis/ --- lsplant/src/main/jni/CMakeLists.txt | 4 +- lsplant/src/main/jni/art/runtime/jit/jit.cxx | 56 ++++++++++++++++++++ lsplant/src/main/jni/common.cxx | 2 +- lsplant/src/main/jni/lsplant.cc | 6 +++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 lsplant/src/main/jni/art/runtime/jit/jit.cxx diff --git a/lsplant/src/main/jni/CMakeLists.txt b/lsplant/src/main/jni/CMakeLists.txt index 6eada45df..0459321ea 100644 --- a/lsplant/src/main/jni/CMakeLists.txt +++ b/lsplant/src/main/jni/CMakeLists.txt @@ -16,8 +16,8 @@ if (LSPLANT_STANDALONE) endif() set(SOURCES lsplant.cc) -file(GLOB_RECURSE MODULE_SOURCES "*.cxx") -file(GLOB_RECURSE MODULE_INTERFACES "*.ixx") +file(GLOB_RECURSE MODULE_SOURCES CONFIGURE_DEPENDS "*.cxx") +file(GLOB_RECURSE MODULE_INTERFACES CONFIGURE_DEPENDS "*.ixx") set(DEX_BUILDER_BUILD_SHARED OFF CACHE INTERNAL "" FORCE) add_subdirectory(external/dex_builder) diff --git a/lsplant/src/main/jni/art/runtime/jit/jit.cxx b/lsplant/src/main/jni/art/runtime/jit/jit.cxx new file mode 100644 index 000000000..3e57bfca1 --- /dev/null +++ b/lsplant/src/main/jni/art/runtime/jit/jit.cxx @@ -0,0 +1,56 @@ +module; + +#include "logging.hpp" +#include "utils/hook_helper.hpp" + +export module jit; + +import art_method; +import common; +import thread; + +namespace lsplant::art::jit { +enum class CompilationKind { + kOsr [[maybe_unused]], + kBaseline [[maybe_unused]], + kOptimized, +}; + +export class Jit { + CREATE_MEM_HOOK_STUB_ENTRY( + "_ZN3art3jit3Jit27EnqueueOptimizedCompilationEPNS_9ArtMethodEPNS_6ThreadE", void, + EnqueueOptimizedCompilation, (Jit * thiz, ArtMethod *method, Thread *self), { + if (auto target = IsBackup(method); target) [[unlikely]] { + LOGD("Propagate enqueue compilation: %p -> %p", method, target); + method = target; + } + return backup(thiz, method, self); + }); + + CREATE_MEM_HOOK_STUB_ENTRY( + "_ZN3art3jit3Jit14AddCompileTaskEPNS_6ThreadEPNS_9ArtMethodENS_15CompilationKindEb", void, + AddCompileTask, + (Jit * thiz, Thread *self, ArtMethod *method, CompilationKind compilation_kind, + bool precompile), + { + if (compilation_kind == CompilationKind::kOptimized && !precompile/* && in_enqueue*/) { + if (auto backup = IsHooked(method); backup) [[unlikely]] { + LOGD("Propagate compile task: %p -> %p", method, backup); + method = backup; + } + } + return backup(thiz, self, method, compilation_kind, precompile); + }); + +public: + static bool Init(const HookHandler &handler) { + auto sdk_int = GetAndroidApiLevel(); + + if (sdk_int <= __ANDROID_API_U__) [[likely]] { + HookSyms(handler, EnqueueOptimizedCompilation); + HookSyms(handler, AddCompileTask); + } + return true; + } +}; +} // namespace lsplant::art::jit diff --git a/lsplant/src/main/jni/common.cxx b/lsplant/src/main/jni/common.cxx index da0f9c922..d83ca366b 100644 --- a/lsplant/src/main/jni/common.cxx +++ b/lsplant/src/main/jni/common.cxx @@ -69,7 +69,7 @@ export { return v + size - 1 - ((v + size - 1) & (size - 1)); } - inline auto GetAndroidApiLevel() { + [[gnu::const]] inline auto GetAndroidApiLevel() { static auto kApiLevel = []() { std::array prop_value; __system_property_get("ro.build.version.sdk", prop_value.data()); diff --git a/lsplant/src/main/jni/lsplant.cc b/lsplant/src/main/jni/lsplant.cc index 5f72dd19c..718deae8f 100644 --- a/lsplant/src/main/jni/lsplant.cc +++ b/lsplant/src/main/jni/lsplant.cc @@ -25,6 +25,7 @@ import scope_gc_critical_section; import jit_code_cache; import jni_id_manager; import dex_file; +import jit; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" @@ -42,6 +43,7 @@ using art::Runtime; using art::Thread; using art::gc::ScopedGCCriticalSection; using art::jit::JitCodeCache; +using art::jit::Jit; using art::jni::JniIdManager; using art::mirror::Class; using art::thread_list::ScopedSuspendAll; @@ -286,6 +288,10 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) { LOGE("Failed to init jit code cache"); return false; } + if (!Jit::Init(handler)) { + LOGE("Failed to init jit"); + return false; + } if (!DexFile::Init(env, handler)) { LOGE("Failed to init dex file"); return false;