Consolidate updating of reflective Field/Method references
Previously we used several different visitors to update Field &
Method references for structural redefinition. We also did not visit
or update JVMTI based references.
This consolidates all the visitors to a single
Runtime::VisitReflectiveTargets function with a single
ReflectiveTargetVisitor type. This simplifies the code around
structural redefinition and ensures that the reflective value holders
are in charge of the actual replacement.
Support was also added for walking internal openjdkjvmti references
for things like field-read/modification events.
Test: ./test.py --host
Bug: 134162467
Change-Id: Ic5fc1db7db0a30f947a1a67259dc024e149ebd57
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 477362b..3809541 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -189,6 +189,7 @@
"read_barrier.cc",
"reference_table.cc",
"reflection.cc",
+ "reflective_value_visitor.cc",
"runtime.cc",
"runtime_callbacks.cc",
"runtime_common.cc",
@@ -498,6 +499,7 @@
"oat.h",
"object_callbacks.h",
"process_state.h",
+ "reflective_value_visitor.h",
"stack.h",
"suspend_reason.h",
"thread.h",
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 8f1508a..b3a46ca 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -41,6 +41,7 @@
#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/utils.h"
+#include "class_root.h"
#include "common_throws.h"
#include "debugger.h"
#include "dex/dex_file-inl.h"
@@ -80,10 +81,14 @@
#include "jit/jit_code_cache.h"
#include "jni/java_vm_ext.h"
#include "mirror/class-inl.h"
+#include "mirror/executable-inl.h"
+#include "mirror/field.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/reference-inl.h"
+#include "mirror/var_handle.h"
#include "nativehelper/scoped_local_ref.h"
#include "obj_ptr-inl.h"
#include "reflection.h"
@@ -4193,5 +4198,27 @@
}
}
+void Heap::VisitReflectiveTargets(ReflectiveValueVisitor *visit) {
+ VisitObjectsPaused([&visit](mirror::Object* ref) NO_THREAD_SAFETY_ANALYSIS {
+ art::ObjPtr<mirror::Class> klass(ref->GetClass());
+ // All these classes are in the BootstrapClassLoader.
+ if (!klass->IsBootStrapClassLoaded()) {
+ return;
+ }
+ if (GetClassRoot<mirror::Method>()->IsAssignableFrom(klass) ||
+ GetClassRoot<mirror::Constructor>()->IsAssignableFrom(klass)) {
+ down_cast<mirror::Executable*>(ref)->VisitTarget(visit);
+ } else if (art::GetClassRoot<art::mirror::Field>() == klass) {
+ down_cast<mirror::Field*>(ref)->VisitTarget(visit);
+ } else if (art::GetClassRoot<art::mirror::MethodHandle>()->IsAssignableFrom(klass)) {
+ down_cast<mirror::MethodHandle*>(ref)->VisitTarget(visit);
+ } else if (art::GetClassRoot<art::mirror::FieldVarHandle>()->IsAssignableFrom(klass)) {
+ down_cast<mirror::FieldVarHandle*>(ref)->VisitTarget(visit);
+ } else if (art::GetClassRoot<art::mirror::DexCache>()->IsAssignableFrom(klass)) {
+ down_cast<mirror::DexCache*>(ref)->VisitReflectiveTargets(visit);
+ }
+ });
+}
+
} // namespace gc
} // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 86d6b82..de94d37 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -51,6 +51,7 @@
enum class InstructionSet;
class IsMarkedVisitor;
class Mutex;
+class ReflectiveValueVisitor;
class RootVisitor;
class StackVisitor;
class Thread;
@@ -286,6 +287,9 @@
ALWAYS_INLINE void VisitObjectsPaused(Visitor&& visitor)
REQUIRES(Locks::mutator_lock_, !Locks::heap_bitmap_lock_, !*gc_complete_lock_);
+ void VisitReflectiveTargets(ReflectiveValueVisitor* visitor)
+ REQUIRES(Locks::mutator_lock_, !Locks::heap_bitmap_lock_, !*gc_complete_lock_);
+
void CheckPreconditionsForAllocObject(ObjPtr<mirror::Class> c, size_t byte_count)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/jni/jni_id_manager.cc b/runtime/jni/jni_id_manager.cc
index 9ae8c89..2553fdf 100644
--- a/runtime/jni/jni_id_manager.cc
+++ b/runtime/jni/jni_id_manager.cc
@@ -28,11 +28,13 @@
#include "jni/jni_internal.h"
#include "jni_id_type.h"
#include "mirror/array-inl.h"
+#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/class.h"
-#include "mirror/class_ext.h"
+#include "mirror/class_ext-inl.h"
#include "mirror/object-inl.h"
#include "obj_ptr-inl.h"
+#include "reflective_value_visitor.h"
#include "thread-inl.h"
#include "thread.h"
#include <algorithm>
@@ -310,18 +312,80 @@
return res;
}
-void JniIdManager::VisitIds(Thread* self, JniIdManager::IdVisitor* visitor) {
- art::WriterMutexLock mu(self, *Locks::jni_id_lock_);
- if (visitor->ShouldVisitFields()) {
- for (auto it = field_id_map_.begin(); it != field_id_map_.end(); ++it) {
- visitor->VisitFieldId(
- reinterpret_cast<jfieldID>(IndexToId(std::distance(field_id_map_.begin(), it))), &*it);
+void JniIdManager::VisitReflectiveTargets(ReflectiveValueVisitor* rvv) {
+ art::WriterMutexLock mu(Thread::Current(), *Locks::jni_id_lock_);
+ for (auto it = field_id_map_.begin(); it != field_id_map_.end(); ++it) {
+ ArtField* old_field = *it;
+ uintptr_t id = IndexToId(std::distance(field_id_map_.begin(), it));
+ ArtField* new_field =
+ rvv->VisitField(old_field, JniIdReflectiveSourceInfo(reinterpret_cast<jfieldID>(id)));
+ if (old_field != new_field) {
+ *it = new_field;
+ ObjPtr<mirror::Class> old_class(old_field->GetDeclaringClass());
+ ObjPtr<mirror::Class> new_class(new_field->GetDeclaringClass());
+ ObjPtr<mirror::ClassExt> old_ext_data(old_class->GetExtData());
+ ObjPtr<mirror::ClassExt> new_ext_data(new_class->GetExtData());
+ if (!old_ext_data.IsNull()) {
+ // Clear the old field mapping.
+ if (old_field->IsStatic()) {
+ size_t old_off = ArraySlice<ArtField>(old_class->GetSFieldsPtr()).OffsetOf(old_field);
+ ObjPtr<mirror::PointerArray> old_statics(old_ext_data->GetStaticJFieldIDs());
+ if (!old_statics.IsNull()) {
+ old_statics->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
+ }
+ } else {
+ size_t old_off = ArraySlice<ArtField>(old_class->GetIFieldsPtr()).OffsetOf(old_field);
+ ObjPtr<mirror::PointerArray> old_instances(old_ext_data->GetInstanceJFieldIDs());
+ if (!old_instances.IsNull()) {
+ old_instances->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
+ }
+ }
+ }
+ if (!new_ext_data.IsNull()) {
+ // Set the new field mapping.
+ if (new_field->IsStatic()) {
+ size_t new_off = ArraySlice<ArtField>(new_class->GetSFieldsPtr()).OffsetOf(new_field);
+ ObjPtr<mirror::PointerArray> new_statics(new_ext_data->GetStaticJFieldIDs());
+ if (!new_statics.IsNull()) {
+ new_statics->SetElementPtrSize(new_off, id, kRuntimePointerSize);
+ }
+ } else {
+ size_t new_off = ArraySlice<ArtField>(new_class->GetIFieldsPtr()).OffsetOf(new_field);
+ ObjPtr<mirror::PointerArray> new_instances(new_ext_data->GetInstanceJFieldIDs());
+ if (!new_instances.IsNull()) {
+ new_instances->SetElementPtrSize(new_off, id, kRuntimePointerSize);
+ }
+ }
+ }
}
}
- if (visitor->ShouldVisitMethods()) {
- for (auto it = method_id_map_.begin(); it != method_id_map_.end(); ++it) {
- visitor->VisitMethodId(
- reinterpret_cast<jmethodID>(IndexToId(std::distance(method_id_map_.begin(), it))), &*it);
+ for (auto it = method_id_map_.begin(); it != method_id_map_.end(); ++it) {
+ ArtMethod* old_method = *it;
+ uintptr_t id = IndexToId(std::distance(method_id_map_.begin(), it));
+ ArtMethod* new_method =
+ rvv->VisitMethod(old_method, JniIdReflectiveSourceInfo(reinterpret_cast<jmethodID>(id)));
+ if (old_method != new_method) {
+ *it = new_method;
+ ObjPtr<mirror::Class> old_class(old_method->GetDeclaringClass());
+ ObjPtr<mirror::Class> new_class(new_method->GetDeclaringClass());
+ ObjPtr<mirror::ClassExt> old_ext_data(old_class->GetExtData());
+ ObjPtr<mirror::ClassExt> new_ext_data(new_class->GetExtData());
+ if (!old_ext_data.IsNull()) {
+ // Clear the old method mapping.
+ size_t old_off = ArraySlice<ArtMethod>(old_class->GetMethodsPtr()).OffsetOf(old_method);
+ ObjPtr<mirror::PointerArray> old_methods(old_ext_data->GetJMethodIDs());
+ if (!old_methods.IsNull()) {
+ old_methods->SetElementPtrSize(old_off, 0, kRuntimePointerSize);
+ }
+ }
+ if (!new_ext_data.IsNull()) {
+ // Set the new method mapping.
+ size_t new_off = ArraySlice<ArtMethod>(new_class->GetMethodsPtr()).OffsetOf(new_method);
+ ObjPtr<mirror::PointerArray> new_methods(new_ext_data->GetJMethodIDs());
+ if (!new_methods.IsNull()) {
+ new_methods->SetElementPtrSize(new_off, id, kRuntimePointerSize);
+ }
+ }
}
}
}
diff --git a/runtime/jni/jni_id_manager.h b/runtime/jni/jni_id_manager.h
index 7b2f3c4..6b43534 100644
--- a/runtime/jni/jni_id_manager.h
+++ b/runtime/jni/jni_id_manager.h
@@ -25,6 +25,7 @@
#include "art_method.h"
#include "base/mutex.h"
#include "jni_id_type.h"
+#include "reflective_value_visitor.h"
namespace art {
namespace jni {
@@ -32,15 +33,6 @@
class ScopedEnableSuspendAllJniIdQueries;
class JniIdManager {
public:
- class IdVisitor {
- public:
- virtual ~IdVisitor() {}
- virtual void VisitMethodId(jmethodID id, ArtMethod** method) = 0;
- virtual void VisitFieldId(jfieldID id, ArtField** field) = 0;
- virtual bool ShouldVisitFields() = 0;
- virtual bool ShouldVisitMethods() = 0;
- };
-
template <typename T,
typename = typename std::enable_if<std::is_same_v<T, jmethodID> ||
std::is_same_v<T, jfieldID>>>
@@ -55,33 +47,8 @@
jfieldID EncodeFieldId(ArtField* field) REQUIRES(!Locks::jni_id_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void VisitIds(Thread* self, IdVisitor* visitor);
-
- template<typename MethodVisitor, typename FieldVisitor>
- void VisitIds(Thread* self, MethodVisitor m, FieldVisitor f) REQUIRES(!Locks::jni_id_lock_) {
- struct FuncVisitor : public IdVisitor {
- public:
- FuncVisitor(MethodVisitor m, FieldVisitor f) : m_(m), f_(f) {}
- bool ShouldVisitFields() override {
- return true;
- }
- bool ShouldVisitMethods() override {
- return true;
- }
- void VisitMethodId(jmethodID mid, ArtMethod** am) NO_THREAD_SAFETY_ANALYSIS override {
- m_(mid, am);
- }
- void VisitFieldId(jfieldID fid, ArtField** af) NO_THREAD_SAFETY_ANALYSIS override {
- f_(fid, af);
- }
-
- private:
- MethodVisitor m_;
- FieldVisitor f_;
- };
- FuncVisitor fv(m, f);
- VisitIds(self, &fv);
- }
+ void VisitReflectiveTargets(ReflectiveValueVisitor* rvv)
+ REQUIRES(Locks::mutator_lock_, !Locks::jni_id_lock_);
private:
template <typename ArtType>
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index f97f521..c2c47a5 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -25,6 +25,7 @@
#include "object-inl.h"
#include "object.h"
#include "object_array-inl.h"
+#include "reflective_value_visitor.h"
#include "runtime.h"
#include "runtime_globals.h"
#include "string.h"
@@ -172,6 +173,27 @@
dex_file->NumCallSiteIds());
}
+void DexCache::VisitReflectiveTargets(ReflectiveValueVisitor* visitor) {
+ for (size_t i = 0; i < NumResolvedFields(); i++) {
+ auto pair(GetNativePairPtrSize(GetResolvedFields(), i, kRuntimePointerSize));
+ ArtField* new_val = visitor->VisitField(
+ pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedField, pair.index, this));
+ if (UNLIKELY(new_val != pair.object)) {
+ pair.object = new_val;
+ SetNativePairPtrSize(GetResolvedFields(), i, pair, kRuntimePointerSize);
+ }
+ }
+ for (size_t i = 0; i < NumResolvedMethods(); i++) {
+ auto pair(GetNativePairPtrSize(GetResolvedMethods(), i, kRuntimePointerSize));
+ ArtMethod* new_val = visitor->VisitMethod(
+ pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, pair.index, this));
+ if (UNLIKELY(new_val != pair.object)) {
+ pair.object = new_val;
+ SetNativePairPtrSize(GetResolvedMethods(), i, pair, kRuntimePointerSize);
+ }
+ }
+}
+
bool DexCache::AddPreResolvedStringsArray() {
DCHECK_EQ(NumPreResolvedStrings(), 0u);
Thread* const self = Thread::Current();
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index b41443e..292db14 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -37,6 +37,7 @@
class DexFile;
union JValue;
class LinearAlloc;
+class ReflectiveValueVisitor;
class Thread;
namespace mirror {
@@ -476,6 +477,8 @@
// Returns true if we succeeded in adding the pre-resolved string array.
bool AddPreResolvedStringsArray() REQUIRES_SHARED(Locks::mutator_lock_);
+ void VisitReflectiveTargets(ReflectiveValueVisitor* visitor) REQUIRES(Locks::mutator_lock_);
+
private:
void Init(const DexFile* dex_file,
ObjPtr<String> location,
diff --git a/runtime/mirror/executable-inl.h b/runtime/mirror/executable-inl.h
index ce35d6e..f2d684a 100644
--- a/runtime/mirror/executable-inl.h
+++ b/runtime/mirror/executable-inl.h
@@ -20,6 +20,7 @@
#include "executable.h"
#include "object-inl.h"
+#include "reflective_value_visitor.h"
#include "verify_object.h"
namespace art {
@@ -37,10 +38,11 @@
return GetFieldObject<mirror::Class>(DeclaringClassOffset());
}
-template<typename Visitor, VerifyObjectFlags kVerifiyFlags>
-inline void Executable::VisitTarget(Visitor&& v) {
+template<VerifyObjectFlags kVerifiyFlags>
+inline void Executable::VisitTarget(ReflectiveValueVisitor* v) {
+ HeapReflectiveSourceInfo hrsi(kSourceJavaLangReflectExecutable, this);
ArtMethod* orig = GetArtMethod<kVerifiyFlags>();
- ArtMethod* new_target = v(orig);
+ ArtMethod* new_target = v->VisitMethod(orig, hrsi);
if (orig != new_target) {
SetArtMethod(new_target);
SetDexMethodIndex(new_target->GetDexMethodIndex());
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 8eca206..750a167 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -25,6 +25,7 @@
struct ExecutableOffsets;
class ArtMethod;
+class ReflectiveValueVisitor;
namespace mirror {
@@ -41,9 +42,8 @@
return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
}
- template <typename Visitor,
- VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+ template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+ inline void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
template <bool kTransactionActive = false,
bool kCheckTransaction = true,
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index 6e82d6d..ac11be1 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -104,18 +104,6 @@
SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, type_), type);
}
-template<typename Visitor>
-inline void Field::VisitTarget(Visitor&& v) {
- ArtField* orig = GetArtField(/*use_dex_cache*/false);
- ArtField* new_value = v(orig);
- if (orig != new_value) {
- SetDexFieldIndex<false>(new_value->GetDexFieldIndex());
- SetOffset<false>(new_value->GetOffset().Int32Value());
- SetDeclaringClass<false>(new_value->GetDeclaringClass());
- }
- DCHECK_EQ(new_value, GetArtField(/*use_dex_cache*/false));
-}
-
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc
index 9a40006..aa071a8 100644
--- a/runtime/mirror/field.cc
+++ b/runtime/mirror/field.cc
@@ -24,6 +24,18 @@
namespace art {
namespace mirror {
+void Field::VisitTarget(ReflectiveValueVisitor* v) {
+ HeapReflectiveSourceInfo hrsi(kSourceJavaLangReflectField, this);
+ ArtField* orig = GetArtField(/*use_dex_cache*/false);
+ ArtField* new_value = v->VisitField(orig, hrsi);
+ if (orig != new_value) {
+ SetDexFieldIndex<false>(new_value->GetDexFieldIndex());
+ SetOffset<false>(new_value->GetOffset().Int32Value());
+ SetDeclaringClass<false>(new_value->GetDeclaringClass());
+ }
+ DCHECK_EQ(new_value, GetArtField(/*use_dex_cache*/false));
+}
+
ArtField* Field::GetArtField(bool use_dex_cache) {
ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
if (UNLIKELY(declaring_class->IsProxyClass())) {
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 89c86e3..2ed3452 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -29,6 +29,7 @@
class ArtField;
struct FieldOffsets;
+class ReflectiveValueVisitor;
namespace mirror {
@@ -82,8 +83,7 @@
// Used to modify the target of this Field object, if required for structural redefinition or some
// other purpose.
- template<typename Visitor>
- inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+ void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
private:
// Padding required for matching alignment with the Java peer.
diff --git a/runtime/mirror/method_handle_impl-inl.h b/runtime/mirror/method_handle_impl-inl.h
index 0085642..932b434 100644
--- a/runtime/mirror/method_handle_impl-inl.h
+++ b/runtime/mirror/method_handle_impl-inl.h
@@ -39,20 +39,6 @@
GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass();
}
-template<typename Visitor>
-inline void MethodHandle::VisitTarget(Visitor&& v) {
- void* target = GetTargetField();
- void* result;
- if (GetHandleKind() < kFirstAccessorKind) {
- result = v(GetTargetMethod());
- } else {
- result = v(GetTargetField());
- }
- if (result != target) {
- SetField64<false>(ArtFieldOrMethodOffset(), reinterpret_cast<uintptr_t>(result));
- }
-}
-
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
index 433d4ba..dd25fc9 100644
--- a/runtime/mirror/method_handle_impl.cc
+++ b/runtime/mirror/method_handle_impl.cc
@@ -54,5 +54,20 @@
return mh.Get();
}
+void MethodHandle::VisitTarget(ReflectiveValueVisitor* v) {
+ void* target = GetTargetField();
+ void* result;
+ HeapReflectiveSourceInfo hrsi(kSourceJavaLangInvokeMethodHandle, this);
+ if (GetHandleKind() < kFirstAccessorKind) {
+ result = v->VisitMethod(GetTargetMethod(), hrsi);
+ } else {
+ result = v->VisitField(GetTargetField(), hrsi);
+ }
+ if (result != target) {
+ SetField64<false>(ArtFieldOrMethodOffset(), reinterpret_cast<uintptr_t>(result));
+ }
+}
+
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 357ec9d..54aa0c9 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -28,6 +28,7 @@
struct MethodHandleOffsets;
struct MethodHandleImplOffsets;
+class ReflectiveValueVisitor;
namespace mirror {
@@ -89,8 +90,7 @@
// Used when classes become structurally obsolete to change the MethodHandle to refer to the new
// method or field.
- template<typename Visitor>
- void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+ void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
protected:
void Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type)
diff --git a/runtime/mirror/var_handle-inl.h b/runtime/mirror/var_handle-inl.h
deleted file mode 100644
index d3f582d..0000000
--- a/runtime/mirror/var_handle-inl.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * 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 ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
-#define ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
-
-#include "var_handle.h"
-
-namespace art {
-class ArtField;
-
-namespace mirror {
-
-template<typename Visitor>
-inline void FieldVarHandle::VisitTarget(Visitor&& v) {
- ArtField* orig = GetField();
- ArtField* new_value = v(orig);
- if (orig != new_value) {
- SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
- reinterpret_cast<uintptr_t>(new_value));
- }
-}
-
-} // namespace mirror
-} // namespace art
-
-#endif // ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index d887b5a..6d5ff2c 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -2032,5 +2032,16 @@
UNREACHABLE();
}
+void FieldVarHandle::VisitTarget(ReflectiveValueVisitor* v) {
+ ArtField* orig = GetField();
+ ArtField* new_value =
+ v->VisitField(orig, HeapReflectiveSourceInfo(kSourceJavaLangInvokeFieldVarHandle, this));
+ if (orig != new_value) {
+ SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
+ reinterpret_cast<uintptr_t>(new_value));
+ }
+}
+
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index ac78d98..02a0d8c 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -36,6 +36,7 @@
struct ByteArrayViewVarHandleOffsets;
struct ByteBufferViewVarHandleOffsets;
+class ReflectiveValueVisitor;
class ShadowFrameGetter;
namespace mirror {
@@ -198,8 +199,7 @@
ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
// Used for updating var-handles to obsolete fields.
- template<typename Visitor>
- inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+ void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
private:
static MemberOffset ArtFieldOffset() {
diff --git a/runtime/reflective_value_visitor.cc b/runtime/reflective_value_visitor.cc
new file mode 100644
index 0000000..69fd51f
--- /dev/null
+++ b/runtime/reflective_value_visitor.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "reflective_value_visitor.h"
+#include <sstream>
+
+#include "base/locks.h"
+#include "base/mutex-inl.h"
+#include "mirror/class.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+void HeapReflectiveSourceInfo::Describe(std::ostream& os) const {
+ Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+ ReflectionSourceInfo::Describe(os);
+ os << " Class=" << src_->GetClass()->PrettyClass();
+}
+
+template<>
+void JniIdReflectiveSourceInfo<jfieldID>::Describe(std::ostream& os) const {
+ ReflectionSourceInfo::Describe(os);
+ os << " jfieldID=" << reinterpret_cast<uintptr_t>(id_);
+}
+
+template<>
+void JniIdReflectiveSourceInfo<jmethodID>::Describe(std::ostream& os) const {
+ ReflectionSourceInfo::Describe(os);
+ os << " jmethodID=" << reinterpret_cast<uintptr_t>(id_);
+}
+
+} // namespace art
diff --git a/runtime/reflective_value_visitor.h b/runtime/reflective_value_visitor.h
new file mode 100644
index 0000000..8823fcb
--- /dev/null
+++ b/runtime/reflective_value_visitor.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * 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 ART_RUNTIME_REFLECTIVE_VALUE_VISITOR_H_
+#define ART_RUNTIME_REFLECTIVE_VALUE_VISITOR_H_
+
+#include <android-base/logging.h>
+
+#include <array>
+#include <compare>
+#include <functional>
+#include <stack>
+
+#include "android-base/macros.h"
+#include "base/enums.h"
+#include "base/globals.h"
+#include "base/locks.h"
+#include "base/macros.h"
+#include "base/value_object.h"
+#include "dex/dex_file.h"
+#include "jni.h"
+#include "mirror/dex_cache.h"
+#include "obj_ptr.h"
+
+namespace art {
+
+class ArtField;
+class ArtMethod;
+class BaseReflectiveHandleScope;
+class Thread;
+
+class ReflectionSourceInfo;
+
+class ReflectiveValueVisitor : public ValueObject {
+ public:
+ virtual ~ReflectiveValueVisitor() {}
+
+ virtual ArtMethod* VisitMethod(ArtMethod* in, const ReflectionSourceInfo& info)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual ArtField* VisitField(ArtField* in, const ReflectionSourceInfo& info)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ // Give it an entrypoint through operator() to interact with things that expect lambda-like things
+ template <typename T,
+ typename = typename std::enable_if<std::is_same_v<T, ArtField> ||
+ std::is_same_v<T, ArtMethod>>>
+ T* operator()(T* t, const ReflectionSourceInfo& info) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if constexpr (std::is_same_v<T, ArtField>) {
+ return VisitField(t, info);
+ } else {
+ static_assert(std::is_same_v<T, ArtMethod>, "Expected ArtField or ArtMethod");
+ return VisitMethod(t, info);
+ }
+ }
+};
+
+template <typename FieldVis, typename MethodVis>
+class FunctionReflectiveValueVisitor : public ReflectiveValueVisitor {
+ public:
+ FunctionReflectiveValueVisitor(FieldVis fv, MethodVis mv) : fv_(fv), mv_(mv) {}
+ ArtField* VisitField(ArtField* in, const ReflectionSourceInfo& info) override
+ REQUIRES(Locks::mutator_lock_) {
+ return fv_(in, info);
+ }
+ ArtMethod* VisitMethod(ArtMethod* in, const ReflectionSourceInfo& info) override
+ REQUIRES(Locks::mutator_lock_) {
+ return mv_(in, info);
+ }
+
+ private:
+ FieldVis fv_;
+ MethodVis mv_;
+};
+
+enum ReflectionSourceType {
+ kSourceUnknown = 0,
+ kSourceJavaLangReflectExecutable,
+ kSourceJavaLangReflectField,
+ kSourceJavaLangInvokeMethodHandle,
+ kSourceJavaLangInvokeFieldVarHandle,
+ kSourceThreadHandleScope,
+ kSourceJniFieldId,
+ kSourceJniMethodId,
+ kSourceDexCacheResolvedMethod,
+ kSourceDexCacheResolvedField,
+ kSourceMiscInternal,
+};
+std::ostream& operator<<(std::ostream& os, const ReflectionSourceType& type);
+
+class ReflectionSourceInfo : public ValueObject {
+ public:
+ virtual ~ReflectionSourceInfo() {}
+ // Thread id 0 is for non thread roots.
+ explicit ReflectionSourceInfo(ReflectionSourceType type) : type_(type) {}
+ virtual void Describe(std::ostream& os) const {
+ os << "Type=" << type_;
+ }
+
+ private:
+ const ReflectionSourceType type_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReflectionSourceInfo);
+};
+inline std::ostream& operator<<(std::ostream& os, const ReflectionSourceInfo& info) {
+ info.Describe(os);
+ return os;
+}
+
+class ReflectiveHandleScopeSourceInfo : public ReflectionSourceInfo {
+ public:
+ explicit ReflectiveHandleScopeSourceInfo(BaseReflectiveHandleScope* source)
+ : ReflectionSourceInfo(kSourceThreadHandleScope), source_(source) {}
+
+ void Describe(std::ostream& os) const override {
+ ReflectionSourceInfo::Describe(os);
+ os << " source=" << source_;
+ }
+
+ private:
+ BaseReflectiveHandleScope* source_;
+};
+
+// TODO Maybe give this the ability to retrieve the type and ref, if it's useful.
+class HeapReflectiveSourceInfo : public ReflectionSourceInfo {
+ public:
+ HeapReflectiveSourceInfo(ReflectionSourceType t, mirror::Object* src)
+ : ReflectionSourceInfo(t), src_(src) {}
+ void Describe(std::ostream& os) const override;
+
+ private:
+ ObjPtr<mirror::Object> src_;
+};
+
+// TODO Maybe give this the ability to retrieve the id if it's useful.
+template <typename T,
+ typename = typename std::enable_if_t<std::is_same_v<T, jmethodID> ||
+ std::is_same_v<T, jfieldID>>>
+class JniIdReflectiveSourceInfo : public ReflectionSourceInfo {
+ public:
+ explicit JniIdReflectiveSourceInfo(T id)
+ : ReflectionSourceInfo(std::is_same_v<T, jmethodID> ? kSourceJniMethodId : kSourceJniFieldId),
+ id_(id) {}
+ void Describe(std::ostream& os) const override;
+
+ private:
+ T id_;
+};
+
+class DexCacheSourceInfo : public ReflectionSourceInfo {
+ public:
+ explicit DexCacheSourceInfo(ReflectionSourceType type,
+ size_t index,
+ ObjPtr<mirror::DexCache> cache)
+ : ReflectionSourceInfo(type), index_(index), cache_(cache) {}
+
+ void Describe(std::ostream& os) const override REQUIRES(Locks::mutator_lock_) {
+ ReflectionSourceInfo::Describe(os);
+ os << " index=" << index_ << " cache_=" << cache_.PtrUnchecked()
+ << " files=" << *cache_->GetDexFile();
+ }
+
+ private:
+ size_t index_;
+ ObjPtr<mirror::DexCache> cache_;
+};
+} // namespace art
+
+#endif // ART_RUNTIME_REFLECTIVE_VALUE_VISITOR_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 499dbf0..9af2f41 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2197,6 +2197,12 @@
VisitConcurrentRoots(visitor, flags);
}
+void Runtime::VisitReflectiveTargets(ReflectiveValueVisitor *visitor) {
+ heap_->VisitReflectiveTargets(visitor);
+ jni_id_manager_->VisitReflectiveTargets(visitor);
+ callbacks_->VisitReflectiveTargets(visitor);
+}
+
void Runtime::VisitImageRoots(RootVisitor* visitor) {
for (auto* space : GetHeap()->GetContinuousSpaces()) {
if (space->IsImageSpace()) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 120ca66..0b336c7 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -43,6 +43,7 @@
#include "offsets.h"
#include "process_state.h"
#include "quick/quick_method_frame_info.h"
+#include "reflective_value_visitor.h"
#include "runtime_stats.h"
namespace art {
@@ -397,6 +398,17 @@
void SweepSystemWeaks(IsMarkedVisitor* visitor)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Walk all reflective objects and visit their targets as well as any method/fields held by the
+ // runtime threads that are marked as being reflective.
+ void VisitReflectiveTargets(ReflectiveValueVisitor* visitor) REQUIRES(Locks::mutator_lock_);
+ // Helper for visiting reflective targets with lambdas for both field and method reflective
+ // targets.
+ template <typename FieldVis, typename MethodVis>
+ void VisitReflectiveTargets(FieldVis&& fv, MethodVis&& mv) REQUIRES(Locks::mutator_lock_) {
+ FunctionReflectiveValueVisitor frvv(fv, mv);
+ VisitReflectiveTargets(&frvv);
+ }
+
// Returns a special method that calls into a trampoline for runtime method resolution
ArtMethod* GetResolutionMethod();
diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc
index 40976c2..ac73364 100644
--- a/runtime/runtime_callbacks.cc
+++ b/runtime/runtime_callbacks.cc
@@ -319,4 +319,20 @@
}
}
+void RuntimeCallbacks::AddReflectiveValueVisitCallback(ReflectiveValueVisitCallback *cb) {
+ WriterMutexLock mu(Thread::Current(), *callback_lock_);
+ reflective_value_visit_callbacks_.push_back(cb);
+}
+
+void RuntimeCallbacks::RemoveReflectiveValueVisitCallback(ReflectiveValueVisitCallback *cb) {
+ WriterMutexLock mu(Thread::Current(), *callback_lock_);
+ Remove(cb, &reflective_value_visit_callbacks_);
+}
+
+void RuntimeCallbacks::VisitReflectiveTargets(ReflectiveValueVisitor *visitor) {
+ for (ReflectiveValueVisitCallback* cb : COPY(reflective_value_visit_callbacks_)) {
+ cb->VisitReflectiveTargets(visitor);
+ }
+}
+
} // namespace art
diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h
index fe7bb0c..7111ba0 100644
--- a/runtime/runtime_callbacks.h
+++ b/runtime/runtime_callbacks.h
@@ -44,6 +44,7 @@
class Monitor;
class ReaderWriterMutex;
class ThreadLifecycleCallback;
+class ReflectiveValueVisitor;
// Note: RuntimeCallbacks uses the mutator lock to synchronize the callback lists. A thread must
// hold the exclusive lock to add or remove a listener. A thread must hold the shared lock
@@ -156,6 +157,17 @@
virtual bool MethodNeedsDebugVersion(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) = 0;
};
+// Callback to let something request to be notified when reflective objects are being visited and
+// updated to update any bare ArtMethod/ArtField pointers it might have.
+class ReflectiveValueVisitCallback {
+ public:
+ virtual ~ReflectiveValueVisitCallback() {}
+
+ // Called when something visits all reflective values with the update visitor.
+ virtual void VisitReflectiveTargets(ReflectiveValueVisitor* visitor)
+ REQUIRES(Locks::mutator_lock_) = 0;
+};
+
class RuntimeCallbacks {
public:
RuntimeCallbacks();
@@ -257,6 +269,13 @@
void RemoveDebuggerControlCallback(DebuggerControlCallback* cb)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void VisitReflectiveTargets(ReflectiveValueVisitor* visitor) REQUIRES(Locks::mutator_lock_);
+
+ void AddReflectiveValueVisitCallback(ReflectiveValueVisitCallback* cb)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ void RemoveReflectiveValueVisitCallback(ReflectiveValueVisitCallback* cb)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
std::unique_ptr<ReaderWriterMutex> callback_lock_ BOTTOM_MUTEX_ACQUIRED_AFTER;
@@ -280,6 +299,8 @@
GUARDED_BY(callback_lock_);
std::vector<DebuggerControlCallback*> debugger_control_callbacks_
GUARDED_BY(callback_lock_);
+ std::vector<ReflectiveValueVisitCallback*> reflective_value_visit_callbacks_
+ GUARDED_BY(callback_lock_);
};
} // namespace art