From 52a7f5caebdf359ab877f1928aad59f1e9ad29fa Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Tue, 18 Aug 2015 18:35:52 -0700 Subject: [PATCH] Add class flags to class to help GC scanning Reduces GC time and pauses by reducing the number of loads required to scan an object. Average total GC time before on EvaluateAndApplyChanges (EAAC): 7.452s After: 7.144s Average GC pause times before on EAAC: 860.67us After: 722.75us Adding the class flags field cause a memory increase of ~24k system wide on low memory devices. Change-Id: I3f04212d5787bfbf5e55026584d149f55476105e --- runtime/asm_support.h | 6 ++-- runtime/class_linker.cc | 38 +++++++++++++++++------- runtime/class_linker_test.cc | 1 + runtime/gc/collector/mark_sweep-inl.h | 13 ++++++-- runtime/gc/collector/mark_sweep.cc | 23 +++++++------- runtime/gc/collector/mark_sweep.h | 13 +++++--- runtime/gc/heap.cc | 2 +- runtime/image.cc | 2 +- runtime/mirror/class-inl.h | 13 ++++++-- runtime/mirror/class.cc | 1 + runtime/mirror/class.h | 33 +++++++++++++-------- runtime/mirror/class_flags.h | 56 +++++++++++++++++++++++++++++++++++ runtime/mirror/object-inl.h | 48 ++++++++++++++++++++++-------- runtime/mirror/string.cc | 1 + runtime/mirror/string.h | 7 ++--- runtime/modifiers.h | 24 +++------------ 16 files changed, 198 insertions(+), 83 deletions(-) create mode 100644 runtime/mirror/class_flags.h diff --git a/runtime/asm_support.h b/runtime/asm_support.h index 35acd424b..084c88e23 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -141,10 +141,10 @@ ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET, #define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET, art::mirror::Class::AccessFlagsOffset().Int32Value()) -#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET, art::mirror::Class::ObjectSizeOffset().Int32Value()) -#define MIRROR_CLASS_STATUS_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET, art::mirror::Class::StatusOffset().Int32Value()) @@ -153,7 +153,7 @@ ADD_TEST_EQ(static_cast(MIRROR_CLASS_STATUS_INITIALIZED), static_cast(art::mirror::Class::kStatusInitialized)) #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000 ADD_TEST_EQ(static_cast(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), - static_cast(kAccClassIsFinalizable)) + static_cast(art::kAccClassIsFinalizable)) // Array offsets. #define MIRROR_ARRAY_LENGTH_OFFSET MIRROR_OBJECT_HEADER_SIZE diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c179c6449..b547d079c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -358,9 +358,9 @@ void ClassLinker::InitWithoutImage(std::vector> b // Setup String. Handle java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); + java_lang_String->SetStringClass(); mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self); - java_lang_String->SetStringClass(); // Setup java.lang.ref.Reference. Handle java_lang_ref_Reference(hs.NewHandle( @@ -570,16 +570,13 @@ void ClassLinker::InitWithoutImage(std::vector> b CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize(image_pointer_size_)); class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); - class_root->SetAccessFlags(class_root->GetAccessFlags() | - kAccClassIsReference | kAccClassIsFinalizerReference); + class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference); class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;"); - class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference | - kAccClassIsPhantomReference); + class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference); class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;"); - class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference); + class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference); class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;"); - class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference | - kAccClassIsWeakReference); + class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference); // Setup the ClassLoader, verifying the object_size_. class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); @@ -2701,6 +2698,11 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto new_class->SetVTable(java_lang_Object->GetVTable()); new_class->SetPrimitiveType(Primitive::kPrimNot); new_class->SetClassLoader(component_type->GetClassLoader()); + if (component_type->IsPrimitive()) { + new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields); + } else { + new_class->SetClassFlags(mirror::kClassFlagObjectArray); + } mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self); { ArtMethod* imt[mirror::Class::kImtSize]; @@ -4385,9 +4387,9 @@ bool ClassLinker::LinkSuperClass(Handle klass) { } // Inherit reference flags (if any) from the superclass. - int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask); + int reference_flags = (super->GetClassFlags() & mirror::kClassFlagReference); if (reference_flags != 0) { - klass->SetAccessFlags(klass->GetAccessFlags() | reference_flags); + klass->SetClassFlags(klass->GetClassFlags() | reference_flags); } // Disallow custom direct subclasses of java.lang.ref.Reference. if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) { @@ -5227,6 +5229,22 @@ bool ClassLinker::LinkFields(Thread* self, Handle klass, bool is_ *class_size = size; } else { klass->SetNumReferenceInstanceFields(num_reference_fields); + mirror::Class* super_class = klass->GetSuperClass(); + if (num_reference_fields == 0 || super_class == nullptr) { + // object has one reference field, klass, but we ignore it since we always visit the class. + // If the super_class is null then we are java.lang.Object. + if (super_class == nullptr || + (super_class->GetClassFlags() & mirror::kClassFlagNoReferenceFields) != 0) { + klass->SetClassFlags(klass->GetClassFlags() | mirror::kClassFlagNoReferenceFields); + } else if (kIsDebugBuild) { + size_t total_reference_instance_fields = 0; + while (super_class != nullptr) { + total_reference_instance_fields += super_class->NumReferenceInstanceFields(); + super_class = super_class->GetSuperClass(); + } + CHECK_GT(total_reference_instance_fields, 1u); + } + } if (!klass->IsVariableSize()) { std::string temp; DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 3c84d8fc0..0d1c875fd 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -488,6 +488,7 @@ struct ObjectOffsets : public CheckOffsets { struct ClassOffsets : public CheckOffsets { ClassOffsets() : CheckOffsets(false, "Ljava/lang/Class;") { addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"); addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"); diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h index a3cc83132..56edcc9d0 100644 --- a/runtime/gc/collector/mark_sweep-inl.h +++ b/runtime/gc/collector/mark_sweep-inl.h @@ -35,10 +35,17 @@ inline void MarkSweep::ScanObjectVisit(mirror::Object* obj, const MarkVisitor& v obj->VisitReferences(visitor, ref_visitor); if (kCountScannedTypes) { mirror::Class* klass = obj->GetClass(); - if (UNLIKELY(klass == mirror::Class::GetJavaLangClass())) { + uint32_t class_flags = klass->GetClassFlags(); + if ((class_flags & mirror::kClassFlagNoReferenceFields) != 0) { + ++no_reference_class_count_; + } else if (class_flags == mirror::kClassFlagNormal) { + ++normal_count_; + } else if (class_flags == mirror::kClassFlagObjectArray) { + ++object_array_count_; + } else if (class_flags == mirror::kClassFlagClass) { ++class_count_; - } else if (UNLIKELY(klass->IsArrayClass())) { - ++array_count_; + } else if ((class_flags & mirror::kClassFlagReference) != 0) { + ++reference_count_; } else { ++other_count_; } diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index b0a8a5bf2..7ddc7ccc6 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -70,7 +70,6 @@ static constexpr bool kParallelProcessMarkStack = true; static constexpr bool kProfileLargeObjects = false; static constexpr bool kMeasureOverhead = false; static constexpr bool kCountTasks = false; -static constexpr bool kCountJavaLangRefs = false; static constexpr bool kCountMarkedObjects = false; // Turn off kCheckLocks when profiling the GC since it slows the GC down by up to 40%. @@ -114,15 +113,17 @@ void MarkSweep::InitializePhase() { mark_stack_ = heap_->GetMarkStack(); DCHECK(mark_stack_ != nullptr); immune_region_.Reset(); + no_reference_class_count_.StoreRelaxed(0); + normal_count_.StoreRelaxed(0); class_count_.StoreRelaxed(0); - array_count_.StoreRelaxed(0); + object_array_count_.StoreRelaxed(0); other_count_.StoreRelaxed(0); + reference_count_.StoreRelaxed(0); large_object_test_.StoreRelaxed(0); large_object_mark_.StoreRelaxed(0); overhead_time_ .StoreRelaxed(0); work_chunks_created_.StoreRelaxed(0); work_chunks_deleted_.StoreRelaxed(0); - reference_count_.StoreRelaxed(0); mark_null_count_.StoreRelaxed(0); mark_immune_count_.StoreRelaxed(0); mark_fastpath_count_.StoreRelaxed(0); @@ -1265,9 +1266,6 @@ void MarkSweep::SweepLargeObjects(bool swap_bitmaps) { // Process the "referent" field in a java.lang.ref.Reference. If the referent has not yet been // marked, put it on the appropriate list in the heap for later processing. void MarkSweep::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref) { - if (kCountJavaLangRefs) { - ++reference_count_; - } heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this); } @@ -1386,8 +1384,14 @@ inline mirror::Object* MarkSweep::IsMarked(mirror::Object* object) { void MarkSweep::FinishPhase() { TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings()); if (kCountScannedTypes) { - VLOG(gc) << "MarkSweep scanned classes=" << class_count_.LoadRelaxed() - << " arrays=" << array_count_.LoadRelaxed() << " other=" << other_count_.LoadRelaxed(); + VLOG(gc) + << "MarkSweep scanned" + << " no reference objects=" << no_reference_class_count_.LoadRelaxed() + << " normal objects=" << normal_count_.LoadRelaxed() + << " classes=" << class_count_.LoadRelaxed() + << " object arrays=" << object_array_count_.LoadRelaxed() + << " references=" << reference_count_.LoadRelaxed() + << " other=" << other_count_.LoadRelaxed(); } if (kCountTasks) { VLOG(gc) << "Total number of work chunks allocated: " << work_chunks_created_.LoadRelaxed(); @@ -1399,9 +1403,6 @@ void MarkSweep::FinishPhase() { VLOG(gc) << "Large objects tested " << large_object_test_.LoadRelaxed() << " marked " << large_object_mark_.LoadRelaxed(); } - if (kCountJavaLangRefs) { - VLOG(gc) << "References scanned " << reference_count_.LoadRelaxed(); - } if (kCountMarkedObjects) { VLOG(gc) << "Marked: null=" << mark_null_count_.LoadRelaxed() << " immune=" << mark_immune_count_.LoadRelaxed() diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 8bd1dc7cd..371bba531 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -245,7 +245,7 @@ class MarkSweep : public GarbageCollector { void RevokeAllThreadLocalBuffers(); // Whether or not we count how many of each type of object were scanned. - static const bool kCountScannedTypes = false; + static constexpr bool kCountScannedTypes = false; // Current space, we check this space first to avoid searching for the appropriate space for an // object. @@ -260,18 +260,23 @@ class MarkSweep : public GarbageCollector { // Parallel finger. AtomicInteger atomic_finger_; + + AtomicInteger no_reference_class_count_; + AtomicInteger normal_count_; // Number of classes scanned, if kCountScannedTypes. AtomicInteger class_count_; - // Number of arrays scanned, if kCountScannedTypes. - AtomicInteger array_count_; + // Number of object arrays scanned, if kCountScannedTypes. + AtomicInteger object_array_count_; // Number of non-class/arrays scanned, if kCountScannedTypes. AtomicInteger other_count_; + // Number of java.lang.ref.Reference instances. + AtomicInteger reference_count_; + AtomicInteger large_object_test_; AtomicInteger large_object_mark_; AtomicInteger overhead_time_; AtomicInteger work_chunks_created_; AtomicInteger work_chunks_deleted_; - AtomicInteger reference_count_; AtomicInteger mark_null_count_; AtomicInteger mark_immune_count_; AtomicInteger mark_fastpath_count_; diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index d7f918b4f..b8c44781a 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3707,7 +3707,7 @@ void Heap::AddModUnionTable(accounting::ModUnionTable* mod_union_table) { void Heap::CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count) { CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) || - (c->IsVariableSize() || c->GetObjectSize() == byte_count)); + (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags(); CHECK_GE(byte_count, sizeof(mirror::Object)); } diff --git a/runtime/image.cc b/runtime/image.cc index 2586959e5..8df17c692 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -24,7 +24,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '1', '9', '\0' }; +const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '0', '\0' }; ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index cd678f670..b2c6e4da1 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -547,6 +547,7 @@ inline uint32_t Class::GetAccessFlags() { inline String* Class::GetName() { return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_)); } + inline void Class::SetName(String* name) { if (Runtime::Current()->IsActiveTransaction()) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_), name); @@ -784,9 +785,17 @@ inline void Class::InitializeClassVisitor::operator()( inline void Class::SetAccessFlags(uint32_t new_access_flags) { // Called inside a transaction when setting pre-verified flag during boot image compilation. if (Runtime::Current()->IsActiveTransaction()) { - SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags); + SetField32(AccessFlagsOffset(), new_access_flags); + } else { + SetField32(AccessFlagsOffset(), new_access_flags); + } +} + +inline void Class::SetClassFlags(uint32_t new_flags) { + if (Runtime::Current()->IsActiveTransaction()) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags); } else { - SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags); + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_), new_flags); } } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 055b3e511..228fd27f2 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -44,6 +44,7 @@ void Class::SetClassClass(Class* java_lang_Class) { << java_lang_Class_.Read() << " " << java_lang_Class; CHECK(java_lang_Class != nullptr); + java_lang_Class->SetClassFlags(java_lang_Class->GetClassFlags() | mirror::kClassFlagClass); java_lang_Class_ = GcRoot(java_lang_Class); } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 3f375be9c..cbcb51700 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -19,6 +19,7 @@ #include "base/iteration_range.h" #include "dex_file.h" +#include "class_flags.h" #include "gc_root.h" #include "gc/allocator_type.h" #include "invoke_type.h" @@ -201,6 +202,12 @@ class MANAGED Class FINAL : public Object { return OFFSET_OF_OBJECT_MEMBER(Class, access_flags_); } + template + ALWAYS_INLINE uint32_t GetClassFlags() SHARED_REQUIRES(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_flags_)); + } + void SetClassFlags(uint32_t new_flags) SHARED_REQUIRES(Locks::mutator_lock_); + void SetAccessFlags(uint32_t new_access_flags) SHARED_REQUIRES(Locks::mutator_lock_); // Returns true if the class is an interface. @@ -228,21 +235,19 @@ class MANAGED Class FINAL : public Object { } ALWAYS_INLINE bool IsStringClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetField32(AccessFlagsOffset()) & kAccClassIsStringClass) != 0; + return (GetClassFlags() & kClassFlagString) != 0; } ALWAYS_INLINE void SetStringClass() SHARED_REQUIRES(Locks::mutator_lock_) { - uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); - SetAccessFlags(flags | kAccClassIsStringClass); + SetClassFlags(GetClassFlags() | kClassFlagString | kClassFlagNoReferenceFields); } ALWAYS_INLINE bool IsClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetField32(AccessFlagsOffset()) & kAccClassIsClassLoaderClass) != 0; + return (GetClassFlags() & kClassFlagClassLoader) != 0; } ALWAYS_INLINE void SetClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) { - uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); - SetAccessFlags(flags | kAccClassIsClassLoaderClass); + SetClassFlags(GetClassFlags() | kClassFlagClassLoader); } // Returns true if the class is abstract. @@ -272,27 +277,27 @@ class MANAGED Class FINAL : public Object { template bool IsTypeOfReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccClassIsReference) != 0; + return (GetClassFlags() & kClassFlagReference) != 0; } template bool IsWeakReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccClassIsWeakReference) != 0; + return (GetClassFlags() & kClassFlagWeakReference) != 0; } template bool IsSoftReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccReferenceFlagsMask) == kAccClassIsReference; + return (GetClassFlags() & kClassFlagSoftReference) != 0; } template bool IsFinalizerReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccClassIsFinalizerReference) != 0; + return (GetClassFlags() & kClassFlagFinalizerReference) != 0; } template bool IsPhantomReferenceClass() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccClassIsPhantomReference) != 0; + return (GetClassFlags() & kClassFlagPhantomReference) != 0; } // Can references of this type be assigned to by things of another type? For non-array types @@ -862,7 +867,8 @@ class MANAGED Class FINAL : public Object { uint32_t NumInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_); ArtField* GetInstanceField(uint32_t i) SHARED_REQUIRES(Locks::mutator_lock_); - // Returns the number of instance fields containing reference types. + // Returns the number of instance fields containing reference types not counting fields in the + // super class. uint32_t NumReferenceInstanceFields() SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(IsResolved() || IsErroneous()); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_)); @@ -1225,6 +1231,9 @@ class MANAGED Class FINAL : public Object { // length-prefixed array. uint64_t virtual_methods_; + // Class flags to help speed up visiting object references. + uint32_t class_flags_; + // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. uint32_t class_size_; diff --git a/runtime/mirror/class_flags.h b/runtime/mirror/class_flags.h new file mode 100644 index 000000000..6c1563917 --- /dev/null +++ b/runtime/mirror/class_flags.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 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_CLASS_FLAGS_H_ +#define ART_RUNTIME_MIRROR_CLASS_FLAGS_H_ + +#include + +namespace art { +namespace mirror { + +// Object types stored in class to help GC with faster object marking. +static constexpr uint32_t kClassFlagNormal = 0x00000000; +// Only normal objects which have no reference fields, e.g. string or primitive array or normal +// class instance. +static constexpr uint32_t kClassFlagNoReferenceFields = 0x00000001; +static constexpr uint32_t kClassFlagString = 0x00000004; +static constexpr uint32_t kClassFlagObjectArray = 0x00000008; +static constexpr uint32_t kClassFlagClass = 0x00000010; + +// class is ClassLoader or one of its subclasses +static constexpr uint32_t kClassFlagClassLoader = 0x00000020; + +// class is a soft/weak/phantom ref +static constexpr uint32_t kClassFlagSoftReference = 0x00000040; +// class is a weak reference +static constexpr uint32_t kClassFlagWeakReference = 0x00000080; +// class is a finalizer reference +static constexpr uint32_t kClassFlagFinalizerReference = 0x00000100; +// class is a phantom reference +static constexpr uint32_t kClassFlagPhantomReference = 0x00000200; + +static constexpr uint32_t kClassFlagReference = + kClassFlagSoftReference | + kClassFlagWeakReference | + kClassFlagFinalizerReference | + kClassFlagPhantomReference; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_CLASS_FLAGS_H_ + diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 586ae30d1..702a0f49e 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -24,6 +24,7 @@ #include "atomic.h" #include "array-inl.h" #include "class.h" +#include "class_flags.h" #include "class_linker.h" #include "class_loader-inl.h" #include "lock_word-inl.h" @@ -1010,20 +1011,43 @@ inline void Object::VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor) { mirror::Class* klass = GetClass(); visitor(this, ClassOffset(), false); - if (klass == Class::GetJavaLangClass()) { - AsClass()->VisitReferences(klass, visitor); - } else if (klass->IsArrayClass() || klass->IsStringClass()) { - if (klass->IsObjectArrayClass()) { - AsObjectArray()->VisitReferences(visitor); - } - } else if (klass->IsClassLoaderClass()) { - mirror::ClassLoader* class_loader = AsClassLoader(); - class_loader->VisitReferences(klass, visitor); - } else { + const uint32_t class_flags = klass->GetClassFlags(); + if (LIKELY(class_flags == kClassFlagNormal)) { DCHECK(!klass->IsVariableSize()); VisitInstanceFieldsReferences(klass, visitor); - if (UNLIKELY(klass->IsTypeOfReferenceClass())) { - ref_visitor(klass, AsReference()); + DCHECK(!klass->IsClassClass()); + } else { + if ((class_flags & kClassFlagNoReferenceFields) == 0) { + DCHECK(!klass->IsStringClass()); + if (class_flags == kClassFlagClass) { + DCHECK(klass->IsClassClass()); + AsClass()->VisitReferences(klass, visitor); + } else if (class_flags == kClassFlagObjectArray) { + DCHECK(klass->IsObjectArrayClass()); + AsObjectArray()->VisitReferences(visitor); + } else if ((class_flags & kClassFlagReference) != 0) { + VisitInstanceFieldsReferences(klass, visitor); + ref_visitor(klass, AsReference()); + } else { + mirror::ClassLoader* const class_loader = AsClassLoader(); + class_loader->VisitReferences(klass, visitor); + } + } else if (kIsDebugBuild) { + CHECK(!klass->IsClassClass()); + CHECK(!klass->IsObjectArrayClass()); + // String still has instance fields for reflection purposes but these don't exist in + // actual string instances. + if (!klass->IsStringClass()) { + size_t total_reference_instance_fields = 0; + mirror::Class* super_class = klass; + do { + total_reference_instance_fields += super_class->NumReferenceInstanceFields(); + super_class = super_class->GetSuperClass(); + } 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); + } } } } diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index b6236b1eb..45610dccc 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -55,6 +55,7 @@ int32_t String::FastIndexOf(int32_t ch, int32_t start) { void String::SetClass(Class* java_lang_String) { CHECK(java_lang_String_.IsNull()); CHECK(java_lang_String != nullptr); + CHECK(java_lang_String->IsStringClass()); java_lang_String_ = GcRoot(java_lang_String); } diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index eb2e1f697..fbee2d7bf 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -157,10 +157,9 @@ class MANAGED String FINAL : public Object { return java_lang_String_.Read(); } - static void SetClass(Class* java_lang_String); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - SHARED_REQUIRES(Locks::mutator_lock_); + static void SetClass(Class* java_lang_String) SHARED_REQUIRES(Locks::mutator_lock_); + static void ResetClass() SHARED_REQUIRES(Locks::mutator_lock_); + static void VisitRoots(RootVisitor* visitor) SHARED_REQUIRES(Locks::mutator_lock_); private: void SetHashCode(int32_t new_hash_code) SHARED_REQUIRES(Locks::mutator_lock_) { diff --git a/runtime/modifiers.h b/runtime/modifiers.h index 0d9ec29db..f7ab10be9 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -19,6 +19,8 @@ #include +namespace art { + static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic @@ -49,28 +51,8 @@ static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only) // Special runtime-only flags. -// Note: if only kAccClassIsReference is set, we have a soft reference. - -// class is ClassLoader or one of its subclasses -static constexpr uint32_t kAccClassIsClassLoaderClass = 0x10000000; - // class/ancestor overrides finalize() static constexpr uint32_t kAccClassIsFinalizable = 0x80000000; -// class is a soft/weak/phantom ref -static constexpr uint32_t kAccClassIsReference = 0x08000000; -// class is a weak reference -static constexpr uint32_t kAccClassIsWeakReference = 0x04000000; -// class is a finalizer reference -static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000; -// class is a phantom reference -static constexpr uint32_t kAccClassIsPhantomReference = 0x01000000; -// class is the string class -static constexpr uint32_t kAccClassIsStringClass = 0x00800000; - -static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference - | kAccClassIsWeakReference - | kAccClassIsFinalizerReference - | kAccClassIsPhantomReference); // Valid (meaningful) bits for a field. static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected | @@ -95,5 +77,7 @@ static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSup static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface | kAccAbstract | kAccSynthetic | kAccAnnotation; +} // namespace art + #endif // ART_RUNTIME_MODIFIERS_H_ -- 2.11.0