Use phmap

This commit is contained in:
LoveSy 2023-10-04 23:53:48 +08:00
parent 7a6940e722
commit c18f276177
No known key found for this signature in database
5 changed files with 62 additions and 80 deletions

View File

@ -2,9 +2,9 @@ plugins {
alias(libs.plugins.lsplugin.publish) alias(libs.plugins.lsplugin.publish)
} }
val androidTargetSdkVersion by extra(33) val androidTargetSdkVersion by extra(34)
val androidMinSdkVersion by extra(21) val androidMinSdkVersion by extra(21)
val androidBuildToolsVersion by extra("33.0.2") val androidBuildToolsVersion by extra("34.0.0")
val androidCompileSdkVersion by extra(33) val androidCompileSdkVersion by extra(34)
val androidNdkVersion by extra("25.2.9519653") val androidNdkVersion by extra("26.0.10792818")
val androidCmakeVersion by extra("3.22.1+") val androidCmakeVersion by extra("3.22.1+")

View File

@ -28,8 +28,8 @@ private:
} }
using BackupMethods = std::list<std::tuple<art::ArtMethod *, void *>>; using BackupMethods = std::list<std::tuple<art::ArtMethod *, void *>>;
inline static absl::flat_hash_map<const art::Thread *, inline static phmap::flat_hash_map<const art::Thread *,
absl::flat_hash_map<const dex::ClassDef *, BackupMethods>> phmap::flat_hash_map<const dex::ClassDef *, BackupMethods>>
backup_methods_; backup_methods_;
inline static std::mutex backup_methods_lock_; inline static std::mutex backup_methods_lock_;
@ -37,28 +37,24 @@ private:
std::list<std::tuple<art::ArtMethod *, void *>> out; std::list<std::tuple<art::ArtMethod *, void *>> out;
if (!class_def) return; if (!class_def) return;
{ {
std::shared_lock lk(hooked_classes_lock_); hooked_classes_.if_contains(class_def, [&out](const auto &it) {
if (auto found = hooked_classes_.find(class_def); found != hooked_classes_.end()) for (auto method : it.second) {
[[unlikely]] {
for (auto method : found->second) {
if (method->IsStatic()) { if (method->IsStatic()) {
LOGV("Backup hooked method %p because of initialization", method); LOGV("Backup hooked method %p because of initialization", method);
out.emplace_back(method, method->GetEntryPoint()); out.emplace_back(method, method->GetEntryPoint());
} }
} }
} });
} }
{ {
std::shared_lock lk(deoptimized_methods_lock_); deoptimized_classes_.if_contains(class_def, [&out](const auto &it) {
if (auto found = deoptimized_classes_.find(class_def); for (auto method : it.second) {
found != deoptimized_classes_.end()) [[unlikely]] {
for (auto method : found->second) {
if (method->IsStatic()) { if (method->IsStatic()) {
LOGV("Backup deoptimized method %p because of initialization", method); LOGV("Backup deoptimized method %p because of initialization", method);
out.emplace_back(method, method->GetEntryPoint()); out.emplace_back(method, method->GetEntryPoint());
} }
} }
} });
} }
if (!out.empty()) [[unlikely]] { if (!out.empty()) [[unlikely]] {
std::unique_lock lk(backup_methods_lock_); std::unique_lock lk(backup_methods_lock_);

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <absl/container/flat_hash_map.h> #include <parallel_hashmap/phmap.h>
#include <absl/container/flat_hash_set.h>
#include <sys/system_properties.h> #include <sys/system_properties.h>
#include <list> #include <list>
@ -104,44 +103,47 @@ class Class;
namespace { namespace {
// target, backup // target, backup
inline absl::flat_hash_map<art::ArtMethod *, std::pair<jobject, art::ArtMethod *>> hooked_methods_; template <class K, class V, class Hash = phmap::priv::hash_default_hash<K>,
inline std::shared_mutex hooked_methods_lock_; class Eq = phmap::priv::hash_default_eq<K>,
class Alloc = phmap::priv::Allocator<phmap::priv::Pair<const K, V>>, size_t N = 4>
using SharedHashMap = phmap::parallel_flat_hash_map<K, V, Hash, Eq, Alloc, N, std::shared_mutex>;
inline absl::flat_hash_map<const art::dex::ClassDef *, absl::flat_hash_set<art::ArtMethod *>> template <class T, class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>, class Alloc = phmap::priv::Allocator<T>,
size_t N = 4>
using SharedHashSet = phmap::parallel_flat_hash_set<T, Hash, Eq, Alloc, N, std::shared_mutex>;
inline SharedHashMap<art::ArtMethod *, std::pair<jobject, art::ArtMethod *>> hooked_methods_;
inline SharedHashMap<const art::dex::ClassDef *, phmap::flat_hash_set<art::ArtMethod *>>
hooked_classes_; hooked_classes_;
inline std::shared_mutex hooked_classes_lock_;
inline absl::flat_hash_set<art::ArtMethod *> deoptimized_methods_set_; inline SharedHashSet<art::ArtMethod *> deoptimized_methods_set_;
inline std::shared_mutex deoptimized_methods_lock_;
inline absl::flat_hash_map<const art::dex::ClassDef *, absl::flat_hash_set<art::ArtMethod *>> inline SharedHashMap<const art::dex::ClassDef *, phmap::flat_hash_set<art::ArtMethod *>>
deoptimized_classes_; deoptimized_classes_;
inline std::shared_mutex deoptimized_classes_lock_;
inline std::list<std::pair<art::ArtMethod *, art::ArtMethod *>> jit_movements_; inline std::list<std::pair<art::ArtMethod *, art::ArtMethod *>> jit_movements_;
inline std::shared_mutex jit_movements_lock_; inline std::shared_mutex jit_movements_lock_;
} // namespace } // namespace
inline art::ArtMethod *IsHooked(art::ArtMethod *art_method, bool including_backup = false) { inline art::ArtMethod *IsHooked(art::ArtMethod *art_method, bool including_backup = false) {
std::shared_lock lk(hooked_methods_lock_); art::ArtMethod *backup = nullptr;
if (auto it = hooked_methods_.find(art_method); hooked_methods_.if_contains(art_method, [&backup, &including_backup](const auto &it) {
it != hooked_methods_.end() && (!including_backup || it->second.first)) { if (!including_backup || it.second.first) backup = it.second.second;
return it->second.second; });
} return backup;
return nullptr;
} }
inline art::ArtMethod *IsBackup(art::ArtMethod *art_method) { inline art::ArtMethod *IsBackup(art::ArtMethod *art_method) {
std::shared_lock lk(hooked_methods_lock_); art::ArtMethod *backup = nullptr;
if (auto it = hooked_methods_.find(art_method); hooked_methods_.if_contains(art_method, [&backup](const auto &it) {
it != hooked_methods_.end() && !it->second.first) { if (!it.second.first) backup = it.second.second;
return it->second.second; });
}
return nullptr; return nullptr;
} }
inline bool IsDeoptimized(art::ArtMethod *art_method) { inline bool IsDeoptimized(art::ArtMethod *art_method) {
std::shared_lock lk(deoptimized_methods_lock_);
return deoptimized_methods_set_.contains(art_method); return deoptimized_methods_set_.contains(art_method);
} }
@ -152,27 +154,19 @@ inline std::list<std::pair<art::ArtMethod *, art::ArtMethod *>> GetJitMovements(
inline void RecordHooked(art::ArtMethod *target, const art::dex::ClassDef *class_def, inline void RecordHooked(art::ArtMethod *target, const art::dex::ClassDef *class_def,
jobject reflected_backup, art::ArtMethod *backup) { jobject reflected_backup, art::ArtMethod *backup) {
{ hooked_classes_.lazy_emplace_l(
std::unique_lock lk(hooked_classes_lock_); class_def, [&target](auto &it) { it.second.emplace(target); },
hooked_classes_[class_def].emplace(target); [&class_def, &target](const auto &ctor) {
} ctor(class_def, phmap::flat_hash_set<art::ArtMethod *>{target});
{ });
std::unique_lock lk(hooked_methods_lock_); hooked_methods_.insert({std::make_pair(target, std::make_pair(reflected_backup, backup)),
hooked_methods_[target] = {reflected_backup, backup}; std::make_pair(backup, std::make_pair(nullptr, target))});
hooked_methods_[backup] = {nullptr, target};
}
} }
inline void RecordDeoptimized(const art::dex::ClassDef *class_def, art::ArtMethod *art_method) { inline void RecordDeoptimized(const art::dex::ClassDef *class_def, art::ArtMethod *art_method) {
{ { deoptimized_classes_[class_def].emplace(art_method); }
std::unique_lock lk(deoptimized_classes_lock_);
deoptimized_classes_[class_def].emplace(art_method);
}
{
std::unique_lock lk(deoptimized_methods_lock_);
deoptimized_methods_set_.insert(art_method); deoptimized_methods_set_.insert(art_method);
} }
}
inline void RecordJitMovement(art::ArtMethod *target, art::ArtMethod *backup) { inline void RecordJitMovement(art::ArtMethod *target, art::ArtMethod *backup) {
std::unique_lock lk(jit_movements_lock_); std::unique_lock lk(jit_movements_lock_);

@ -1 +1 @@
Subproject commit 60251dde8d7dcb49b2a6249a0214437836cc8991 Subproject commit b5a00f2ea94ad4c3b92054fd53896dbb429298f9

View File

@ -158,7 +158,8 @@ bool InitJNI(JNIEnv *env) {
return false; return false;
} }
if (method_get_return_type = if (method_get_return_type =
JNI_GetMethodID(env, JNI_FindClass(env, "java/lang/reflect/Method"), "getReturnType", "()Ljava/lang/Class;"); JNI_GetMethodID(env, JNI_FindClass(env, "java/lang/reflect/Method"), "getReturnType",
"()Ljava/lang/Class;");
!method_get_return_type) { !method_get_return_type) {
LOGE("Failed to find getReturnType method"); LOGE("Failed to find getReturnType method");
return false; return false;
@ -776,28 +777,19 @@ using ::lsplant::IsHooked;
auto *target = ArtMethod::FromReflectedMethod(env, target_method); auto *target = ArtMethod::FromReflectedMethod(env, target_method);
jobject reflected_backup = nullptr; jobject reflected_backup = nullptr;
art::ArtMethod *backup = nullptr; art::ArtMethod *backup = nullptr;
{ if (!hooked_methods_.erase_if(target, [&reflected_backup, &backup](const auto &it) {
std::unique_lock lk(hooked_methods_lock_); std::tie(reflected_backup, backup) = it.second;
if (auto it = hooked_methods_.find(target); it != hooked_methods_.end()) [[likely]] { return reflected_backup != nullptr;
std::tie(reflected_backup, backup) = it->second; })) {
if (reflected_backup == nullptr) {
LOGE("Unable to unhook a method that is not hooked"); LOGE("Unable to unhook a method that is not hooked");
return false; return false;
} }
hooked_methods_.erase(it->second.second); // FIXME: not atomic, but should be fine
hooked_methods_.erase(it); hooked_methods_.erase(backup);
} hooked_classes_.erase_if(target->GetDeclaringClass()->GetClassDef(), [&target](auto &it) {
} it.second.erase(target);
{ return it.second.empty();
std::unique_lock lk(hooked_classes_lock_); });
if (auto it = hooked_classes_.find(target->GetDeclaringClass()->GetClassDef());
it != hooked_classes_.end()) {
it->second.erase(target);
if (it->second.empty()) {
hooked_classes_.erase(it);
}
}
}
auto *backup_method = env->FromReflectedMethod(reflected_backup); auto *backup_method = env->FromReflectedMethod(reflected_backup);
env->DeleteGlobalRef(reflected_backup); env->DeleteGlobalRef(reflected_backup);
if (DoUnHook(target, backup)) { if (DoUnHook(target, backup)) {