ART: Correctly handle temporary classes in class-load events (3/3)
When a temporary class is given out in a ClassLoad event, all stored
references need to be fixed up before publishing a ClassPrepare event.
This CL handles objects stored in the heap.
Bug: 31684920
Test: m test-art-host-run-test-912-classes
Change-Id: Ia0456c81fd848618e637b93301edf4dbc8d848f2
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index cf3cfa4..fc4b6fe 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -50,6 +50,8 @@
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
+#include "mirror/object_reference.h"
+#include "mirror/object-inl.h"
#include "runtime.h"
#include "runtime_callbacks.h"
#include "ScopedLocalRef.h"
@@ -347,6 +349,7 @@
FixupGlobalReferenceTables(input, output);
FixupLocalReferenceTables(self, input, output);
+ FixupHeap(input, output);
}
if (heap->IsGcConcurrentAndMoving()) {
heap->DecrementDisableMovingGC(self);
@@ -385,8 +388,7 @@
art::mirror::Class* output_;
};
- void FixupGlobalReferenceTables(art::mirror::Class* input,
- art::mirror::Class* output)
+ void FixupGlobalReferenceTables(art::mirror::Class* input, art::mirror::Class* output)
REQUIRES(art::Locks::mutator_lock_) {
art::JavaVMExt* java_vm = art::Runtime::Current()->GetJavaVM();
@@ -441,6 +443,53 @@
art::Runtime::Current()->GetThreadList()->ForEach(LocalUpdate::Callback, &local_upd);
}
+ void FixupHeap(art::mirror::Class* input, art::mirror::Class* output)
+ REQUIRES(art::Locks::mutator_lock_) {
+ class HeapFixupVisitor {
+ public:
+ HeapFixupVisitor(const art::mirror::Class* root_input, art::mirror::Class* root_output)
+ : input_(root_input), output_(root_output) {}
+
+ void operator()(art::mirror::Object* src,
+ art::MemberOffset field_offset,
+ bool is_static ATTRIBUTE_UNUSED) const
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::mirror::HeapReference<art::mirror::Object>* trg =
+ src->GetFieldObjectReferenceAddr(field_offset);
+ if (trg->AsMirrorPtr() == input_) {
+ DCHECK_NE(field_offset.Uint32Value(), 0u); // This shouldn't be the class field of
+ // an object.
+ trg->Assign(output_);
+ }
+ }
+
+ void VisitRoot(art::mirror::CompressedReference<art::mirror::Object>* root ATTRIBUTE_UNUSED)
+ const {
+ LOG(FATAL) << "Unreachable";
+ }
+
+ void VisitRootIfNonNull(
+ art::mirror::CompressedReference<art::mirror::Object>* root ATTRIBUTE_UNUSED) const {
+ LOG(FATAL) << "Unreachable";
+ }
+
+ static void AllObjectsCallback(art::mirror::Object* obj, void* arg)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ HeapFixupVisitor* hfv = reinterpret_cast<HeapFixupVisitor*>(arg);
+
+ // Visit references, not native roots.
+ obj->VisitReferences<false>(*hfv, art::VoidFunctor());
+ }
+
+ private:
+ const art::mirror::Class* input_;
+ art::mirror::Class* output_;
+ };
+ HeapFixupVisitor hfv(input, output);
+ art::Runtime::Current()->GetHeap()->VisitObjectsPaused(HeapFixupVisitor::AllObjectsCallback,
+ &hfv);
+ }
+
// A set of all the temp classes we have handed out. We have to fix up references to these.
// For simplicity, we store the temp classes as JNI global references in a vector. Normally a
// Prepare event will closely follow, so the vector should be small.