From 7ebe6b476abf0ead6ba4a62dad9e0b71416309ae Mon Sep 17 00:00:00 2001 From: 5ec1cff Date: Sun, 18 Feb 2024 01:09:09 +0800 Subject: [PATCH] Fix static method hook lost if it is deoptimized before class initialization --- lsplant/src/main/jni/art/mirror/class.hpp | 8 ++++---- .../src/main/jni/art/runtime/class_linker.hpp | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lsplant/src/main/jni/art/mirror/class.hpp b/lsplant/src/main/jni/art/mirror/class.hpp index 6dce48c1d..dbd97cb65 100644 --- a/lsplant/src/main/jni/art/mirror/class.hpp +++ b/lsplant/src/main/jni/art/mirror/class.hpp @@ -27,21 +27,21 @@ class Class { return nullptr; } - using BackupMethods = std::list>; + using BackupMethods = phmap::flat_hash_map; inline static phmap::flat_hash_map> backup_methods_; inline static std::mutex backup_methods_lock_; static void BackupClassMethods(const dex::ClassDef *class_def, art::Thread *self) { - std::list> out; + BackupMethods out; if (!class_def) return; { hooked_classes_.if_contains(class_def, [&out](const auto &it) { for (auto method : it.second) { if (method->IsStatic()) { LOGV("Backup hooked method %p because of initialization", method); - out.emplace_back(method, method->GetEntryPoint()); + out.emplace(method, method->GetEntryPoint()); } } }); @@ -51,7 +51,7 @@ class Class { for (auto method : it.second) { if (method->IsStatic()) { LOGV("Backup deoptimized method %p because of initialization", method); - out.emplace_back(method, method->GetEntryPoint()); + out.emplace(method, method->GetEntryPoint()); } } }); diff --git a/lsplant/src/main/jni/art/runtime/class_linker.hpp b/lsplant/src/main/jni/art/runtime/class_linker.hpp index 0db166241..073abf954 100644 --- a/lsplant/src/main/jni/art/runtime/class_linker.hpp +++ b/lsplant/src/main/jni/art/runtime/class_linker.hpp @@ -79,19 +79,20 @@ class ClassLinker { for (const auto &[art_method, old_trampoline] : methods) { auto new_trampoline = art_method->GetEntryPoint(); art_method->SetEntryPoint(old_trampoline); - if (IsDeoptimized(art_method)) { + auto deoptimized = IsDeoptimized(art_method); + auto backup_method = IsHooked(art_method); + if (backup_method) { + // If deoptimized, the backup entrypoint should be already set to interpreter + if (!deoptimized && new_trampoline != old_trampoline) [[unlikely]] { + LOGV("propagate entrypoint for orig %p backup %p", art_method, backup_method); + backup_method->SetEntryPoint(new_trampoline); + } + } else if (deoptimized) { if (new_trampoline != art_quick_to_interpreter_bridge && new_trampoline != art_quick_generic_jni_trampoline) { LOGV("re-deoptimize for %p", art_method); SetEntryPointsToInterpreter(art_method); } - continue; - } - if (auto backup_method = IsHooked(art_method); backup_method) [[likely]] { - if (new_trampoline != old_trampoline) [[unlikely]] { - LOGV("propagate entrypoint for %p", backup_method); - backup_method->SetEntryPoint(new_trampoline); - } } } }