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)
}
val androidTargetSdkVersion by extra(33)
val androidTargetSdkVersion by extra(34)
val androidMinSdkVersion by extra(21)
val androidBuildToolsVersion by extra("33.0.2")
val androidCompileSdkVersion by extra(33)
val androidNdkVersion by extra("25.2.9519653")
val androidBuildToolsVersion by extra("34.0.0")
val androidCompileSdkVersion by extra(34)
val androidNdkVersion by extra("26.0.10792818")
val androidCmakeVersion by extra("3.22.1+")

View File

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

View File

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

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

View File

@ -158,7 +158,8 @@ bool InitJNI(JNIEnv *env) {
return false;
}
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) {
LOGE("Failed to find getReturnType method");
return false;
@ -620,7 +621,7 @@ struct JavaDebuggableGuard {
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
Runtime::RuntimeDebugState::kJavaDebuggableAtInit);
count.fetch_add(1, std::memory_order_release);
count.notify_all();
break;
@ -642,7 +643,7 @@ struct JavaDebuggableGuard {
if (count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Runtime::Current()->SetJavaDebuggable(
Runtime::RuntimeDebugState::kNonJavaDebuggable);
Runtime::RuntimeDebugState::kNonJavaDebuggable);
count.fetch_sub(1, std::memory_order_release);
count.notify_all();
break;
@ -776,28 +777,19 @@ using ::lsplant::IsHooked;
auto *target = ArtMethod::FromReflectedMethod(env, target_method);
jobject reflected_backup = nullptr;
art::ArtMethod *backup = nullptr;
{
std::unique_lock lk(hooked_methods_lock_);
if (auto it = hooked_methods_.find(target); it != hooked_methods_.end()) [[likely]] {
std::tie(reflected_backup, backup) = it->second;
if (reflected_backup == nullptr) {
LOGE("Unable to unhook a method that is not hooked");
return false;
}
hooked_methods_.erase(it->second.second);
hooked_methods_.erase(it);
}
}
{
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);
}
}
if (!hooked_methods_.erase_if(target, [&reflected_backup, &backup](const auto &it) {
std::tie(reflected_backup, backup) = it.second;
return reflected_backup != nullptr;
})) {
LOGE("Unable to unhook a method that is not hooked");
return false;
}
// FIXME: not atomic, but should be fine
hooked_methods_.erase(backup);
hooked_classes_.erase_if(target->GetDeclaringClass()->GetClassDef(), [&target](auto &it) {
it.second.erase(target);
return it.second.empty();
});
auto *backup_method = env->FromReflectedMethod(reflected_backup);
env->DeleteGlobalRef(reflected_backup);
if (DoUnHook(target, backup)) {