diff options
| -rw-r--r-- | runtime/base/mutex.h | 1 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 86 | ||||
| -rw-r--r-- | runtime/class_linker.h | 23 | ||||
| -rw-r--r-- | runtime/mirror/dex_cache_test.cc | 14 |
4 files changed, 89 insertions, 35 deletions
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 91e31d8d0d..b3ff6c20bc 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -89,6 +89,7 @@ enum LockLevel { kDeoptimizedMethodsLock, kClassLoaderClassesLock, kDefaultMutexLevel, + kDexLock, kMarkSweepLargeObjectLock, kPinTableLock, kJdwpObjectRegistryLock, diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index d67e1118bb..bd04bfa40c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -315,7 +315,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", kDefaultMutexLevel), + : dex_lock_("ClassLinker dex lock", kDexLock), dex_cache_boot_image_class_lookup_required_(false), failed_dex_cache_class_lookups_(0), class_roots_(nullptr), @@ -2107,28 +2107,22 @@ mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length : static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length))); } -mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, - const DexFile& dex_file, - LinearAlloc* linear_alloc) { - StackHandleScope<6> hs(self); - auto dex_cache(hs.NewHandle(down_cast<mirror::DexCache*>( - GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); - if (dex_cache.Get() == nullptr) { - self->AssertPendingOOMException(); - return nullptr; - } - auto location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str()))); - if (location.Get() == nullptr) { - self->AssertPendingOOMException(); - return nullptr; - } +void ClassLinker::InitializeDexCache(Thread* self, + mirror::DexCache* dex_cache, + 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; - if (dex_file.GetOatDexFile() != nullptr && - dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) { - raw_arrays = dex_file.GetOatDexFile()->GetDexCacheArrays(); - } else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u || - dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) { + + 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())); } @@ -2185,7 +2179,7 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull()); } for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) { - CHECK(types[i].Read<kWithoutReadBarrier>() == nullptr); + CHECK(types[i].IsNull()); } for (size_t i = 0; i < dex_file.NumMethodIds(); ++i) { CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size_) == nullptr); @@ -2205,7 +2199,7 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, mirror::MethodTypeDexCachePair::Initialize(method_types); } dex_cache->Init(&dex_file, - location.Get(), + location, strings, num_strings, types, @@ -2217,9 +2211,41 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, method_types, num_method_types, image_pointer_size_); +} + +mirror::DexCache* ClassLinker::AllocDexCache(mirror::String** out_location, + Thread* self, + const DexFile& dex_file) { + StackHandleScope<1> hs(self); + DCHECK(out_location != nullptr); + auto dex_cache(hs.NewHandle(down_cast<mirror::DexCache*>( + GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); + if (dex_cache.Get() == nullptr) { + self->AssertPendingOOMException(); + return nullptr; + } + mirror::String* location = intern_table_->InternStrong(dex_file.GetLocation().c_str()); + if (location == nullptr) { + self->AssertPendingOOMException(); + return nullptr; + } + *out_location = location; return dex_cache.Get(); } +mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, + const DexFile& dex_file, + LinearAlloc* linear_alloc) { + mirror::String* location = nullptr; + mirror::DexCache* dex_cache = AllocDexCache(&location, self, dex_file); + if (dex_cache != nullptr) { + WriterMutexLock mu(self, dex_lock_); + DCHECK(location != nullptr); + InitializeDexCache(self, dex_cache, location, dex_file, linear_alloc); + } + return dex_cache; +} + mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class, uint32_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); @@ -3292,7 +3318,7 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) { StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache( + Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocAndInitializeDexCache( self, dex_file, Runtime::Current()->GetLinearAlloc()))); @@ -3369,8 +3395,12 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, // Don't alloc while holding the lock, since allocation may need to // suspend all threads and another thread may need the dex_lock_ to // get to a suspend point. - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc))); + StackHandleScope<2> hs(self); + mirror::String* location; + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(/*out*/&location, + self, + dex_file))); + Handle<mirror::String> h_location(hs.NewHandle(location)); { WriterMutexLock mu(self, dex_lock_); mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true); @@ -3381,6 +3411,10 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, self->AssertPendingOOMException(); return nullptr; } + // 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); RegisterDexFileLocked(dex_file, h_dex_cache); } table->InsertStrongRoot(h_dex_cache.Get()); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index f69a5767e2..d2eeaabef7 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -735,12 +735,29 @@ class ClassLinker { mirror::Class* AllocClass(Thread* self, uint32_t class_size) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::DexCache* AllocDexCache(Thread* self, - const DexFile& dex_file, - LinearAlloc* linear_alloc) + + mirror::DexCache* AllocDexCache(mirror::String** out_location, + Thread* self, + const DexFile& dex_file) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); + + // Used for tests and AppendToBootClassPath. + mirror::DexCache* AllocAndInitializeDexCache(Thread* self, + const DexFile& dex_file, + LinearAlloc* linear_alloc) REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!dex_lock_) REQUIRES(!Roles::uninterruptible_); + void InitializeDexCache(Thread* self, + mirror::DexCache* dex_cache, + 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_); diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 12301b8809..e95ca210f6 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -44,9 +44,10 @@ TEST_F(DexCacheTest, Open) { StackHandleScope<1> hs(soa.Self()); ASSERT_TRUE(java_lang_dex_file_ != nullptr); Handle<DexCache> dex_cache( - hs.NewHandle(class_linker_->AllocDexCache(soa.Self(), - *java_lang_dex_file_, - Runtime::Current()->GetLinearAlloc()))); + hs.NewHandle(class_linker_->AllocAndInitializeDexCache( + soa.Self(), + *java_lang_dex_file_, + Runtime::Current()->GetLinearAlloc()))); ASSERT_TRUE(dex_cache.Get() != nullptr); EXPECT_TRUE(dex_cache->StaticStringSize() == dex_cache->NumStrings() @@ -64,9 +65,10 @@ TEST_F(DexCacheMethodHandlesTest, Open) { StackHandleScope<1> hs(soa.Self()); ASSERT_TRUE(java_lang_dex_file_ != nullptr); Handle<DexCache> dex_cache( - hs.NewHandle(class_linker_->AllocDexCache(soa.Self(), - *java_lang_dex_file_, - Runtime::Current()->GetLinearAlloc()))); + hs.NewHandle(class_linker_->AllocAndInitializeDexCache( + soa.Self(), + *java_lang_dex_file_, + Runtime::Current()->GetLinearAlloc()))); EXPECT_TRUE(dex_cache->StaticMethodTypeSize() == dex_cache->NumResolvedMethodTypes() || java_lang_dex_file_->NumProtoIds() == dex_cache->NumResolvedMethodTypes()); |