diff options
-rw-r--r-- | compiler/driver/compiler_driver.cc | 24 | ||||
-rw-r--r-- | runtime/class_linker.cc | 18 | ||||
-rw-r--r-- | runtime/class_table-inl.h | 44 | ||||
-rw-r--r-- | runtime/class_table.cc | 10 | ||||
-rw-r--r-- | runtime/class_table.h | 11 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.cc | 2 | ||||
-rw-r--r-- | runtime/hprof/hprof.cc | 36 | ||||
-rw-r--r-- | runtime/mirror/class.h | 9 | ||||
-rw-r--r-- | runtime/mirror/class_loader-inl.h | 43 | ||||
-rw-r--r-- | runtime/mirror/class_loader.h | 8 | ||||
-rw-r--r-- | runtime/mirror/object-inl.h | 16 | ||||
-rw-r--r-- | runtime/mirror/object.h | 6 | ||||
-rw-r--r-- | runtime/modifiers.h | 3 |
13 files changed, 199 insertions, 31 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 299b99585a..fa4667ec97 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -829,6 +829,18 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve) : exceptions_to_resolve_(exceptions_to_resolve) {} + virtual bool Visit(mirror::Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { + const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); + for (auto& m : c->GetVirtualMethods(pointer_size)) { + ResolveExceptionsForMethod(&m); + } + for (auto& m : c->GetDirectMethods(pointer_size)) { + ResolveExceptionsForMethod(&m); + } + return true; + } + + private: void ResolveExceptionsForMethod(ArtMethod* method_handle) SHARED_REQUIRES(Locks::mutator_lock_) { const DexFile::CodeItem* code_item = method_handle->GetCodeItem(); if (code_item == nullptr) { @@ -864,18 +876,6 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { } } - virtual bool Visit(mirror::Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { - const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& m : c->GetVirtualMethods(pointer_size)) { - ResolveExceptionsForMethod(&m); - } - for (auto& m : c->GetDirectMethods(pointer_size)) { - ResolveExceptionsForMethod(&m); - } - return true; - } - - private: std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve_; }; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0886e327d9..f19263d757 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -37,6 +37,7 @@ #include "base/unix_file/fd_file.h" #include "base/value_object.h" #include "class_linker-inl.h" +#include "class_table-inl.h" #include "compiler_callbacks.h" #include "debugger.h" #include "dex_file-inl.h" @@ -582,6 +583,7 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Setup the ClassLoader, verifying the object_size_. class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); + class_root->SetClassLoaderClass(); CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize()); SetClassRoot(kJavaLangClassLoader, class_root); @@ -1273,15 +1275,10 @@ void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { // Moving concurrent: // Need to make sure to not copy ArtMethods without doing read barriers since the roots are // marked concurrently and we don't hold the classlinker_classes_lock_ when we do the copy. - boot_class_table_.VisitRoots(visitor, flags); + boot_class_table_.VisitRoots(buffered_visitor); for (GcRoot<mirror::ClassLoader>& root : class_loaders_) { // May be null for boot ClassLoader. root.VisitRoot(visitor, RootInfo(kRootVMInternal)); - ClassTable* const class_table = root.Read()->GetClassTable(); - if (class_table != nullptr) { - // May be null if we have no classes. - class_table->VisitRoots(visitor, flags); - } } } else if ((flags & kVisitRootFlagNewRoots) != 0) { for (auto& root : new_class_roots_) { @@ -2810,6 +2807,10 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k } VerifyObject(klass); class_table->InsertWithHash(klass, hash); + if (class_loader != nullptr) { + // This is necessary because we need to have the card dirtied for remembered sets. + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); + } if (log_new_class_table_roots_) { new_class_roots_.push_back(GcRoot<mirror::Class>(klass)); } @@ -4375,6 +4376,11 @@ bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { klass->SetFinalizable(); } + // Inherit class loader flag form super class. + if (super->IsClassLoaderClass()) { + klass->SetClassLoaderClass(); + } + // Inherit reference flags (if any) from the superclass. int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask); if (reference_flags != 0) { diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h new file mode 100644 index 0000000000..dc60a2c239 --- /dev/null +++ b/runtime/class_table-inl.h @@ -0,0 +1,44 @@ +/* + * 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_CLASS_TABLE_INL_H_ +#define ART_RUNTIME_CLASS_TABLE_INL_H_ + +#include "class_table.h" + +namespace art { + +template<class Visitor> +void ClassTable::VisitRoots(Visitor& visitor) { + for (ClassSet& class_set : classes_) { + for (GcRoot<mirror::Class>& root : class_set) { + visitor.VisitRoot(root.AddressWithoutBarrier()); + } + } +} + +template<class Visitor> +void ClassTable::VisitRoots(const Visitor& visitor) { + for (ClassSet& class_set : classes_) { + for (GcRoot<mirror::Class>& root : class_set) { + visitor.VisitRoot(root.AddressWithoutBarrier()); + } + } +} + +} // namespace art + +#endif // ART_RUNTIME_CLASS_TABLE_INL_H_ diff --git a/runtime/class_table.cc b/runtime/class_table.cc index c245d4e780..fc8e6c49da 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -61,16 +61,6 @@ mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* kl return existing; } -void ClassTable::VisitRoots(RootVisitor* visitor, VisitRootFlags flags ATTRIBUTE_UNUSED) { - BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor( - visitor, RootInfo(kRootStickyClass)); - for (ClassSet& class_set : classes_) { - for (GcRoot<mirror::Class>& root : class_set) { - buffered_visitor.VisitRoot(root); - } - } -} - bool ClassTable::Visit(ClassVisitor* visitor) { for (ClassSet& class_set : classes_) { for (GcRoot<mirror::Class>& root : class_set) { diff --git a/runtime/class_table.h b/runtime/class_table.h index 418295449f..6b18d9009d 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -67,8 +67,15 @@ class ClassTable { mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash) REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); - void VisitRoots(RootVisitor* visitor, VisitRootFlags flags) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + // NO_THREAD_SAFETY_ANALYSIS for object marking requiring heap bitmap lock. + template<class Visitor> + void VisitRoots(Visitor& visitor) + SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) + NO_THREAD_SAFETY_ANALYSIS; + template<class Visitor> + void VisitRoots(const Visitor& visitor) + SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) + NO_THREAD_SAFETY_ANALYSIS; // Return false if the callback told us to exit. bool Visit(ClassVisitor* visitor) diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index e2bcca23fb..5799b664e3 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -1276,7 +1276,7 @@ class MarkVisitor { explicit MarkVisitor(MarkSweep* const mark_sweep) ALWAYS_INLINE : mark_sweep_(mark_sweep) { } - void operator()(mirror::Object* obj, MemberOffset offset, bool /* is_static */) const + void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) { if (kCheckLocks) { diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index e67ea3fa8f..713797fc3d 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -883,6 +883,7 @@ class Hprof : public SingleRootVisitor { gc::EqAllocRecordTypesPtr<gc::AllocRecordStackTraceElement>> frames_; std::unordered_map<const mirror::Object*, const gc::AllocRecordStackTrace*> allocation_records_; + friend class GcRootVisitor; DISALLOW_COPY_AND_ASSIGN(Hprof); }; @@ -1023,12 +1024,47 @@ void Hprof::MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeap ++objects_in_segment_; } +// Use for visiting the GcRoots held live by ArtFields, ArtMethods, and ClassLoaders. +class GcRootVisitor { + public: + explicit GcRootVisitor(Hprof* hprof) : hprof_(hprof) {} + + void operator()(mirror::Object* obj ATTRIBUTE_UNUSED, + MemberOffset offset ATTRIBUTE_UNUSED, + bool is_static ATTRIBUTE_UNUSED) const {} + + // Note that these don't have read barriers. Its OK however since the GC is guaranteed to not be + // running during the hprof dumping process. + void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const + SHARED_REQUIRES(Locks::mutator_lock_) { + if (!root->IsNull()) { + VisitRoot(root); + } + } + + void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const + SHARED_REQUIRES(Locks::mutator_lock_) { + mirror::Object* obj = root->AsMirrorPtr(); + // The two cases are either classes or dex cache arrays. If it is a dex cache array, then use + // VM internal. Otherwise the object is a declaring class of an ArtField or ArtMethod or a + // class from a ClassLoader. + hprof_->VisitRoot(obj, RootInfo(obj->IsClass() ? kRootStickyClass : kRootVMInternal)); + } + + + private: + Hprof* const hprof_; +}; + void Hprof::DumpHeapObject(mirror::Object* obj) { // Ignore classes that are retired. if (obj->IsClass() && obj->AsClass()->IsRetired()) { return; } + GcRootVisitor visitor(this); + obj->VisitReferences<true>(visitor, VoidFunctor()); + gc::Heap* const heap = Runtime::Current()->GetHeap(); const gc::space::ContinuousSpace* const space = heap->FindContinuousSpaceFromObject(obj, true); HprofHeapId heap_type = HPROF_HEAP_APP; diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 513ab37033..dc60a380e3 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -236,6 +236,15 @@ class MANAGED Class FINAL : public Object { SetAccessFlags(flags | kAccClassIsStringClass); } + ALWAYS_INLINE bool IsClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) { + return (GetField32(AccessFlagsOffset()) & kAccClassIsClassLoaderClass) != 0; + } + + ALWAYS_INLINE void SetClassLoaderClass() SHARED_REQUIRES(Locks::mutator_lock_) { + uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); + SetAccessFlags(flags | kAccClassIsClassLoaderClass); + } + // Returns true if the class is abstract. ALWAYS_INLINE bool IsAbstract() SHARED_REQUIRES(Locks::mutator_lock_) { return (GetAccessFlags() & kAccAbstract) != 0; diff --git a/runtime/mirror/class_loader-inl.h b/runtime/mirror/class_loader-inl.h new file mode 100644 index 0000000000..35f3664fbf --- /dev/null +++ b/runtime/mirror/class_loader-inl.h @@ -0,0 +1,43 @@ +/* + * 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_LOADER_INL_H_ +#define ART_RUNTIME_MIRROR_CLASS_LOADER_INL_H_ + +#include "class_loader.h" + +#include "base/mutex-inl.h" +#include "class_table-inl.h" + +namespace art { +namespace mirror { + +template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags, typename Visitor> +inline void ClassLoader::VisitReferences(mirror::Class* klass, const Visitor& visitor) { + // Visit instance fields first. + VisitInstanceFieldsReferences<kVisitClass>(klass, visitor); + // Visit classes loaded after. + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + ClassTable* const class_table = GetClassTable(); + if (class_table != nullptr) { + class_table->VisitRoots(visitor); + } +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_CLASS_LOADER_INL_H_ diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h index 940aaa6fb2..21c652a941 100644 --- a/runtime/mirror/class_loader.h +++ b/runtime/mirror/class_loader.h @@ -26,6 +26,8 @@ class ClassTable; namespace mirror { +class Class; + // C++ mirror of java.lang.ClassLoader class MANAGED ClassLoader : public Object { public: @@ -44,6 +46,12 @@ class MANAGED ClassLoader : public Object { SetField64<false>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, class_table_), reinterpret_cast<uint64_t>(class_table)); } + // Visit instance fields of the class loader as well as its associated classes. + // Null class loader is handled by ClassLinker::VisitClassRoots. + template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags, typename Visitor> + void VisitReferences(mirror::Class* klass, const Visitor& visitor) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Locks::classlinker_classes_lock_); private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index c5610b5a2e..7b1660ba7e 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -25,6 +25,7 @@ #include "array-inl.h" #include "class.h" #include "class_linker.h" +#include "class_loader-inl.h" #include "lock_word-inl.h" #include "monitor.h" #include "object_array-inl.h" @@ -997,6 +998,18 @@ inline void Object::VisitStaticFieldsReferences(mirror::Class* klass, const Visi klass->VisitFieldsReferences<kVisitClass, true>(0, visitor); } + +template<VerifyObjectFlags kVerifyFlags> +inline bool Object::IsClassLoader() { + return GetClass<kVerifyFlags>()->IsClassLoaderClass(); +} + +template<VerifyObjectFlags kVerifyFlags> +inline mirror::ClassLoader* Object::AsClassLoader() { + DCHECK(IsClassLoader<kVerifyFlags>()); + return down_cast<mirror::ClassLoader*>(this); +} + template <const bool kVisitClass, VerifyObjectFlags kVerifyFlags, typename Visitor, typename JavaLangRefVisitor> inline void Object::VisitReferences(const Visitor& visitor, @@ -1010,6 +1023,9 @@ inline void Object::VisitReferences(const Visitor& visitor, } else if (kVisitClass) { visitor(this, ClassOffset(), false); } + } else if (klass->IsClassLoaderClass()) { + mirror::ClassLoader* class_loader = AsClassLoader<kVerifyFlags>(); + class_loader->VisitReferences<kVisitClass, kVerifyFlags>(klass, visitor); } else { DCHECK(!klass->IsVariableSize()); VisitInstanceFieldsReferences<kVisitClass>(klass, visitor); diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index eea9f3751e..4967a14a39 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -37,6 +37,7 @@ namespace mirror { class Array; class Class; +class ClassLoader; class FinalizerReference; template<class T> class ObjectArray; template<class T> class PrimitiveArray; @@ -156,6 +157,11 @@ class MANAGED LOCKABLE Object { template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ObjectArray<T>* AsObjectArray() SHARED_REQUIRES(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + bool IsClassLoader() SHARED_REQUIRES(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> + ClassLoader* AsClassLoader() SHARED_REQUIRES(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> bool IsArrayInstance() SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/modifiers.h b/runtime/modifiers.h index 8586dd196b..8b363a686f 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -55,6 +55,9 @@ static constexpr uint32_t kAccDontInline = 0x00400000; // method (dex // 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 |