// Normal instance with at least one ref field other than the class.
static constexpr uint32_t kClassFlagNormal = 0x00000000;
// Only normal objects which have no reference fields, e.g. string or primitive array or normal
// class instance with no fields other than klass.
static constexpr uint32_t kClassFlagNoReferenceFields = 0x00000001;
// Class is java.lang.String.class.
static constexpr uint32_t kClassFlagString = 0x00000004;
// Class is an object array class.
static constexpr uint32_t kClassFlagObjectArray = 0x00000008;
// Class is java.lang.Class.class.
static constexpr uint32_t kClassFlagClass = 0x00000010;
// Class is ClassLoader or one of its subclasses.
static constexpr uint32_t kClassFlagClassLoader = 0x00000020;
// Class is DexCache.
static constexpr uint32_t kClassFlagDexCache = 0x00000040;
// Class is a soft/weak/phantom class.
static constexpr uint32_t kClassFlagSoftReference = 0x00000080;
// Class is a weak reference class.
static constexpr uint32_t kClassFlagWeakReference = 0x00000100;
// Class is a finalizer reference class.
static constexpr uint32_t kClassFlagFinalizerReference = 0x00000200;
// Class is the phantom reference class.
static constexpr uint32_t kClassFlagPhantomReference = 0x00000400;
template <bool kVisitNativeRoots,
VerifyObjectFlags kVerifyFlags,
ReadBarrierOption kReadBarrierOption,
typename Visitor,
typename JavaLangRefVisitor>
inline void Object::VisitReferences(const Visitor& visitor,
const JavaLangRefVisitor& ref_visitor) {
visitor(this, ClassOffset(), /* is_static= */ false);
ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>();
const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
if (LIKELY(class_flags == kClassFlagNormal)) {
DCHECK((!klass->IsVariableSize<kVerifyFlags>()));
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
DCHECK((!klass->IsClassClass<kVerifyFlags>()));
DCHECK(!klass->IsStringClass<kVerifyFlags>());
DCHECK(!klass->IsClassLoaderClass<kVerifyFlags>());
DCHECK((!klass->IsArrayClass<kVerifyFlags>()));
} else {
if ((class_flags & kClassFlagNoReferenceFields) == 0) {
DCHECK(!klass->IsStringClass<kVerifyFlags>());
if (class_flags == kClassFlagClass) {
DCHECK((klass->IsClassClass<kVerifyFlags>()));
ObjPtr<Class> as_klass = AsClass<kVerifyNone>();
as_klass->VisitReferences<kVisitNativeRoots, kVerifyFlags, kReadBarrierOption>(klass,
visitor);
} else if (class_flags == kClassFlagObjectArray) {
DCHECK((klass->IsObjectArrayClass<kVerifyFlags>()));
AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor);
} else if ((class_flags & kClassFlagReference) != 0) {
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
ref_visitor(klass, AsReference<kVerifyFlags, kReadBarrierOption>());
} else if (class_flags == kClassFlagDexCache) {
ObjPtr<mirror::DexCache> const dex_cache = AsDexCache<kVerifyFlags, kReadBarrierOption>();
dex_cache->VisitReferences<kVisitNativeRoots,
kVerifyFlags,
kReadBarrierOption>(klass, visitor);
} else {
ObjPtr<mirror::ClassLoader> const class_loader =
AsClassLoader<kVerifyFlags, kReadBarrierOption>();
class_loader->VisitReferences<kVisitNativeRoots,
kVerifyFlags,
kReadBarrierOption>(klass, visitor);
}
} else if (kIsDebugBuild) {
CHECK((!klass->IsClassClass<kVerifyFlags>()));
CHECK((!klass->IsObjectArrayClass<kVerifyFlags>()));
// String still has instance fields for reflection purposes but these don't exist in
// actual string instances.
if (!klass->IsStringClass<kVerifyFlags>()) {
size_t total_reference_instance_fields = 0;
ObjPtr<Class> super_class = klass;
do {
total_reference_instance_fields +=
super_class->NumReferenceInstanceFields<kVerifyFlags>();
super_class = super_class->GetSuperClass<kVerifyFlags, kReadBarrierOption>();
} while (super_class != nullptr);
// The only reference field should be the object's class. This field is handled at the
// beginning of the function.
CHECK_EQ(total_reference_instance_fields, 1u);
}
}
}
}
class
template <bool kVisitNativeRoots,
VerifyObjectFlags kVerifyFlags,
ReadBarrierOption kReadBarrierOption,
typename Visitor>
inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) {
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor);
// Right after a class is allocated, but not yet loaded
// (ClassStatus::kNotReady, see ClassLinker::LoadClass()), GC may find it
// and scan it. IsTemp() may call Class::GetAccessFlags() but may
// fail in the DCHECK in Class::GetAccessFlags() because the class
// status is ClassStatus::kNotReady. To avoid it, rely on IsResolved()
// only. This is fine because a temp class never goes into the
// ClassStatus::kResolved state.
if (IsResolved<kVerifyFlags>()) {
// Temp classes don't ever populate imt/vtable or static fields and they are not even
// allocated with the right size for those. Also, unresolved classes don't have fields
// linked yet.
VisitStaticFieldsReferences<kVerifyFlags, kReadBarrierOption>(this, visitor);
}
if (kVisitNativeRoots) {
// Since this class is reachable, we must also visit the associated roots when we scan it.
VisitNativeRoots<kReadBarrierOption>(
visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
}
}
template<ReadBarrierOption kReadBarrierOption, class Visitor>
void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
VisitFields<kReadBarrierOption>([&](ArtField* field) REQUIRES_SHARED(art::Locks::mutator_lock_) {
field->VisitRoots(visitor);
if (kIsDebugBuild && IsResolved()) {
CHECK_EQ(field->GetDeclaringClass<kReadBarrierOption>(), this)
<< GetStatus() << field->GetDeclaringClass()->PrettyClass() << " != " << PrettyClass();
}
});
// Don't use VisitMethods because we don't want to hit the class-ext methods twice.
for (ArtMethod& method : GetMethods(pointer_size)) {
method.VisitRoots<kReadBarrierOption>(visitor, pointer_size);
}
ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>());
if (!ext.IsNull()) {
ext->VisitNativeRoots<kReadBarrierOption, Visitor>(visitor, pointer_size);
}
}
ObjectArray
template<class T> template<typename Visitor>
inline void ObjectArray<T>::VisitReferences(const Visitor& visitor) {
const size_t length = static_cast<size_t>(GetLength());
for (size_t i = 0; i < length; ++i) {
visitor(this, OffsetOfElement(i), false);
}
}
DexCache
template <bool kVisitNativeRoots,
VerifyObjectFlags kVerifyFlags,
ReadBarrierOption kReadBarrierOption,
typename Visitor>
inline void DexCache::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) {
// Visit instance fields first.
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
// Visit arrays after.
if (kVisitNativeRoots) {
VisitDexCachePairs<String, kReadBarrierOption, Visitor>(
GetStrings<kVerifyFlags>(), NumStrings<kVerifyFlags>(), visitor);
VisitDexCachePairs<Class, kReadBarrierOption, Visitor>(
GetResolvedTypes<kVerifyFlags>(), NumResolvedTypes<kVerifyFlags>(), visitor);
VisitDexCachePairs<MethodType, kReadBarrierOption, Visitor>(
GetResolvedMethodTypes<kVerifyFlags>(), NumResolvedMethodTypes<kVerifyFlags>(), visitor);
GcRoot<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites<kVerifyFlags>();
size_t num_call_sites = NumResolvedCallSites<kVerifyFlags>();
for (size_t i = 0; i != num_call_sites; ++i) {
visitor.VisitRootIfNonNull(resolved_call_sites[i].AddressWithoutBarrier());
}
GcRoot<mirror::String>* const preresolved_strings = GetPreResolvedStrings();
if (preresolved_strings != nullptr) {
const size_t num_preresolved_strings = NumPreResolvedStrings();
for (size_t i = 0; i != num_preresolved_strings; ++i) {
visitor.VisitRootIfNonNull(preresolved_strings[i].AddressWithoutBarrier());
}
}
}
}
ClassLoader
template <bool kVisitClasses,
VerifyObjectFlags kVerifyFlags,
ReadBarrierOption kReadBarrierOption,
typename Visitor>
inline void ClassLoader::VisitReferences(ObjPtr<mirror::Class> klass, const Visitor& visitor) {
// Visit instance fields first.
VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
if (kVisitClasses) {
// Visit classes loaded after.
ClassTable* const class_table = GetClassTable<kVerifyFlags>();
if (class_table != nullptr) {
class_table->VisitRoots(visitor);
}
}
}