diff options
| author | 2016-12-03 01:20:05 +0000 | |
|---|---|---|
| committer | 2016-12-03 01:20:06 +0000 | |
| commit | 0480523e01102e40a072d266e43a18a0ca4344e4 (patch) | |
| tree | 3d38b5a98764fd99d6c5de1a6e9c9509168baef4 | |
| parent | b487af4fc80ffabe0219657a9690be1316dab8e7 (diff) | |
| parent | cc1b5357f83f0b787d51fbfde3fe870c8a2fa050 (diff) | |
Merge "ART: Clean up ClassLinker"
| -rw-r--r-- | compiler/image_writer.cc | 8 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 2 | ||||
| -rw-r--r-- | runtime/base/mutex.cc | 6 | ||||
| -rw-r--r-- | runtime/base/mutex.h | 4 | ||||
| -rw-r--r-- | runtime/class_linker-inl.h | 2 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 232 | ||||
| -rw-r--r-- | runtime/class_linker.h | 141 | ||||
| -rw-r--r-- | runtime/class_linker_test.cc | 4 | ||||
| -rw-r--r-- | runtime/mirror/dex_cache.cc | 108 | ||||
| -rw-r--r-- | runtime/mirror/dex_cache.h | 38 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 16 | ||||
| -rw-r--r-- | runtime/runtime.cc | 21 |
12 files changed, 284 insertions, 298 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index fb5560b124..7bb2bb71a9 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -433,7 +433,7 @@ void ImageWriter::PrepareDexCacheArraySlots() { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Thread* const self = Thread::Current(); - ReaderMutexLock mu(self, *class_linker->DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { ObjPtr<mirror::DexCache> dex_cache = ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); @@ -884,7 +884,7 @@ void ImageWriter::PruneNonImageClasses() { ScopedAssertNoThreadSuspension sa(__FUNCTION__); ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // For ClassInClassTable - ReaderMutexLock mu2(self, *class_linker->DexLock()); + ReaderMutexLock mu2(self, *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { if (self->IsJWeakCleared(data.weak_root)) { continue; @@ -1013,7 +1013,7 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { // caches. We check that the number of dex caches does not change. size_t dex_cache_count = 0; { - ReaderMutexLock mu(self, *class_linker->DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); // Count number of dex caches not in the boot image. for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { ObjPtr<mirror::DexCache> dex_cache = @@ -1031,7 +1031,7 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(), dex_cache_count))); CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array."; { - ReaderMutexLock mu(self, *class_linker->DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); size_t non_image_dex_caches = 0; // Re-count number of non image dex caches. for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 692a951c97..80c7113175 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1604,7 +1604,7 @@ class ImageDumper { // Mark dex caches. dex_caches_.clear(); { - ReaderMutexLock mu(self, *class_linker->DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { ObjPtr<mirror::DexCache> dex_cache = ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 6665f95bba..ce452cbcf6 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -67,6 +67,7 @@ Mutex* Locks::unexpected_signal_lock_ = nullptr; Uninterruptible Roles::uninterruptible_; ReaderWriterMutex* Locks::jni_globals_lock_ = nullptr; Mutex* Locks::jni_weak_globals_lock_ = nullptr; +ReaderWriterMutex* Locks::dex_lock_ = nullptr; struct AllMutexData { // A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait). @@ -961,6 +962,7 @@ void Locks::Init() { DCHECK(thread_suspend_count_lock_ != nullptr); DCHECK(trace_lock_ != nullptr); DCHECK(unexpected_signal_lock_ != nullptr); + DCHECK(dex_lock_ != nullptr); } else { // Create global locks in level order from highest lock level to lowest. LockLevel current_lock_level = kInstrumentEntrypointsLock; @@ -1039,6 +1041,10 @@ void Locks::Init() { modify_ldt_lock_ = new Mutex("modify_ldt lock", current_lock_level); } + UPDATE_CURRENT_LOCK_LEVEL(kDexLock); + DCHECK(dex_lock_ == nullptr); + dex_lock_ = new ReaderWriterMutex("ClassLinker dex lock", current_lock_level); + UPDATE_CURRENT_LOCK_LEVEL(kOatFileManagerLock); DCHECK(oat_file_manager_lock_ == nullptr); oat_file_manager_lock_ = new ReaderWriterMutex("OatFile manager lock", current_lock_level); diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 21b5bb926f..255ad714f2 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -659,8 +659,10 @@ class Locks { // Guards modification of the LDT on x86. static Mutex* modify_ldt_lock_ ACQUIRED_AFTER(allocated_thread_ids_lock_); + static ReaderWriterMutex* dex_lock_ ACQUIRED_AFTER(modify_ldt_lock_); + // Guards opened oat files in OatFileManager. - static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_); + static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(dex_lock_); // Guards extra string entries for VerifierDeps. static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_); diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 7005c292c8..0a65cd11aa 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -248,7 +248,7 @@ ArtMethod* ClassLinker::FindMethodForProxy(ObjPtr<mirror::Class> proxy_class, DCHECK(proxy_method->IsProxyMethod<kReadBarrierOption>()); { Thread* const self = Thread::Current(); - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); // Locate the dex cache of the original interface/Object for (const DexCacheData& data : dex_caches_) { if (!self->IsJWeakCleared(data.weak_root) && diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index e9f5978e97..992d4bfd0c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -341,9 +341,7 @@ static void ShuffleForward(size_t* current_field_idx, } ClassLinker::ClassLinker(InternTable* intern_table) - // dex_lock_ is recursive as it may be used in stack dumping. - : dex_lock_("ClassLinker dex lock", kDexLock), - failed_dex_cache_class_lookups_(0), + : failed_dex_cache_class_lookups_(0), class_roots_(nullptr), array_iftable_(nullptr), find_array_class_cache_next_victim_(0), @@ -1329,7 +1327,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } } { - WriterMutexLock mu2(self, dex_lock_); + WriterMutexLock mu2(self, *Locks::dex_lock_); // Make sure to do this after we update the arrays since we store the resolved types array // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the // BSS. @@ -2144,109 +2142,6 @@ mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length : static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length))); } -void ClassLinker::InitializeDexCache(Thread* self, - ObjPtr<mirror::DexCache> dex_cache, - ObjPtr<mirror::String> location, - const DexFile& dex_file, - LinearAlloc* linear_alloc) { - ScopedAssertNoThreadSuspension sants(__FUNCTION__); - DexCacheArraysLayout layout(image_pointer_size_, &dex_file); - uint8_t* raw_arrays = nullptr; - - const OatDexFile* const oat_dex = dex_file.GetOatDexFile(); - if (oat_dex != nullptr && oat_dex->GetDexCacheArrays() != nullptr) { - raw_arrays = oat_dex->GetDexCacheArrays(); - } else if (dex_file.NumStringIds() != 0u || - dex_file.NumTypeIds() != 0u || - dex_file.NumMethodIds() != 0u || - dex_file.NumFieldIds() != 0u) { - // Zero-initialized. - raw_arrays = reinterpret_cast<uint8_t*>(linear_alloc->Alloc(self, layout.Size())); - } - - mirror::StringDexCacheType* strings = (dex_file.NumStringIds() == 0u) ? nullptr : - reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); - GcRoot<mirror::Class>* types = (dex_file.NumTypeIds() == 0u) ? nullptr : - reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); - ArtMethod** methods = (dex_file.NumMethodIds() == 0u) ? nullptr : - reinterpret_cast<ArtMethod**>(raw_arrays + layout.MethodsOffset()); - ArtField** fields = (dex_file.NumFieldIds() == 0u) ? nullptr : - reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset()); - - size_t num_strings = mirror::DexCache::kDexCacheStringCacheSize; - if (dex_file.NumStringIds() < num_strings) { - num_strings = dex_file.NumStringIds(); - } - - // Note that we allocate the method type dex caches regardless of this flag, - // and we make sure here that they're not used by the runtime. This is in the - // interest of simplicity and to avoid extensive compiler and layout class changes. - // - // If this needs to be mitigated in a production system running this code, - // DexCache::kDexCacheMethodTypeCacheSize can be set to zero. - mirror::MethodTypeDexCacheType* method_types = nullptr; - size_t num_method_types = 0; - - if (dex_file.NumProtoIds() < mirror::DexCache::kDexCacheMethodTypeCacheSize) { - num_method_types = dex_file.NumProtoIds(); - } else { - num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; - } - - if (num_method_types > 0) { - method_types = reinterpret_cast<mirror::MethodTypeDexCacheType*>( - raw_arrays + layout.MethodTypesOffset()); - } - - DCHECK_ALIGNED(raw_arrays, alignof(mirror::StringDexCacheType)) << - "Expected raw_arrays to align to StringDexCacheType."; - DCHECK_ALIGNED(layout.StringsOffset(), alignof(mirror::StringDexCacheType)) << - "Expected StringsOffset() to align to StringDexCacheType."; - DCHECK_ALIGNED(strings, alignof(mirror::StringDexCacheType)) << - "Expected strings to align to StringDexCacheType."; - static_assert(alignof(mirror::StringDexCacheType) == 8u, - "Expected StringDexCacheType to have align of 8."); - if (kIsDebugBuild) { - // Sanity check to make sure all the dex cache arrays are empty. b/28992179 - for (size_t i = 0; i < num_strings; ++i) { - CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u); - CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull()); - } - for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) { - CHECK(types[i].IsNull()); - } - for (size_t i = 0; i < dex_file.NumMethodIds(); ++i) { - CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size_) == nullptr); - } - for (size_t i = 0; i < dex_file.NumFieldIds(); ++i) { - CHECK(mirror::DexCache::GetElementPtrSize(fields, i, image_pointer_size_) == nullptr); - } - for (size_t i = 0; i < num_method_types; ++i) { - CHECK_EQ(method_types[i].load(std::memory_order_relaxed).index, 0u); - CHECK(method_types[i].load(std::memory_order_relaxed).object.IsNull()); - } - } - if (strings != nullptr) { - mirror::StringDexCachePair::Initialize(strings); - } - if (method_types != nullptr) { - mirror::MethodTypeDexCachePair::Initialize(method_types); - } - dex_cache->Init(&dex_file, - location, - strings, - num_strings, - types, - dex_file.NumTypeIds(), - methods, - dex_file.NumMethodIds(), - fields, - dex_file.NumFieldIds(), - method_types, - num_method_types, - image_pointer_size_); -} - mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr<mirror::String>* out_location, Thread* self, const DexFile& dex_file) { @@ -2273,9 +2168,14 @@ mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, ObjPtr<mirror::String> location = nullptr; ObjPtr<mirror::DexCache> dex_cache = AllocDexCache(&location, self, dex_file); if (dex_cache != nullptr) { - WriterMutexLock mu(self, dex_lock_); + WriterMutexLock mu(self, *Locks::dex_lock_); DCHECK(location != nullptr); - InitializeDexCache(self, dex_cache, location, dex_file, linear_alloc); + mirror::DexCache::InitializeDexCache(self, + dex_cache, + location, + &dex_file, + linear_alloc, + image_pointer_size_); } return dex_cache.Ptr(); } @@ -3295,7 +3195,7 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) { Thread* const self = Thread::Current(); - dex_lock_.AssertExclusiveHeld(self); + Locks::dex_lock_->AssertExclusiveHeld(self); CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); // For app images, the dex cache location may be a suffix of the dex file location since the // dex file location is an absolute path. @@ -3337,7 +3237,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader) { Thread* self = Thread::Current(); { - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { return dex_cache.Ptr(); @@ -3360,7 +3260,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, dex_file))); Handle<mirror::String> h_location(hs.NewHandle(location)); { - WriterMutexLock mu(self, dex_lock_); + WriterMutexLock mu(self, *Locks::dex_lock_); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { // Another thread managed to initialize the dex cache faster, so use that DexCache. @@ -3376,7 +3276,12 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, // Do InitializeDexCache while holding dex lock to make sure two threads don't call it at the // same time with the same dex cache. Since the .bss is shared this can cause failing DCHECK // that the arrays are null. - InitializeDexCache(self, h_dex_cache.Get(), h_location.Get(), dex_file, linear_alloc); + mirror::DexCache::InitializeDexCache(self, + h_dex_cache.Get(), + h_location.Get(), + &dex_file, + linear_alloc, + image_pointer_size_); RegisterDexFileLocked(dex_file, h_dex_cache); } table->InsertStrongRoot(h_dex_cache.Get()); @@ -3385,14 +3290,14 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, void ClassLinker::RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) { - WriterMutexLock mu(Thread::Current(), dex_lock_); + WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_); RegisterDexFileLocked(dex_file, dex_cache); } mirror::DexCache* ClassLinker::FindDexCache(Thread* self, const DexFile& dex_file, bool allow_failure) { - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); return FindDexCacheLocked(self, dex_file, allow_failure); } @@ -3429,7 +3334,7 @@ mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { Thread* const self = Thread::Current(); - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const DexCacheData& data : dex_caches_) { if (!self->IsJWeakCleared(data.weak_root)) { ObjPtr<mirror::DexCache> dex_cache = ObjPtr<mirror::DexCache>::DownCast( @@ -3824,6 +3729,17 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, return false; } +// Ensures that methods have the kAccSkipAccessChecks bit set. We use the +// kAccVerificationAttempted bit on the class access flags to determine whether this has been done +// before. +static void EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass, PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (!klass->WasVerificationAttempted()) { + klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size); + klass->SetVerificationAttempted(); + } +} + verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( Thread* self, Handle<mirror::Class> klass, verifier::HardFailLogMode log_level) { { @@ -3851,7 +3767,7 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Don't attempt to re-verify if already sufficiently verified. if (klass->IsVerified()) { - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); return verifier::MethodVerifier::kNoFailure; } if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { @@ -3870,7 +3786,7 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); return verifier::MethodVerifier::kNoFailure; } } @@ -4005,19 +3921,12 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Mark the class as having a verification attempt to avoid re-running the verifier. klass->SetVerificationAttempted(); } else { - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); } } return verifier_failure; } -void ClassLinker::EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass) { - if (!klass->WasVerificationAttempted()) { - klass->SetSkipAccessChecksFlagOnAllMethods(image_pointer_size_); - klass->SetVerificationAttempted(); - } -} - bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, ObjPtr<mirror::Class> klass, mirror::Class::Status& oat_file_class_status) { @@ -4987,7 +4896,7 @@ bool ClassLinker::EnsureInitialized(Thread* self, bool can_init_parents) { DCHECK(c.Get() != nullptr); if (c->IsInitialized()) { - EnsureSkipAccessChecksMethods(c); + EnsureSkipAccessChecksMethods(c, image_pointer_size_); self->AssertNoPendingException(); return true; } @@ -8010,42 +7919,6 @@ mirror::MethodType* ClassLinker::ResolveMethodType(const DexFile& dex_file, return type.Get(); } -const char* ClassLinker::MethodShorty(uint32_t method_idx, - ArtMethod* referrer, - uint32_t* length) { - ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass(); - ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache(); - const DexFile& dex_file = *dex_cache->GetDexFile(); - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - return dex_file.GetMethodShorty(method_id, length); -} - -class DumpClassVisitor : public ClassVisitor { - public: - explicit DumpClassVisitor(int flags) : flags_(flags) {} - - bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - klass->DumpClass(LOG_STREAM(ERROR), flags_); - return true; - } - - private: - const int flags_; -}; - -void ClassLinker::DumpAllClasses(int flags) { - DumpClassVisitor visitor(flags); - VisitClasses(&visitor); -} - -static OatFile::OatMethod CreateOatMethod(const void* code) { - CHECK(code != nullptr); - const uint8_t* base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code. - base -= sizeof(void*); // Move backward so that code_offset != 0. - const uint32_t code_offset = sizeof(void*); - return OatFile::OatMethod(base, code_offset); -} - bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const { return (entry_point == GetQuickResolutionStub()) || (quick_resolution_trampoline_ == entry_point); @@ -8065,9 +7938,12 @@ const void* ClassLinker::GetRuntimeQuickGenericJniStub() const { return GetQuickGenericJniStub(); } -void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, - const void* method_code) const { - OatFile::OatMethod oat_method = CreateOatMethod(method_code); +void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, const void* code) const { + CHECK(code != nullptr); + const uint8_t* base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code. + base -= sizeof(void*); // Move backward so that code_offset != 0. + const uint32_t code_offset = sizeof(void*); + OatFile::OatMethod oat_method(base, code_offset); oat_method.LinkMethod(method); } @@ -8075,9 +7951,7 @@ void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const { if (!method->IsNative()) { method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); } else { - const void* quick_method_code = GetQuickGenericJniStub(); - OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code); - oat_method.LinkMethod(method); + SetEntryPointsToCompiledCode(method, GetQuickGenericJniStub()); } } @@ -8128,7 +8002,7 @@ pid_t ClassLinker::GetClassesLockOwner() { } pid_t ClassLinker::GetDexLockOwner() { - return dex_lock_.GetExclusiveOwnerTid(); + return Locks::dex_lock_->GetExclusiveOwnerTid(); } void ClassLinker::SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass) { @@ -8294,20 +8168,6 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, return soa.Env()->NewGlobalRef(local_ref.get()); } -ArtMethod* ClassLinker::CreateRuntimeMethod(LinearAlloc* linear_alloc) { - const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); - const size_t method_size = ArtMethod::Size(image_pointer_size_); - LengthPrefixedArray<ArtMethod>* method_array = AllocArtMethodArray( - Thread::Current(), - linear_alloc, - 1); - ArtMethod* method = &method_array->At(0, method_size, method_alignment); - CHECK(method != nullptr); - method->SetDexMethodIndex(DexFile::kDexNoIndex); - CHECK(method->IsRuntimeMethod()); - return method; -} - void ClassLinker::DropFindArrayClassCache() { std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot<mirror::Class>(nullptr)); find_array_class_cache_next_victim_ = 0; @@ -8381,7 +8241,7 @@ std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_bo std::set<DexCacheResolvedClasses> ret; VLOG(class_linker) << "Collecting resolved classes"; const uint64_t start_time = NanoTime(); - ReaderMutexLock mu(soa.Self(), *DexLock()); + ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_); // Loop through all the dex caches and inspect resolved classes. for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (soa.Self()->IsJWeakCleared(data.weak_root)) { @@ -8450,7 +8310,7 @@ std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys( std::unordered_map<std::string, const DexFile*> location_to_dex_file; ScopedObjectAccess soa(self); ScopedAssertNoThreadSuspension ants(__FUNCTION__); - ReaderMutexLock mu(self, *DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (!self->IsJWeakCleared(data.weak_root)) { ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 60755cdea6..de1f0f09be 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -140,12 +140,12 @@ class ClassLinker { bool InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Initialize class linker from one or more boot images. bool InitFromBootImage(std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Add an image space to the class linker, may fix up classloader fields and dex cache fields. // The dex files that were newly opened for the space are placed in the out argument @@ -158,13 +158,13 @@ class ClassLinker { const char* dex_location, std::vector<std::unique_ptr<const DexFile>>* out_dex_files, std::string* error_msg) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); bool OpenImageDexFiles(gc::space::ImageSpace* space, std::vector<std::unique_ptr<const DexFile>>* out_dex_files, std::string* error_msg) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Finds a class by its descriptor, loading it if necessary. @@ -173,18 +173,18 @@ class ClassLinker { const char* descriptor, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Finds a class by its descriptor using the "system" class loader, ie by searching the // boot_class_path_. mirror::Class* FindSystemClass(Thread* self, const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Finds the array class given for the element class. mirror::Class* FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Returns true if the class linker is initialized. bool IsInitialized() const { @@ -199,7 +199,7 @@ class ClassLinker { const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Finds a class by its descriptor, returning null if it isn't wasn't loaded // by the given 'class_loader'. @@ -224,10 +224,6 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - void DumpAllClasses(int flags) - REQUIRES(!Locks::classlinker_classes_lock_) - REQUIRES_SHARED(Locks::mutator_lock_); - void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_); size_t NumLoadedClasses() @@ -261,18 +257,18 @@ class ClassLinker { dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Resolve a Type with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the // target DexCache and ClassLoader to use for resolution. mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search // for the type, since it may be referenced from but not contained within the given DexFile. @@ -291,7 +287,7 @@ class ClassLinker { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError // check should be performed even after a hit. @@ -313,7 +309,7 @@ class ClassLinker { ArtMethod* referrer, InvokeType type) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_); @@ -325,17 +321,17 @@ class ClassLinker { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); template <ResolveMode kResolveMode> ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); ArtMethod* ResolveMethodWithoutInvokeType(const DexFile& dex_file, uint32_t method_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); ArtField* GetResolvedField(uint32_t field_idx, ObjPtr<mirror::Class> field_declaring_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -343,7 +339,7 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_); ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Resolve a field with a given ID from the DexFile, storing the // result in DexCache. The ClassLinker and ClassLoader are used as @@ -354,7 +350,7 @@ class ClassLinker { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, bool is_static) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Resolve a field with a given ID from the DexFile, storing the // result in DexCache. The ClassLinker and ClassLoader are used as @@ -365,7 +361,7 @@ class ClassLinker { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Resolve a method type with a given ID from the DexFile, storing // the result in the DexCache. @@ -374,11 +370,7 @@ class ClassLinker { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); - - // Get shorty from method index without resolution. Used to do handlerization. - const char* MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Returns true on success, false if there's an exception pending. // can_run_clinit=false allows the compiler to attempt to init a class, @@ -388,20 +380,20 @@ class ClassLinker { bool can_init_fields, bool can_init_parents) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // Initializes classes that have instances in the image but that have // <clinit> methods so they could not be initialized by the compiler. void RunRootClinits() REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); mirror::DexCache* RegisterDexFile(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); const std::vector<const DexFile*>& GetBootClassPath() { @@ -418,22 +410,22 @@ class ClassLinker { // can race with insertion and deletion of classes while the visitor is being called. void VisitClassesWithoutClassesLock(ClassVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); void VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) REQUIRES(!Locks::classlinker_classes_lock_, !Locks::trace_lock_) REQUIRES_SHARED(Locks::mutator_lock_); void VisitRoots(RootVisitor* visitor, VisitRootFlags flags) - REQUIRES(!dex_lock_, !Locks::classlinker_classes_lock_, !Locks::trace_lock_) + REQUIRES(!Locks::dex_lock_, !Locks::classlinker_classes_lock_, !Locks::trace_lock_) REQUIRES_SHARED(Locks::mutator_lock_); mirror::DexCache* FindDexCache(Thread* self, const DexFile& dex_file, bool allow_failure = false) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); void FixupDexCaches(ArtMethod* resolution_method) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Allocate an instance of a java.lang.Object. @@ -481,18 +473,18 @@ class ClassLinker { Handle<mirror::Class> klass, verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); bool VerifyClassUsingOatFile(const DexFile& dex_file, ObjPtr<mirror::Class> klass, mirror::Class::Status& oat_file_class_status) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); void ResolveMethodExceptionHandlerTypes(ArtMethod* klass) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, @@ -505,7 +497,7 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_); template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ArtMethod* FindMethodForProxy(ObjPtr<mirror::Class> proxy_class, ArtMethod* proxy_method) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Get the oat code for a method when its class isn't yet initialized. @@ -568,7 +560,7 @@ class ClassLinker { // Note: the objects are not completely set up. Do not use this outside of tests and the compiler. jobject CreatePathClassLoader(Thread* self, const std::vector<const DexFile*>& dex_files) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); PointerSize GetImagePointerSize() const { return image_pointer_size_; @@ -579,8 +571,6 @@ class ClassLinker { REQUIRES(Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - ArtMethod* CreateRuntimeMethod(LinearAlloc* linear_alloc); - // Clear the ArrayClass cache. This is necessary when cleaning up for the image, as the cache // entries are roots, but potentially not image classes. void DropFindArrayClassCache() REQUIRES_SHARED(Locks::mutator_lock_); @@ -611,11 +601,11 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_); std::set<DexCacheResolvedClasses> GetResolvedClasses(bool ignore_boot_classes) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); std::unordered_set<std::string> GetClassDescriptorsForProfileKeys( const std::set<DexCacheResolvedClasses>& classes) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, ObjPtr<mirror::ClassLoader> class_loader) @@ -650,7 +640,7 @@ class ClassLinker { // class. void ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def = false) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Get the actual holding class for a copied method. Pretty slow, don't call often. mirror::Class* GetHoldingClassOfCopiedMethod(ArtMethod* method) @@ -680,7 +670,7 @@ class ClassLinker { bool AttemptSupertypeVerification(Thread* self, Handle<mirror::Class> klass, Handle<mirror::Class> supertype) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); static void DeleteClassLoader(Thread* self, const ClassLoaderData& data) @@ -704,7 +694,7 @@ class ClassLinker { void FinishInit(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); // For early bootstrapping by Init mirror::Class* AllocClass(Thread* self, @@ -731,17 +721,9 @@ class ClassLinker { const DexFile& dex_file, LinearAlloc* linear_alloc) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES(!Roles::uninterruptible_); - void InitializeDexCache(Thread* self, - ObjPtr<mirror::DexCache> dex_cache, - ObjPtr<mirror::String> location, - const DexFile& dex_file, - LinearAlloc* linear_alloc) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(dex_lock_); - mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -755,14 +737,14 @@ class ClassLinker { size_t hash, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_, !Roles::uninterruptible_); + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); void AppendToBootClassPath(Thread* self, const DexFile& dex_file) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Precomputes size needed for Class, in the case of a non-temporary class this size must be // sufficient to hold all static fields. @@ -810,7 +792,7 @@ class ClassLinker { Handle<mirror::ClassLoader> class_loader, ObjPtr<mirror::Class>* result) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded // by the given 'class_loader'. Uses the provided hash for the descriptor. @@ -822,10 +804,10 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_); void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) - REQUIRES(dex_lock_) + REQUIRES(Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); mirror::DexCache* FindDexCacheLocked(Thread* self, const DexFile& dex_file, bool allow_failure) - REQUIRES(dex_lock_) + REQUIRES(Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); bool InitializeClass(Thread* self, @@ -833,12 +815,12 @@ class ClassLinker { bool can_run_clinit, bool can_init_parents) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); bool InitializeDefaultInterfaceRecursive(Thread* self, Handle<mirror::Class> klass, bool can_run_clinit, bool can_init_parents) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); bool WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self, @@ -871,7 +853,7 @@ class ClassLinker { bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); bool LinkMethods(Thread* self, Handle<mirror::Class> klass, @@ -1037,17 +1019,11 @@ class ClassLinker { void CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const REQUIRES_SHARED(Locks::mutator_lock_); - // For use by ImageWriter to find DexCaches for its roots - ReaderWriterMutex* DexLock() - REQUIRES_SHARED(Locks::mutator_lock_) - LOCK_RETURNED(dex_lock_) { - return &dex_lock_; - } - size_t GetDexCacheCount() REQUIRES_SHARED(Locks::mutator_lock_, dex_lock_) { + size_t GetDexCacheCount() REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) { return dex_caches_.size(); } const std::list<DexCacheData>& GetDexCachesData() - REQUIRES_SHARED(Locks::mutator_lock_, dex_lock_) { + REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) { return dex_caches_; } @@ -1056,12 +1032,6 @@ class ClassLinker { void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out) REQUIRES_SHARED(Locks::mutator_lock_); - // Ensures that methods have the kAccSkipAccessChecks bit set. We use the - // kAccVerificationAttempted bit on the class access flags to determine whether this has been done - // before. - void EnsureSkipAccessChecksMethods(Handle<mirror::Class> c) - REQUIRES_SHARED(Locks::mutator_lock_); - // Register a class loader and create its class table and allocator. Should not be called if // these are already created. void RegisterClassLoader(ObjPtr<mirror::ClassLoader> class_loader) @@ -1086,7 +1056,7 @@ class ClassLinker { mirror::Class* EnsureResolved(Thread* self, const char* descriptor, ObjPtr<mirror::Class> klass) WARN_UNUSED REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!dex_lock_); + REQUIRES(!Locks::dex_lock_); void FixupTemporaryDeclaringClass(ObjPtr<mirror::Class> temp_class, ObjPtr<mirror::Class> new_class) @@ -1117,12 +1087,12 @@ class ClassLinker { ClassTable::ClassSet* new_class_set, bool* out_forward_dex_cache_array, std::string* out_error_msg) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Check that c1 == FindSystemClass(self, descriptor). Abort with class dumps otherwise. void CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor) - REQUIRES(!dex_lock_) + REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Sets imt_ref appropriately for LinkInterfaceMethods. @@ -1153,10 +1123,9 @@ class ClassLinker { std::vector<const DexFile*> boot_class_path_; std::vector<std::unique_ptr<const DexFile>> boot_dex_files_; - mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; // JNI weak globals and side data to allow dex caches to get unloaded. We lazily delete weak // globals when we register new dex files. - std::list<DexCacheData> dex_caches_ GUARDED_BY(dex_lock_); + std::list<DexCacheData> dex_caches_ GUARDED_BY(Locks::dex_lock_); // This contains the class loaders which have class tables. It is populated by // InsertClassTableForClassLoader. diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 7c06ffedb8..ddb9e590a7 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1319,7 +1319,7 @@ TEST_F(ClassLinkerTest, RegisterDexFileName) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr)); { - ReaderMutexLock mu(soa.Self(), *class_linker->DexLock()); + ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { dex_cache.Assign(soa.Self()->DecodeJObject(data.weak_root)->AsDexCache()); if (dex_cache.Get() != nullptr) { @@ -1343,7 +1343,7 @@ TEST_F(ClassLinkerTest, RegisterDexFileName) { 0u, nullptr)); { - WriterMutexLock mu(soa.Self(), *class_linker->DexLock()); + WriterMutexLock mu(soa.Self(), *Locks::dex_lock_); // Check that inserting with a UTF16 name works. class_linker->RegisterDexFileLocked(*dex_file, dex_cache); } diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index a32d51fbef..741cf3bb47 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -22,15 +22,123 @@ #include "gc/accounting/card_table-inl.h" #include "gc/heap.h" #include "globals.h" +#include "linear_alloc.h" #include "object.h" #include "object-inl.h" #include "object_array-inl.h" #include "runtime.h" #include "string.h" +#include "thread.h" +#include "utils/dex_cache_arrays_layout-inl.h" namespace art { namespace mirror { +void DexCache::InitializeDexCache(Thread* self, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::String> location, + const DexFile* dex_file, + LinearAlloc* linear_alloc, + PointerSize image_pointer_size) { + DCHECK(dex_file != nullptr); + ScopedAssertNoThreadSuspension sants(__FUNCTION__); + DexCacheArraysLayout layout(image_pointer_size, dex_file); + uint8_t* raw_arrays = nullptr; + + const OatDexFile* const oat_dex = dex_file->GetOatDexFile(); + if (oat_dex != nullptr && oat_dex->GetDexCacheArrays() != nullptr) { + raw_arrays = oat_dex->GetDexCacheArrays(); + } else if (dex_file->NumStringIds() != 0u || + dex_file->NumTypeIds() != 0u || + dex_file->NumMethodIds() != 0u || + dex_file->NumFieldIds() != 0u) { + // Zero-initialized. + raw_arrays = reinterpret_cast<uint8_t*>(linear_alloc->Alloc(self, layout.Size())); + } + + mirror::StringDexCacheType* strings = (dex_file->NumStringIds() == 0u) ? nullptr : + reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); + GcRoot<mirror::Class>* types = (dex_file->NumTypeIds() == 0u) ? nullptr : + reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); + ArtMethod** methods = (dex_file->NumMethodIds() == 0u) ? nullptr : + reinterpret_cast<ArtMethod**>(raw_arrays + layout.MethodsOffset()); + ArtField** fields = (dex_file->NumFieldIds() == 0u) ? nullptr : + reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset()); + + size_t num_strings = mirror::DexCache::kDexCacheStringCacheSize; + if (dex_file->NumStringIds() < num_strings) { + num_strings = dex_file->NumStringIds(); + } + + // Note that we allocate the method type dex caches regardless of this flag, + // and we make sure here that they're not used by the runtime. This is in the + // interest of simplicity and to avoid extensive compiler and layout class changes. + // + // If this needs to be mitigated in a production system running this code, + // DexCache::kDexCacheMethodTypeCacheSize can be set to zero. + mirror::MethodTypeDexCacheType* method_types = nullptr; + size_t num_method_types = 0; + + if (dex_file->NumProtoIds() < mirror::DexCache::kDexCacheMethodTypeCacheSize) { + num_method_types = dex_file->NumProtoIds(); + } else { + num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; + } + + if (num_method_types > 0) { + method_types = reinterpret_cast<mirror::MethodTypeDexCacheType*>( + raw_arrays + layout.MethodTypesOffset()); + } + + DCHECK_ALIGNED(raw_arrays, alignof(mirror::StringDexCacheType)) << + "Expected raw_arrays to align to StringDexCacheType."; + DCHECK_ALIGNED(layout.StringsOffset(), alignof(mirror::StringDexCacheType)) << + "Expected StringsOffset() to align to StringDexCacheType."; + DCHECK_ALIGNED(strings, alignof(mirror::StringDexCacheType)) << + "Expected strings to align to StringDexCacheType."; + static_assert(alignof(mirror::StringDexCacheType) == 8u, + "Expected StringDexCacheType to have align of 8."); + if (kIsDebugBuild) { + // Sanity check to make sure all the dex cache arrays are empty. b/28992179 + for (size_t i = 0; i < num_strings; ++i) { + CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u); + CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull()); + } + for (size_t i = 0; i < dex_file->NumTypeIds(); ++i) { + CHECK(types[i].IsNull()); + } + for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) { + CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size) == nullptr); + } + for (size_t i = 0; i < dex_file->NumFieldIds(); ++i) { + CHECK(mirror::DexCache::GetElementPtrSize(fields, i, image_pointer_size) == nullptr); + } + for (size_t i = 0; i < num_method_types; ++i) { + CHECK_EQ(method_types[i].load(std::memory_order_relaxed).index, 0u); + CHECK(method_types[i].load(std::memory_order_relaxed).object.IsNull()); + } + } + if (strings != nullptr) { + mirror::StringDexCachePair::Initialize(strings); + } + if (method_types != nullptr) { + mirror::MethodTypeDexCachePair::Initialize(method_types); + } + dex_cache->Init(dex_file, + location, + strings, + num_strings, + types, + dex_file->NumTypeIds(), + methods, + dex_file->NumMethodIds(), + fields, + dex_file->NumFieldIds(), + method_types, + num_method_types, + image_pointer_size); +} + void DexCache::Init(const DexFile* dex_file, ObjPtr<String> location, StringDexCacheType* strings, diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index cc4d01a075..ec265e5ab3 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -31,6 +31,8 @@ struct DexCacheOffsets; class DexFile; class ImageWriter; union JValue; +class LinearAlloc; +class Thread; namespace mirror { @@ -137,19 +139,14 @@ class MANAGED DexCache FINAL : public Object { return sizeof(DexCache); } - void Init(const DexFile* dex_file, - ObjPtr<String> location, - StringDexCacheType* strings, - uint32_t num_strings, - GcRoot<Class>* resolved_types, - uint32_t num_resolved_types, - ArtMethod** resolved_methods, - uint32_t num_resolved_methods, - ArtField** resolved_fields, - uint32_t num_resolved_fields, - MethodTypeDexCacheType* resolved_methodtypes, - uint32_t num_resolved_methodtypes, - PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); + static void InitializeDexCache(Thread* self, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::String> location, + const DexFile* dex_file, + LinearAlloc* linear_alloc, + PointerSize image_pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(Locks::dex_lock_); void Fixup(ArtMethod* trampoline, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); @@ -339,6 +336,21 @@ class MANAGED DexCache FINAL : public Object { static void SetElementPtrSize(PtrType* ptr_array, size_t idx, PtrType ptr, PointerSize ptr_size); private: + void Init(const DexFile* dex_file, + ObjPtr<String> location, + StringDexCacheType* strings, + uint32_t num_strings, + GcRoot<Class>* resolved_types, + uint32_t num_resolved_types, + ArtMethod** resolved_methods, + uint32_t num_resolved_methods, + ArtField** resolved_fields, + uint32_t num_resolved_fields, + MethodTypeDexCacheType* resolved_methodtypes, + uint32_t num_resolved_methodtypes, + PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_); + // Visit instance fields of the dex cache as well as its associated arrays. template <bool kVisitNativeRoots, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index adf35b6f01..67b2e1c503 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -177,8 +177,22 @@ static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) { } static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) { + class DumpClassVisitor : public ClassVisitor { + public: + explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {} + + bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + klass->DumpClass(LOG_STREAM(ERROR), flags_); + return true; + } + + private: + const int flags_; + }; + DumpClassVisitor visitor(flags); + ScopedFastNativeObjectAccess soa(env); - return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags); + return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor); } static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 92e00ec155..66bb80315d 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1736,9 +1736,24 @@ void Runtime::VisitImageRoots(RootVisitor* visitor) { } } +static ArtMethod* CreateRuntimeMethod(ClassLinker* class_linker, LinearAlloc* linear_alloc) { + const PointerSize image_pointer_size = class_linker->GetImagePointerSize(); + const size_t method_alignment = ArtMethod::Alignment(image_pointer_size); + const size_t method_size = ArtMethod::Size(image_pointer_size); + LengthPrefixedArray<ArtMethod>* method_array = class_linker->AllocArtMethodArray( + Thread::Current(), + linear_alloc, + 1); + ArtMethod* method = &method_array->At(0, method_size, method_alignment); + CHECK(method != nullptr); + method->SetDexMethodIndex(DexFile::kDexNoIndex); + CHECK(method->IsRuntimeMethod()); + return method; +} + ArtMethod* Runtime::CreateImtConflictMethod(LinearAlloc* linear_alloc) { ClassLinker* const class_linker = GetClassLinker(); - ArtMethod* method = class_linker->CreateRuntimeMethod(linear_alloc); + ArtMethod* method = CreateRuntimeMethod(class_linker, linear_alloc); // When compiling, the code pointer will get set later when the image is loaded. const PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_); if (IsAotCompiler()) { @@ -1759,7 +1774,7 @@ void Runtime::SetImtConflictMethod(ArtMethod* method) { } ArtMethod* Runtime::CreateResolutionMethod() { - auto* method = GetClassLinker()->CreateRuntimeMethod(GetLinearAlloc()); + auto* method = CreateRuntimeMethod(GetClassLinker(), GetLinearAlloc()); // When compiling, the code pointer will get set later when the image is loaded. if (IsAotCompiler()) { PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_); @@ -1771,7 +1786,7 @@ ArtMethod* Runtime::CreateResolutionMethod() { } ArtMethod* Runtime::CreateCalleeSaveMethod() { - auto* method = GetClassLinker()->CreateRuntimeMethod(GetLinearAlloc()); + auto* method = CreateRuntimeMethod(GetClassLinker(), GetLinearAlloc()); PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_); method->SetEntryPointFromQuickCompiledCodePtrSize(nullptr, pointer_size); DCHECK_NE(instruction_set_, kNone); |