summaryrefslogtreecommitdiff
path: root/runtime/mirror/object-refvisitor-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/mirror/object-refvisitor-inl.h')
-rw-r--r--runtime/mirror/object-refvisitor-inl.h96
1 files changed, 96 insertions, 0 deletions
diff --git a/runtime/mirror/object-refvisitor-inl.h b/runtime/mirror/object-refvisitor-inl.h
index f98c433cdd..2361d79f3f 100644
--- a/runtime/mirror/object-refvisitor-inl.h
+++ b/runtime/mirror/object-refvisitor-inl.h
@@ -90,6 +90,102 @@ inline void Object::VisitReferences(const Visitor& visitor,
}
}
+// Could be called with from-space address of the object as we access klass and
+// length (in case of arrays/strings) and we don't want to cause cascading faults.
+template <bool kFetchObjSize,
+ bool kVisitNativeRoots,
+ VerifyObjectFlags kVerifyFlags,
+ ReadBarrierOption kReadBarrierOption,
+ typename Visitor>
+inline size_t Object::VisitRefsForCompaction(const Visitor& visitor,
+ MemberOffset begin,
+ MemberOffset end) {
+ constexpr VerifyObjectFlags kSizeOfFlags = RemoveThisFlags(kVerifyFlags);
+ size_t size;
+ // We want to continue using pre-compact klass to avoid cascading faults.
+ ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>();
+ visitor(this, ClassOffset(), /* is_static= */ false);
+ const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>();
+ if (LIKELY(class_flags == kClassFlagNormal)) {
+ DCHECK((!klass->IsVariableSize<kVerifyFlags>()));
+ VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
+ size = kFetchObjSize ? klass->GetObjectSize<kSizeOfFlags>() : 0;
+ 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);
+ return kFetchObjSize ? as_klass->SizeOf<kSizeOfFlags>() : 0;
+ } else if (class_flags == kClassFlagObjectArray) {
+ DCHECK((klass->IsObjectArrayClass<kVerifyFlags>()));
+ ObjPtr<ObjectArray<mirror::Object>> obj_arr = AsObjectArray<mirror::Object, kVerifyNone>();
+ obj_arr->VisitReferences(visitor, begin, end);
+ return kFetchObjSize ? obj_arr->SizeOf<kSizeOfFlags>() : 0;
+ } else if ((class_flags & kClassFlagReference) != 0) {
+ VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor);
+ // Visit referent also as this is about updating the reference only.
+ // There is no reference processing happening here.
+ visitor(this, mirror::Reference::ReferentOffset(), /* is_static= */ false);
+ if ((class_flags & kClassFlagFinalizerReference) != 0) {
+ visitor(this, mirror::FinalizerReference::ZombieOffset(), /* is_static= */ false);
+ }
+ } 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);
+ }
+ size = kFetchObjSize ? klass->GetObjectSize<kSizeOfFlags>() : 0;
+ } else {
+ DCHECK((!klass->IsClassClass<kVerifyFlags>()));
+ DCHECK((!klass->IsObjectArrayClass<kVerifyFlags>()));
+ if (class_flags == kClassFlagString) {
+ size = kFetchObjSize ? AsString<kSizeOfFlags>()->template SizeOf<kSizeOfFlags>() : 0;
+ } else if (klass->IsArrayClass<kVerifyFlags>()) {
+ // TODO: We can optimize this by implementing a SizeOf() version which takes
+ // component-size-shift as an argument, thereby avoiding multiple loads of
+ // component_type.
+ size = kFetchObjSize ? AsArray<kSizeOfFlags>()->template SizeOf<kSizeOfFlags>() : 0;
+ } else {
+ DCHECK_NE(class_flags & kClassFlagNormal, 0u);
+ // Only possibility left is of a normal klass instance with no references.
+ size = kFetchObjSize ? klass->GetObjectSize<kSizeOfFlags>() : 0;
+ }
+
+ if (kIsDebugBuild) {
+ // 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);
+ }
+ }
+ }
+ }
+ return size;
+}
+
} // namespace mirror
} // namespace art