Refactor object reference visiting logic.
Refactored the reference visiting logic to be in mirror::Object
instead of MarkSweep.
Change-Id: I773249478dc463d83b465e85c2402320488577c0
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index e3f4eed..89d9241 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -465,6 +465,12 @@
return Alloc<true>(self, Runtime::Current()->GetHeap()->GetCurrentNonMovingAllocator());
}
+template <bool kVisitClass, typename Visitor>
+inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
+ VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
+ VisitStaticFieldsReferences<kVisitClass>(this, visitor);
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 76ab94c..ddc07ff 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -861,6 +861,10 @@
// When class is verified, set the kAccPreverified flag on each method.
void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template <bool kVisitClass, typename Visitor>
+ void VisitReferences(mirror::Class* klass, const Visitor& visitor)
+ NO_THREAD_SAFETY_ANALYSIS;
+
private:
void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index cad1017..281d4ec 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -557,6 +557,77 @@
return success;
}
+template<bool kVisitClass, bool kIsStatic, typename Visitor>
+inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) {
+ if (LIKELY(ref_offsets != CLASS_WALK_SUPER)) {
+ if (!kVisitClass) {
+ // Mask out the class from the reference offsets.
+ ref_offsets ^= kWordHighBitMask;
+ }
+ DCHECK_EQ(ClassOffset().Uint32Value(), 0U);
+ // Found a reference offset bitmap. Visit the specified offsets.
+ while (ref_offsets != 0) {
+ size_t right_shift = CLZ(ref_offsets);
+ MemberOffset field_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
+ visitor(this, field_offset, kIsStatic);
+ ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
+ }
+ } else {
+ // There is no reference offset bitmap. In the non-static case, walk up the class
+ // inheritance hierarchy and find reference offsets the hard way. In the static case, just
+ // consider this class.
+ for (mirror::Class* klass = kIsStatic ? AsClass() : GetClass(); klass != nullptr;
+ klass = kIsStatic ? nullptr : klass->GetSuperClass()) {
+ size_t num_reference_fields =
+ kIsStatic ? klass->NumReferenceStaticFields() : klass->NumReferenceInstanceFields();
+ for (size_t i = 0; i < num_reference_fields; ++i) {
+ mirror::ArtField* field = kIsStatic ? klass->GetStaticField(i)
+ : klass->GetInstanceField(i);
+ MemberOffset field_offset = field->GetOffset();
+ // TODO: Do a simpler check?
+ if (!kVisitClass && UNLIKELY(field_offset.Uint32Value() == ClassOffset().Uint32Value())) {
+ continue;
+ }
+ visitor(this, field_offset, kIsStatic);
+ }
+ }
+ }
+}
+
+template<bool kVisitClass, typename Visitor>
+inline void Object::VisitInstanceFieldsReferences(mirror::Class* klass, const Visitor& visitor) {
+ VisitFieldsReferences<kVisitClass, false>(
+ klass->GetReferenceInstanceOffsets<kVerifyNone>(), visitor);
+}
+
+template<bool kVisitClass, typename Visitor>
+inline void Object::VisitStaticFieldsReferences(mirror::Class* klass, const Visitor& visitor) {
+ klass->VisitFieldsReferences<kVisitClass, true>(
+ klass->GetReferenceStaticOffsets<kVerifyNone>(), visitor);
+}
+
+template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags, typename Visitor,
+ typename JavaLangRefVisitor>
+inline void Object::VisitReferences(const Visitor& visitor,
+ const JavaLangRefVisitor& ref_visitor) {
+ mirror::Class* klass = GetClass<kVerifyFlags>();
+ if (UNLIKELY(klass == Class::GetJavaLangClass())) {
+ DCHECK_EQ(klass->GetClass(), Class::GetJavaLangClass());
+ AsClass<kVerifyNone>()->VisitReferences<kVisitClass>(klass, visitor);
+ } else if (UNLIKELY(klass->IsArrayClass<kVerifyFlags>())) {
+ if (klass->IsObjectArrayClass<kVerifyNone>()) {
+ AsObjectArray<mirror::Object>()->VisitReferences<kVisitClass>(visitor);
+ } else if (kVisitClass) {
+ visitor(this, ClassOffset(), false);
+ }
+ } else {
+ VisitFieldsReferences<kVisitClass, false>(klass->GetReferenceInstanceOffsets(), visitor);
+ if (UNLIKELY(klass->IsReferenceClass())) {
+ ref_visitor(klass, AsReference());
+ }
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 476259f..0a77828 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -240,6 +240,14 @@
#endif
}
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+ typename Visitor, typename JavaLangRefVisitor = VoidFunctor>
+ void VisitReferences(const Visitor& visitor,
+ const JavaLangRefVisitor& ref_visitor = VoidFunctor())
+ NO_THREAD_SAFETY_ANALYSIS;
+
protected:
// Accessors for non-Java type fields
template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -251,6 +259,17 @@
#endif
}
+ // TODO: Fixme when anotatalysis works with visitors.
+ template<bool kVisitClass, bool kIsStatic, typename Visitor>
+ void VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor)
+ NO_THREAD_SAFETY_ANALYSIS;
+ template<bool kVisitClass, typename Visitor>
+ void VisitInstanceFieldsReferences(mirror::Class* klass, const Visitor& visitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kVisitClass, typename Visitor>
+ void VisitStaticFieldsReferences(mirror::Class* klass, const Visitor& visitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
// Verify the type correctness of stores to fields.
void CheckFieldAssignmentImpl(MemberOffset field_offset, Object* new_value)
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index a427957..8032cc3 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -233,6 +233,17 @@
(i * sizeof(HeapReference<Object>)));
}
+template<class T> template<const bool kVisitClass, typename Visitor>
+void ObjectArray<T>::VisitReferences(const Visitor& visitor) {
+ if (kVisitClass) {
+ visitor(this, ClassOffset(), false);
+ }
+ const size_t length = static_cast<size_t>(GetLength());
+ for (size_t i = 0; i < length; ++i) {
+ visitor(this, OffsetOfElement(i), false);
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 7f9e716..5ff0490 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -78,6 +78,11 @@
ObjectArray<T>* CopyOf(Thread* self, int32_t new_length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<const bool kVisitClass, typename Visitor>
+ void VisitReferences(const Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS;
+
private:
static MemberOffset OffsetOfElement(int32_t i);