diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 305 |
1 files changed, 170 insertions, 135 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index edd6e3b522..9380588576 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1171,6 +1171,23 @@ static void CopyNonNull(const T* src, size_t count, T* dst, const NullPred& pred } } +template <typename T> +static void CopyDexCachePairs(const std::atomic<mirror::DexCachePair<T>>* src, + size_t count, + std::atomic<mirror::DexCachePair<T>>* dst) { + DCHECK_NE(count, 0u); + DCHECK(!src[0].load(std::memory_order_relaxed).object.IsNull() || + src[0].load(std::memory_order_relaxed).index != 0u); + for (size_t i = 0; i < count; ++i) { + DCHECK_EQ(dst[i].load(std::memory_order_relaxed).index, 0u); + DCHECK(dst[i].load(std::memory_order_relaxed).object.IsNull()); + mirror::DexCachePair<T> source = src[i].load(std::memory_order_relaxed); + if (source.index != 0u || !source.object.IsNull()) { + dst[i].store(source, std::memory_order_relaxed); + } + } +} + bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -1224,7 +1241,10 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( if (dex_file->NumStringIds() < num_strings) { num_strings = dex_file->NumStringIds(); } - const size_t num_types = dex_file->NumTypeIds(); + size_t num_types = mirror::DexCache::kDexCacheTypeCacheSize; + if (dex_file->NumTypeIds() < num_types) { + num_types = dex_file->NumTypeIds(); + } const size_t num_methods = dex_file->NumMethodIds(); const size_t num_fields = dex_file->NumFieldIds(); size_t num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; @@ -1243,28 +1263,14 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::StringDexCacheType* const image_resolved_strings = dex_cache->GetStrings(); mirror::StringDexCacheType* const strings = reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); - for (size_t j = 0; j < num_strings; ++j) { - DCHECK_EQ(strings[j].load(std::memory_order_relaxed).index, 0u); - DCHECK(strings[j].load(std::memory_order_relaxed).object.IsNull()); - strings[j].store(image_resolved_strings[j].load(std::memory_order_relaxed), - std::memory_order_relaxed); - } - mirror::StringDexCachePair::Initialize(strings); + CopyDexCachePairs(image_resolved_strings, num_strings, strings); dex_cache->SetStrings(strings); } if (num_types != 0u) { - GcRoot<mirror::Class>* const image_resolved_types = dex_cache->GetResolvedTypes(); - GcRoot<mirror::Class>* const types = - reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); - for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) { - DCHECK(types[j].IsNull()); - } - CopyNonNull(image_resolved_types, - num_types, - types, - [](const GcRoot<mirror::Class>& elem) { - return elem.IsNull(); - }); + mirror::TypeDexCacheType* const image_resolved_types = dex_cache->GetResolvedTypes(); + mirror::TypeDexCacheType* const types = + reinterpret_cast<mirror::TypeDexCacheType*>(raw_arrays + layout.TypesOffset()); + CopyDexCachePairs(image_resolved_types, num_types, types); dex_cache->SetResolvedTypes(types); } if (num_methods != 0u) { @@ -1305,15 +1311,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::MethodTypeDexCacheType* const method_types = reinterpret_cast<mirror::MethodTypeDexCacheType*>( raw_arrays + layout.MethodTypesOffset()); - for (size_t j = 0; j < num_method_types; ++j) { - DCHECK_EQ(method_types[j].load(std::memory_order_relaxed).index, 0u); - DCHECK(method_types[j].load(std::memory_order_relaxed).object.IsNull()); - method_types[j].store( - image_resolved_method_types[j].load(std::memory_order_relaxed), - std::memory_order_relaxed); - } - - mirror::MethodTypeDexCachePair::Initialize(method_types); + CopyDexCachePairs(image_resolved_method_types, num_method_types, method_types); dex_cache->SetResolvedMethodTypes(method_types); } } @@ -1322,24 +1320,16 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( // 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. - ObjPtr<mirror::DexCache> existing_dex_cache = FindDexCacheLocked(self, - *dex_file, - /*allow_failure*/true); - CHECK(existing_dex_cache == nullptr); - StackHandleScope<1> hs3(self); - Handle<mirror::DexCache> h_dex_cache = hs3.NewHandle(dex_cache); - RegisterDexFileLocked(*dex_file, h_dex_cache); - if (kIsDebugBuild) { - dex_cache.Assign(h_dex_cache.Get()); // Update dex_cache, used below in debug build. - } + CHECK(!FindDexCacheDataLocked(*dex_file).IsValid()); + RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get()); } if (kIsDebugBuild) { CHECK(new_class_set != nullptr); - GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes(); + mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); const size_t num_types = dex_cache->NumResolvedTypes(); - for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { + for (size_t j = 0; j != num_types; ++j) { // The image space is not yet added to the heap, avoid read barriers. - ObjPtr<mirror::Class> klass = types[j].Read(); + ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); if (space->HasAddress(klass.Ptr())) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->Find(ClassTable::TableSlot(klass)); @@ -1675,11 +1665,9 @@ bool ClassLinker::AddImageSpace( return false; } - StackHandleScope<1> hs2(self); - MutableHandle<mirror::DexCache> h_dex_cache(hs2.NewHandle<mirror::DexCache>(nullptr)); for (int32_t i = 0; i < dex_caches->GetLength(); i++) { - h_dex_cache.Assign(dex_caches->Get(i)); - std::string dex_file_location(h_dex_cache->GetLocation()->ToModifiedUtf8()); + ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i); + std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); // TODO: Only store qualified paths. // If non qualified, qualify it. if (dex_file_location.find('/') == std::string::npos) { @@ -1699,10 +1687,10 @@ bool ClassLinker::AddImageSpace( if (app_image) { // The current dex file field is bogus, overwrite it so that we can get the dex file in the // loop below. - h_dex_cache->SetDexFile(dex_file.get()); - GcRoot<mirror::Class>* const types = h_dex_cache->GetResolvedTypes(); - for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) { - ObjPtr<mirror::Class> klass = types[j].Read(); + dex_cache->SetDexFile(dex_file.get()); + mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); + for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { + ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); if (klass != nullptr) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } @@ -1711,11 +1699,11 @@ bool ClassLinker::AddImageSpace( if (kSanityCheckObjects) { ImageSanityChecks::CheckPointerArray(heap, this, - h_dex_cache->GetResolvedMethods(), - h_dex_cache->NumResolvedMethods()); + dex_cache->GetResolvedMethods(), + dex_cache->NumResolvedMethods()); } // Register dex files, keep track of existing ones that are conflicts. - AppendToBootClassPath(*dex_file.get(), h_dex_cache); + AppendToBootClassPath(*dex_file.get(), dex_cache); } out_dex_files->push_back(std::move(dex_file)); } @@ -2656,7 +2644,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, } ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get()); if (dex_cache == nullptr) { - self->AssertPendingOOMException(); + self->AssertPendingException(); return nullptr; } klass->SetDexCache(dex_cache); @@ -3264,28 +3252,27 @@ 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(AllocAndInitializeDexCache( + ObjPtr<mirror::DexCache> dex_cache = AllocAndInitializeDexCache( self, dex_file, - Runtime::Current()->GetLinearAlloc()))); - CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for " - << dex_file.GetLocation(); + Runtime::Current()->GetLinearAlloc()); + CHECK(dex_cache != nullptr) << "Failed to allocate dex cache for " << dex_file.GetLocation(); AppendToBootClassPath(dex_file, dex_cache); } void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) { - CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); + ObjPtr<mirror::DexCache> dex_cache) { + CHECK(dex_cache != nullptr) << dex_file.GetLocation(); boot_class_path_.push_back(&dex_file); - RegisterDexFile(dex_file, dex_cache); + RegisterBootClassPathDexFile(dex_file, dex_cache); } void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) { + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader) { Thread* const self = Thread::Current(); Locks::dex_lock_->AssertExclusiveHeld(self); - CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); + CHECK(dex_cache != 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. const std::string dex_cache_location = dex_cache->GetLocation()->ToModifiedUtf8(); @@ -3313,25 +3300,49 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, ++it; } } - jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache.Get()); + jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache); dex_cache->SetDexFile(&dex_file); DexCacheData data; data.weak_root = dex_cache_jweak; data.dex_file = dex_cache->GetDexFile(); data.resolved_methods = dex_cache->GetResolvedMethods(); + data.class_table = ClassTableForClassLoader(class_loader); + DCHECK(data.class_table != nullptr); dex_caches_.push_back(data); } -mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, - ObjPtr<mirror::ClassLoader> class_loader) { +ObjPtr<mirror::DexCache> ClassLinker::DecodeDexCache(Thread* self, const DexCacheData& data) { + return data.IsValid() + ? ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)) + : nullptr; +} + +ObjPtr<mirror::DexCache> ClassLinker::EnsureSameClassLoader( + Thread* self, + ObjPtr<mirror::DexCache> dex_cache, + const DexCacheData& data, + ObjPtr<mirror::ClassLoader> class_loader) { + DCHECK_EQ(dex_cache->GetDexFile(), data.dex_file); + if (data.class_table != ClassTableForClassLoader(class_loader)) { + self->ThrowNewExceptionF("Ljava/lang/InternalError;", + "Attempt to register dex file %s with multiple class loaders", + data.dex_file->GetLocation().c_str()); + return nullptr; + } + return dex_cache; +} + +ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file, + ObjPtr<mirror::ClassLoader> class_loader) { Thread* self = Thread::Current(); + DexCacheData old_data; { ReaderMutexLock mu(self, *Locks::dex_lock_); - ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); - if (dex_cache != nullptr) { - // TODO: Check if the dex file was registered with the same class loader. Bug: 34193123 - return dex_cache.Ptr(); - } + old_data = FindDexCacheDataLocked(dex_file); + } + ObjPtr<mirror::DexCache> old_dex_cache = DecodeDexCache(self, old_data); + if (old_dex_cache != nullptr) { + return EnsureSameClassLoader(self, old_dex_cache, old_data, class_loader); } LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader); DCHECK(linear_alloc != nullptr); @@ -3343,7 +3354,8 @@ 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<2> hs(self); + StackHandleScope<3> hs(self); + Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader)); ObjPtr<mirror::String> location; Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(/*out*/&location, self, @@ -3351,75 +3363,92 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, Handle<mirror::String> h_location(hs.NewHandle(location)); { 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. - // If this thread encountered OOME, ignore it. - DCHECK_EQ(h_dex_cache.Get() == nullptr, self->IsExceptionPending()); - self->ClearException(); - return dex_cache.Ptr(); - } - if (h_dex_cache.Get() == nullptr) { - 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. - mirror::DexCache::InitializeDexCache(self, - h_dex_cache.Get(), - h_location.Get(), - &dex_file, - linear_alloc, - image_pointer_size_); - RegisterDexFileLocked(dex_file, h_dex_cache); + old_data = FindDexCacheDataLocked(dex_file); + old_dex_cache = DecodeDexCache(self, old_data); + if (old_dex_cache == nullptr && h_dex_cache.Get() != 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. + mirror::DexCache::InitializeDexCache(self, + h_dex_cache.Get(), + h_location.Get(), + &dex_file, + linear_alloc, + image_pointer_size_); + RegisterDexFileLocked(dex_file, h_dex_cache.Get(), h_class_loader.Get()); + } + } + if (old_dex_cache != nullptr) { + // Another thread managed to initialize the dex cache faster, so use that DexCache. + // If this thread encountered OOME, ignore it. + DCHECK_EQ(h_dex_cache.Get() == nullptr, self->IsExceptionPending()); + self->ClearException(); + // We cannot call EnsureSameClassLoader() while holding the dex_lock_. + return EnsureSameClassLoader(self, old_dex_cache, old_data, h_class_loader.Get()); + } + if (h_dex_cache.Get() == nullptr) { + self->AssertPendingOOMException(); + return nullptr; } table->InsertStrongRoot(h_dex_cache.Get()); return h_dex_cache.Get(); } -void ClassLinker::RegisterDexFile(const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) { +void ClassLinker::RegisterBootClassPathDexFile(const DexFile& dex_file, + ObjPtr<mirror::DexCache> dex_cache) { WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_); - RegisterDexFileLocked(dex_file, dex_cache); + RegisterDexFileLocked(dex_file, dex_cache, /* class_loader */ nullptr); +} + +bool ClassLinker::IsDexFileRegistered(Thread* self, const DexFile& dex_file) { + ReaderMutexLock mu(self, *Locks::dex_lock_); + return DecodeDexCache(self, FindDexCacheDataLocked(dex_file)) != nullptr; } -mirror::DexCache* ClassLinker::FindDexCache(Thread* self, - const DexFile& dex_file, - bool allow_failure) { +ObjPtr<mirror::DexCache> ClassLinker::FindDexCache(Thread* self, const DexFile& dex_file) { ReaderMutexLock mu(self, *Locks::dex_lock_); - return FindDexCacheLocked(self, dex_file, allow_failure); + ObjPtr<mirror::DexCache> dex_cache = DecodeDexCache(self, FindDexCacheDataLocked(dex_file)); + if (dex_cache != nullptr) { + return dex_cache; + } + // Failure, dump diagnostic and abort. + std::string location(dex_file.GetLocation()); + for (const DexCacheData& data : dex_caches_) { + if (DecodeDexCache(self, data) != nullptr) { + LOG(ERROR) << "Registered dex file " << data.dex_file->GetLocation(); + } + } + LOG(FATAL) << "Failed to find DexCache for DexFile " << location; + UNREACHABLE(); } -mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, - const DexFile& dex_file, - bool allow_failure) { +ClassTable* ClassLinker::FindClassTable(Thread* self, ObjPtr<mirror::DexCache> dex_cache) { + const DexFile* dex_file = dex_cache->GetDexFile(); + DCHECK(dex_file != nullptr); + ReaderMutexLock mu(self, *Locks::dex_lock_); // Search assuming unique-ness of dex file. for (const DexCacheData& data : dex_caches_) { // Avoid decoding (and read barriers) other unrelated dex caches. - if (data.dex_file == &dex_file) { - ObjPtr<mirror::DexCache> dex_cache = - ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); - if (dex_cache != nullptr) { - return dex_cache.Ptr(); + if (data.dex_file == dex_file) { + ObjPtr<mirror::DexCache> registered_dex_cache = DecodeDexCache(self, data); + if (registered_dex_cache != nullptr) { + CHECK_EQ(registered_dex_cache, dex_cache) << dex_file->GetLocation(); + return data.class_table; } - break; } } - if (allow_failure) { - return nullptr; - } - std::string location(dex_file.GetLocation()); - // Failure, dump diagnostic and abort. + return nullptr; +} + +ClassLinker::DexCacheData ClassLinker::FindDexCacheDataLocked(const DexFile& dex_file) { + // Search assuming unique-ness of dex file. for (const DexCacheData& data : dex_caches_) { - ObjPtr<mirror::DexCache> dex_cache = - ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); - if (dex_cache != nullptr) { - LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation(); + // Avoid decoding (and read barriers) other unrelated dex caches. + if (data.dex_file == &dex_file) { + return data; } } - LOG(FATAL) << "Failed to find DexCache for DexFile " << location; - UNREACHABLE(); + return DexCacheData(); } void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { @@ -5679,14 +5708,7 @@ class LinkVirtualHashTable { const uint32_t LinkVirtualHashTable::invalid_index_ = std::numeric_limits<uint32_t>::max(); const uint32_t LinkVirtualHashTable::removed_index_ = std::numeric_limits<uint32_t>::max() - 1; -// b/30419309 -#if defined(__i386__) -#define X86_OPTNONE __attribute__((optnone)) -#else -#define X86_OPTNONE -#endif - -X86_OPTNONE bool ClassLinker::LinkVirtualMethods( +bool ClassLinker::LinkVirtualMethods( Thread* self, Handle<mirror::Class> klass, /*out*/std::unordered_map<size_t, ClassLinker::MethodTranslation>* default_translations) { @@ -7698,7 +7720,9 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); ObjPtr<mirror::String> string = intern_table_->InternStrong(utf16_length, utf8_data); - dex_cache->SetResolvedString(string_idx, string); + if (string != nullptr) { + dex_cache->SetResolvedString(string_idx, string); + } return string.Ptr(); } @@ -7739,11 +7763,16 @@ ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file, // Find the class in the loaded classes table. type = LookupClass(self, descriptor, hash, class_loader.Ptr()); } + if (type != nullptr) { + if (type->IsResolved()) { + dex_cache->SetResolvedType(type_idx, type); + } else { + type = nullptr; + } + } } - if (type != nullptr && type->IsResolved()) { - return type.Ptr(); - } - return nullptr; + DCHECK(type == nullptr || type->IsResolved()); + return type; } mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, @@ -7763,6 +7792,12 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, Thread::PoisonObjectPointersIfDebug(); ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx); if (resolved == nullptr) { + // TODO: Avoid this lookup as it duplicates work done in FindClass(). It is here + // as a workaround for FastNative JNI to avoid AssertNoPendingException() when + // trying to resolve annotations while an exception may be pending. Bug: 34659969 + resolved = LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()); + } + if (resolved == nullptr) { Thread* self = Thread::Current(); const char* descriptor = dex_file.StringByTypeIdx(type_idx); resolved = FindClass(self, descriptor, class_loader); |