diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 1175 |
1 files changed, 664 insertions, 511 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index acb39c5402..4ce52f10f3 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -16,12 +16,15 @@ #include "class_linker.h" +#include <algorithm> #include <deque> #include <iostream> #include <memory> #include <queue> #include <string> +#include <tuple> #include <unistd.h> +#include <unordered_map> #include <utility> #include <vector> @@ -41,24 +44,20 @@ #include "compiler_callbacks.h" #include "debugger.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "handle_scope.h" +#include "handle_scope-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "leb128.h" #include "linear_alloc.h" -#include "oat.h" -#include "oat_file.h" -#include "oat_file-inl.h" -#include "oat_file_assistant.h" -#include "object_lock.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -72,12 +71,17 @@ #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.h" +#include "native/dalvik_system_DexFile.h" +#include "oat.h" +#include "oat_file.h" +#include "oat_file-inl.h" +#include "oat_file_assistant.h" +#include "oat_file_manager.h" +#include "object_lock.h" #include "os.h" #include "runtime.h" -#include "entrypoints/entrypoint_utils.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" -#include "handle_scope-inl.h" #include "thread-inl.h" #include "trace.h" #include "utils.h" @@ -89,9 +93,6 @@ namespace art { static constexpr bool kSanityCheckObjects = kIsDebugBuild; -// For b/21333911. -static constexpr bool kDuplicateClassesCheck = false; - static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) SHARED_REQUIRES(Locks::mutator_lock_); @@ -696,343 +697,6 @@ void ClassLinker::RunRootClinits() { } } -const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) { - WriterMutexLock mu(Thread::Current(), dex_lock_); - if (kIsDebugBuild) { - for (size_t i = 0; i < oat_files_.size(); ++i) { - CHECK_NE(oat_file, oat_files_[i]) << oat_file->GetLocation(); - } - } - VLOG(class_linker) << "Registering " << oat_file->GetLocation(); - oat_files_.push_back(oat_file); - return oat_file; -} - -OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) { - VLOG(startup) << "ClassLinker::GetImageOatFile entering"; - OatFile* oat_file = space->ReleaseOatFile(); - CHECK_EQ(RegisterOatFile(oat_file), oat_file); - VLOG(startup) << "ClassLinker::GetImageOatFile exiting"; - return *oat_file; -} - -class DexFileAndClassPair : ValueObject { - public: - DexFileAndClassPair(const DexFile* dex_file, size_t current_class_index, bool from_loaded_oat) - : cached_descriptor_(GetClassDescriptor(dex_file, current_class_index)), - dex_file_(dex_file), - current_class_index_(current_class_index), - from_loaded_oat_(from_loaded_oat) {} - - DexFileAndClassPair(const DexFileAndClassPair&) = default; - - DexFileAndClassPair& operator=(const DexFileAndClassPair& rhs) { - cached_descriptor_ = rhs.cached_descriptor_; - dex_file_ = rhs.dex_file_; - current_class_index_ = rhs.current_class_index_; - from_loaded_oat_ = rhs.from_loaded_oat_; - return *this; - } - - const char* GetCachedDescriptor() const { - return cached_descriptor_; - } - - bool operator<(const DexFileAndClassPair& rhs) const { - const char* lhsDescriptor = cached_descriptor_; - const char* rhsDescriptor = rhs.cached_descriptor_; - int cmp = strcmp(lhsDescriptor, rhsDescriptor); - if (cmp != 0) { - // Note that the order must be reversed. We want to iterate over the classes in dex files. - // They are sorted lexicographically. Thus, the priority-queue must be a min-queue. - return cmp > 0; - } - return dex_file_ < rhs.dex_file_; - } - - bool DexFileHasMoreClasses() const { - return current_class_index_ + 1 < dex_file_->NumClassDefs(); - } - - DexFileAndClassPair GetNext() const { - return DexFileAndClassPair(dex_file_, current_class_index_ + 1, from_loaded_oat_); - } - - size_t GetCurrentClassIndex() const { - return current_class_index_; - } - - bool FromLoadedOat() const { - return from_loaded_oat_; - } - - const DexFile* GetDexFile() const { - return dex_file_; - } - - void DeleteDexFile() { - delete dex_file_; - dex_file_ = nullptr; - } - - private: - static const char* GetClassDescriptor(const DexFile* dex_file, size_t index) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(static_cast<uint16_t>(index)); - return dex_file->StringByTypeIdx(class_def.class_idx_); - } - - const char* cached_descriptor_; - const DexFile* dex_file_; - size_t current_class_index_; - bool from_loaded_oat_; // We only need to compare mismatches between what we load now - // and what was loaded before. Any old duplicates must have been - // OK, and any new "internal" duplicates are as well (they must - // be from multidex, which resolves correctly). -}; - -static void AddDexFilesFromOat(const OatFile* oat_file, - bool already_loaded, - std::priority_queue<DexFileAndClassPair>* heap) { - const std::vector<const OatDexFile*>& oat_dex_files = oat_file->GetOatDexFiles(); - for (const OatDexFile* oat_dex_file : oat_dex_files) { - std::string error; - std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error); - if (dex_file.get() == nullptr) { - LOG(WARNING) << "Could not create dex file from oat file: " << error; - } else { - if (dex_file->NumClassDefs() > 0U) { - heap->emplace(dex_file.release(), 0U, already_loaded); - } - } - } -} - -static void AddNext(DexFileAndClassPair* original, - std::priority_queue<DexFileAndClassPair>* heap) { - if (original->DexFileHasMoreClasses()) { - heap->push(original->GetNext()); - } else { - // Need to delete the dex file. - original->DeleteDexFile(); - } -} - -static void FreeDexFilesInHeap(std::priority_queue<DexFileAndClassPair>* heap) { - while (!heap->empty()) { - delete heap->top().GetDexFile(); - heap->pop(); - } -} - -const OatFile* ClassLinker::GetBootOatFile() { - gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); - if (image_space == nullptr) { - return nullptr; - } - return image_space->GetOatFile(); -} - -const OatFile* ClassLinker::GetPrimaryOatFile() { - ReaderMutexLock mu(Thread::Current(), dex_lock_); - const OatFile* boot_oat_file = GetBootOatFile(); - if (boot_oat_file != nullptr) { - for (const OatFile* oat_file : oat_files_) { - if (oat_file != boot_oat_file) { - return oat_file; - } - } - } - return nullptr; -} - -// Check for class-def collisions in dex files. -// -// This works by maintaining a heap with one class from each dex file, sorted by the class -// descriptor. Then a dex-file/class pair is continually removed from the heap and compared -// against the following top element. If the descriptor is the same, it is now checked whether -// the two elements agree on whether their dex file was from an already-loaded oat-file or the -// new oat file. Any disagreement indicates a collision. -bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg) { - if (!kDuplicateClassesCheck) { - return false; - } - - // Dex files are registered late - once a class is actually being loaded. We have to compare - // against the open oat files. Take the dex_lock_ that protects oat_files_ accesses. - ReaderMutexLock mu(Thread::Current(), dex_lock_); - - std::priority_queue<DexFileAndClassPair> queue; - - // Add dex files from already loaded oat files, but skip boot. - { - const OatFile* boot_oat = GetBootOatFile(); - for (const OatFile* loaded_oat_file : oat_files_) { - if (loaded_oat_file == boot_oat) { - continue; - } - AddDexFilesFromOat(loaded_oat_file, true, &queue); - } - } - - if (queue.empty()) { - // No other oat files, return early. - return false; - } - - // Add dex files from the oat file to check. - AddDexFilesFromOat(oat_file, false, &queue); - - // Now drain the queue. - while (!queue.empty()) { - DexFileAndClassPair compare_pop = queue.top(); - queue.pop(); - - // Compare against the following elements. - while (!queue.empty()) { - DexFileAndClassPair top = queue.top(); - - if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) { - // Same descriptor. Check whether it's crossing old-oat-files to new-oat-files. - if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) { - *error_msg = - StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s", - compare_pop.GetCachedDescriptor(), - compare_pop.GetDexFile()->GetLocation().c_str(), - top.GetDexFile()->GetLocation().c_str()); - FreeDexFilesInHeap(&queue); - return true; - } - // Pop it. - queue.pop(); - AddNext(&top, &queue); - } else { - // Something else. Done here. - break; - } - } - AddNext(&compare_pop, &queue); - } - - return false; -} - -std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat( - const char* dex_location, const char* oat_location, - std::vector<std::string>* error_msgs) { - CHECK(error_msgs != nullptr); - - // Verify we aren't holding the mutator lock, which could starve GC if we - // have to generate or relocate an oat file. - Locks::mutator_lock_->AssertNotHeld(Thread::Current()); - - OatFileAssistant oat_file_assistant(dex_location, oat_location, kRuntimeISA, - !Runtime::Current()->IsAotCompiler()); - - // Lock the target oat location to avoid races generating and loading the - // oat file. - std::string error_msg; - if (!oat_file_assistant.Lock(&error_msg)) { - // Don't worry too much if this fails. If it does fail, it's unlikely we - // can generate an oat file anyway. - VLOG(class_linker) << "OatFileAssistant::Lock: " << error_msg; - } - - // Check if we already have an up-to-date oat file open. - const OatFile* source_oat_file = nullptr; - { - ReaderMutexLock mu(Thread::Current(), dex_lock_); - for (const OatFile* oat_file : oat_files_) { - CHECK(oat_file != nullptr); - if (oat_file_assistant.GivenOatFileIsUpToDate(*oat_file)) { - source_oat_file = oat_file; - break; - } - } - } - - // If we didn't have an up-to-date oat file open, try to load one from disk. - if (source_oat_file == nullptr) { - // Update the oat file on disk if we can. This may fail, but that's okay. - // Best effort is all that matters here. - if (!oat_file_assistant.MakeUpToDate(&error_msg)) { - LOG(WARNING) << error_msg; - } - - // Get the oat file on disk. - std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); - if (oat_file.get() != nullptr) { - // Take the file only if it has no collisions, or we must take it because of preopting. - bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg); - if (!accept_oat_file) { - // Failed the collision check. Print warning. - if (Runtime::Current()->IsDexFileFallbackEnabled()) { - LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for " - << dex_location; - } else { - LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to " - " load classes for " << dex_location; - } - LOG(WARNING) << error_msg; - - // However, if the app was part of /system and preopted, there is no original dex file - // available. In that case grudgingly accept the oat file. - if (!DexFile::MaybeDex(dex_location)) { - accept_oat_file = true; - LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. " - << "Allow oat file use. This is potentially dangerous."; - } - } - - if (accept_oat_file) { - source_oat_file = oat_file.release(); - RegisterOatFile(source_oat_file); - } - } - } - - std::vector<std::unique_ptr<const DexFile>> dex_files; - - // Load the dex files from the oat file. - if (source_oat_file != nullptr) { - dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); - if (dex_files.empty()) { - error_msgs->push_back("Failed to open dex files from " - + source_oat_file->GetLocation()); - } - } - - // Fall back to running out of the original dex file if we couldn't load any - // dex_files from the oat file. - if (dex_files.empty()) { - if (oat_file_assistant.HasOriginalDexFiles()) { - if (Runtime::Current()->IsDexFileFallbackEnabled()) { - if (!DexFile::Open(dex_location, dex_location, &error_msg, &dex_files)) { - LOG(WARNING) << error_msg; - error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)); - } - } else { - error_msgs->push_back("Fallback mode disabled, skipping dex files."); - } - } else { - error_msgs->push_back("No original dex files found for dex location " - + std::string(dex_location)); - } - } - return dex_files; -} - -const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) { - ReaderMutexLock mu(Thread::Current(), dex_lock_); - for (size_t i = 0; i < oat_files_.size(); i++) { - const OatFile* oat_file = oat_files_[i]; - DCHECK(oat_file != nullptr); - if (oat_file->GetLocation() == oat_location) { - return oat_file; - } - } - return nullptr; -} - static void SanityCheckArtMethod(ArtMethod* m, mirror::Class* expected_class, gc::space::ImageSpace* space) @@ -1169,16 +833,17 @@ void ClassLinker::InitFromImage() { CHECK(space != nullptr); image_pointer_size_ = space->GetImageHeader().GetPointerSize(); dex_cache_image_class_lookup_required_ = true; - OatFile& oat_file = GetImageOatFile(space); - CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U); - CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatDataBegin(), 0U); - const char* image_file_location = oat_file.GetOatHeader(). + const OatFile* oat_file = runtime->GetOatFileManager().RegisterImageOatFile(space); + DCHECK(oat_file != nullptr); + CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U); + CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U); + const char* image_file_location = oat_file->GetOatHeader(). GetStoreValueByKey(OatHeader::kImageLocationKey); CHECK(image_file_location == nullptr || *image_file_location == 0); - quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline(); - quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline(); - quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline(); - quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge(); + quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline(); + quick_imt_conflict_trampoline_ = oat_file->GetOatHeader().GetQuickImtConflictTrampoline(); + quick_generic_jni_trampoline_ = oat_file->GetOatHeader().GetQuickGenericJniTrampoline(); + quick_to_interpreter_bridge_trampoline_ = oat_file->GetOatHeader().GetQuickToInterpreterBridge(); StackHandleScope<2> hs(self); mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches( @@ -1200,20 +865,20 @@ void ClassLinker::InitFromImage() { java_lang_Object->GetObjectSize(), VoidFunctor())); - CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(), + CHECK_EQ(oat_file->GetOatHeader().GetDexFileCount(), static_cast<uint32_t>(dex_caches->GetLength())); for (int32_t i = 0; i < dex_caches->GetLength(); i++) { StackHandleScope<1> hs2(self); Handle<mirror::DexCache> dex_cache(hs2.NewHandle(dex_caches->Get(i))); const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); - const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(), - nullptr); - CHECK(oat_dex_file != nullptr) << oat_file.GetLocation() << " " << dex_file_location; + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location.c_str(), + nullptr); + CHECK(oat_dex_file != nullptr) << oat_file->GetLocation() << " " << dex_file_location; std::string error_msg; std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); - if (dex_file.get() == nullptr) { + if (dex_file == nullptr) { LOG(FATAL) << "Failed to open dex file " << dex_file_location - << " from within oat file " << oat_file.GetLocation() + << " from within oat file " << oat_file->GetLocation() << " error '" << error_msg << "'"; UNREACHABLE(); } @@ -1361,9 +1026,9 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); VisitClassRoots(visitor, flags); array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); - for (GcRoot<mirror::Class>& root : find_array_class_cache_) { - root.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); - } + // Instead of visiting the find_array_class_cache_ drop it so that it doesn't prevent class + // unloading if we are marking roots. + DropFindArrayClassCache(); } class VisitClassLoaderClassesVisitor : public ClassLoaderVisitor { @@ -1508,7 +1173,6 @@ ClassLinker::~ClassLinker() { mirror::IntArray::ResetArrayClass(); mirror::LongArray::ResetArrayClass(); mirror::ShortArray::ResetArrayClass(); - STLDeleteElements(&oat_files_); Thread* const self = Thread::Current(); JavaVMExt* const vm = Runtime::Current()->GetJavaVM(); for (const ClassLoaderData& data : class_loaders_) { @@ -1525,7 +1189,9 @@ 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) { +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)))); @@ -1540,22 +1206,20 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_fi } DexCacheArraysLayout layout(image_pointer_size_, &dex_file); uint8_t* raw_arrays = nullptr; - if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u || + if (dex_file.GetOatDexFile() != nullptr && + dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) { + raw_arrays = const_cast<uint8_t*>(dex_file.GetOatDexFile()->GetDexCacheArrays()); + } else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u || dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) { // NOTE: We "leak" the raw_arrays because we never destroy the dex cache. DCHECK(image_pointer_size_ == 4u || image_pointer_size_ == 8u); - if (sizeof(void*) == 8u && image_pointer_size_ == 4u) { - // When cross-compiling for a 32-bit target on a 64-bit host, we need these arrays - // in the low 4GiB address space so that we can store pointers in 32-bit fields. - // This is conveniently provided by the linear allocator. - raw_arrays = reinterpret_cast<uint8_t*>( - Runtime::Current()->GetLinearAlloc()->Alloc(self, layout.Size())); // Zero-initialized. - } else { - raw_arrays = reinterpret_cast<uint8_t*>(calloc(layout.Size(), 1u)); // Zero-initialized. - if (raw_arrays == nullptr) { - return nullptr; - } - } + // When cross-compiling for a 32-bit target on a 64-bit host, we need these arrays + // in the low 4GiB address space so that we can store pointers in 32-bit fields. + // This is conveniently provided by the linear allocator. + raw_arrays = reinterpret_cast<uint8_t*>( + (sizeof(void*) == 8u && image_pointer_size_ == 4u) + ? Runtime::Current()->GetLinearAlloc()->Alloc(self, layout.Size()) // Zero-initialized. + : linear_alloc->Alloc(self, layout.Size())); // Zero-initialized. } GcRoot<mirror::String>* strings = (dex_file.NumStringIds() == 0u) ? nullptr : reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset()); @@ -1768,13 +1432,18 @@ bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& break; } int32_t long_array_size = long_array->GetLength(); - for (int32_t j = 0; j < long_array_size; ++j) { + // First element is the oat file. + for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( long_array->GetWithoutChecks(j))); const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { - mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader, - *cp_dex_file, *dex_class_def); + mirror::Class* klass = DefineClass(self, + descriptor, + hash, + class_loader, + *cp_dex_file, + *dex_class_def); if (klass == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); @@ -1921,7 +1590,9 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, self->AssertPendingOOMException(); return nullptr; } - mirror::DexCache* dex_cache = RegisterDexFile(dex_file); + mirror::DexCache* dex_cache = RegisterDexFile( + dex_file, + GetOrCreateAllocatorForClassLoader(class_loader.Get())); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; @@ -2424,6 +2095,19 @@ LinearAlloc* ClassLinker::GetAllocatorForClassLoader(mirror::ClassLoader* class_ return allocator; } +LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader) { + if (class_loader == nullptr) { + return Runtime::Current()->GetLinearAlloc(); + } + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + LinearAlloc* allocator = class_loader->GetAllocator(); + if (allocator == nullptr) { + allocator = Runtime::Current()->CreateLinearAlloc(); + class_loader->SetAllocator(allocator); + } + return allocator; +} + void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data, @@ -2582,7 +2266,10 @@ void ClassLinker::LoadMethod(Thread* self, void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) { StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file))); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache( + self, + dex_file, + Runtime::Current()->GetLinearAlloc()))); CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for " << dex_file.GetLocation(); AppendToBootClassPath(dex_file, dex_cache); @@ -2618,7 +2305,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, dex_cache->SetDexFile(&dex_file); } -mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file) { +mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, LinearAlloc* linear_alloc) { Thread* self = Thread::Current(); { ReaderMutexLock mu(self, dex_lock_); @@ -2631,7 +2318,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file) { // 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))); + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc))); WriterMutexLock mu(self, dex_lock_); mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { @@ -3428,6 +3115,9 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& std::string descriptor(GetDescriptorForProxy(klass.Get())); const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str()); + // Needs to be before we insert the class so that the allocator field is set. + LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(klass->GetClassLoader()); + // Insert the class before loading the fields as the field roots // (ArtField::declaring_class_) are only visited from the class // table. There can't be any suspend points between inserting the @@ -3435,9 +3125,6 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), hash); CHECK(existing == nullptr); - // Needs to be after we insert the class so that the allocator field is set. - LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); - // Instance fields are inherited, but we add a couple of static fields... const size_t num_fields = 2; LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields); @@ -3676,6 +3363,18 @@ bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_stati return false; } } + // If we are a class we need to initialize all interfaces with default methods when we are + // initialized. Check all of them. + if (!klass->IsInterface()) { + size_t num_interfaces = klass->GetIfTableCount(); + for (size_t i = 0; i < num_interfaces; i++) { + mirror::Class* iface = klass->GetIfTable()->GetInterface(i); + if (iface->HasDefaultMethods() && + !CanWeInitializeClass(iface, can_init_statics, can_init_parents)) { + return false; + } + } + } } if (klass->IsInterface() || !klass->HasSuperClass()) { return true; @@ -3802,6 +3501,38 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, } } + if (!klass->IsInterface()) { + // Initialize interfaces with default methods for the JLS. + size_t num_direct_interfaces = klass->NumDirectInterfaces(); + // Only setup the (expensive) handle scope if we actually need to. + if (UNLIKELY(num_direct_interfaces > 0)) { + StackHandleScope<1> hs_iface(self); + MutableHandle<mirror::Class> handle_scope_iface(hs_iface.NewHandle<mirror::Class>(nullptr)); + for (size_t i = 0; i < num_direct_interfaces; i++) { + handle_scope_iface.Assign(mirror::Class::GetDirectInterface(self, klass, i)); + CHECK(handle_scope_iface.Get() != nullptr); + CHECK(handle_scope_iface->IsInterface()); + if (handle_scope_iface->HasBeenRecursivelyInitialized()) { + // We have already done this for this interface. Skip it. + continue; + } + // We cannot just call initialize class directly because we need to ensure that ALL + // interfaces with default methods are initialized. Non-default interface initialization + // will not affect other non-default super-interfaces. + bool iface_initialized = InitializeDefaultInterfaceRecursive(self, + handle_scope_iface, + can_init_statics, + can_init_parents); + if (!iface_initialized) { + ObjectLock<mirror::Class> lock(self, klass); + // Initialization failed because one of our interfaces with default methods is erroneous. + mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + return false; + } + } + } + } + const size_t num_static_fields = klass->NumStaticFields(); if (num_static_fields > 0) { const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); @@ -3891,6 +3622,52 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return success; } +// We recursively run down the tree of interfaces. We need to do this in the order they are declared +// and perform the initialization only on those interfaces that contain default methods. +bool ClassLinker::InitializeDefaultInterfaceRecursive(Thread* self, + Handle<mirror::Class> iface, + bool can_init_statics, + bool can_init_parents) { + CHECK(iface->IsInterface()); + size_t num_direct_ifaces = iface->NumDirectInterfaces(); + // Only create the (expensive) handle scope if we need it. + if (UNLIKELY(num_direct_ifaces > 0)) { + StackHandleScope<1> hs(self); + MutableHandle<mirror::Class> handle_super_iface(hs.NewHandle<mirror::Class>(nullptr)); + // First we initialize all of iface's super-interfaces recursively. + for (size_t i = 0; i < num_direct_ifaces; i++) { + mirror::Class* super_iface = mirror::Class::GetDirectInterface(self, iface, i); + if (!super_iface->HasBeenRecursivelyInitialized()) { + // Recursive step + handle_super_iface.Assign(super_iface); + if (!InitializeDefaultInterfaceRecursive(self, + handle_super_iface, + can_init_statics, + can_init_parents)) { + return false; + } + } + } + } + + bool result = true; + // Then we initialize 'iface' if it has default methods. We do not need to (and in fact must not) + // initialize if we don't have default methods. + if (iface->HasDefaultMethods()) { + result = EnsureInitialized(self, iface, can_init_statics, can_init_parents); + } + + // Mark that this interface has undergone recursive default interface initialization so we know we + // can skip it on any later class initializations. We do this even if we are not a default + // interface since we can still avoid the traversal. This is purely a performance optimization. + if (result) { + // TODO This should be done in a better way + ObjectLock<mirror::Class> lock(self, iface); + iface->SetRecursivelyInitialized(); + } + return result; +} + bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self, ObjectLock<mirror::Class>& lock) @@ -4193,13 +3970,13 @@ ClassTable* ClassLinker::InsertClassTableForClassLoader(mirror::ClassLoader* cla ClassLoaderData data; data.weak_root = self->GetJniEnv()->vm->AddWeakGlobalRef(self, class_loader); data.class_table = class_table; - data.allocator = Runtime::Current()->CreateLinearAlloc(); - class_loaders_.push_back(data); // Don't already have a class table, add it to the class loader. CHECK(class_loader->GetClassTable() == nullptr); - CHECK(class_loader->GetAllocator() == nullptr); class_loader->SetClassTable(data.class_table); - class_loader->SetAllocator(data.allocator); + // Should have been set when we registered the dex file. + data.allocator = class_loader->GetAllocator(); + CHECK(data.allocator != nullptr); + class_loaders_.push_back(data); } return class_table; } @@ -4623,20 +4400,16 @@ bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::ObjectArray<mirror::Class>> interfaces, ArtMethod** out_imt) { self->AllowThreadSuspension(); - if (klass->IsInterface()) { - // No vtable. - size_t count = klass->NumVirtualMethods(); - if (!IsUint<16>(count)) { - ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zd", count); - return false; - } - for (size_t i = 0; i < count; ++i) { - klass->GetVirtualMethodDuringLinking(i, image_pointer_size_)->SetMethodIndex(i); - } - } else if (!LinkVirtualMethods(self, klass)) { // Link virtual methods first. - return false; - } - return LinkInterfaceMethods(self, klass, interfaces, out_imt); // Link interface method last. + // A map from vtable indexes to the method they need to be updated to point to. Used because we + // need to have default methods be in the virtuals array of each class but we don't set that up + // until LinkInterfaceMethods. + std::unordered_map<size_t, ArtMethod*> default_translations; + // Link virtual methods then interface methods. + // We set up the interface lookup table first because we need it to determine if we need to update + // any vtable entries with new default method implementations. + return SetupInterfaceLookupTable(self, klass, interfaces) + && LinkVirtualMethods(self, klass, /*out*/ &default_translations) + && LinkInterfaceMethods(self, klass, default_translations, out_imt); } // Comparator for name and signature of a method, used in finding overriding methods. Implementation @@ -4760,9 +4533,36 @@ 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; -bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) { +bool ClassLinker::LinkVirtualMethods( + Thread* self, + Handle<mirror::Class> klass, + /*out*/std::unordered_map<size_t, ArtMethod*>* default_translations) { const size_t num_virtual_methods = klass->NumVirtualMethods(); - if (klass->HasSuperClass()) { + if (klass->IsInterface()) { + // No vtable. + if (!IsUint<16>(num_virtual_methods)) { + ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zu", num_virtual_methods); + return false; + } + bool has_defaults = false; + // TODO May need to replace this with real VTable for invoke_super + // Assign each method an IMT index and set the default flag. + for (size_t i = 0; i < num_virtual_methods; ++i) { + ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_); + m->SetMethodIndex(i); + if (!m->IsAbstract()) { + m->SetAccessFlags(m->GetAccessFlags() | kAccDefault); + has_defaults = true; + } + } + // Mark that we have default methods so that we won't need to scan the virtual_methods_ array + // during initialization. This is a performance optimization. We could simply traverse the + // virtual_methods_ array again during initialization. + if (has_defaults) { + klass->SetHasDefaultMethods(); + } + return true; + } else if (klass->HasSuperClass()) { const size_t super_vtable_length = klass->GetSuperClass()->GetVTableLength(); const size_t max_count = num_virtual_methods + super_vtable_length; StackHandleScope<2> hs(self); @@ -4778,14 +4578,22 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) vtable->SetElementPtrSize( i, super_class->GetEmbeddedVTableEntry(i, image_pointer_size_), image_pointer_size_); } - if (num_virtual_methods == 0) { + // We might need to change vtable if we have new virtual methods or new interfaces (since that + // might give us new default methods). If no new interfaces then we can skip the rest since + // the class cannot override any of the super-class's methods. This is required for + // correctness since without it we might not update overridden default method vtable entries + // correctly. + if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) { klass->SetVTable(vtable.Get()); return true; } } else { + DCHECK(super_class->IsAbstract() && !super_class->IsArrayClass()); auto* super_vtable = super_class->GetVTable(); CHECK(super_vtable != nullptr) << PrettyClass(super_class.Get()); - if (num_virtual_methods == 0) { + // We might need to change vtable if we have new virtual methods or new interfaces (since that + // might give us new default methods). See comment above. + if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) { klass->SetVTable(super_vtable); return true; } @@ -4806,7 +4614,9 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) // the need for the initial vtable which we later shrink back down). // 3. Add non overridden methods to the end of the vtable. static constexpr size_t kMaxStackHash = 250; - const size_t hash_table_size = num_virtual_methods * 3; + // + 1 so that even if we only have new default methods we will still be able to use this hash + // table (i.e. it will never have 0 size). + const size_t hash_table_size = num_virtual_methods * 3 + 1; uint32_t* hash_table_ptr; std::unique_ptr<uint32_t[]> hash_heap_storage; if (hash_table_size <= kMaxStackHash) { @@ -4823,10 +4633,10 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) i, image_pointer_size_)->GetDeclaringClass() != nullptr); hash_table.Add(i); } - // Loop through each super vtable method and see if they are overriden by a method we added to + // Loop through each super vtable method and see if they are overridden by a method we added to // the hash table. for (size_t j = 0; j < super_vtable_length; ++j) { - // Search the hash table to see if we are overidden by any method. + // Search the hash table to see if we are overridden by any method. ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); MethodNameAndSignatureComparator super_method_name_comparator( super_method->GetInterfaceMethodIfProxy(image_pointer_size_)); @@ -4849,10 +4659,51 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) << " would have incorrectly overridden the package-private method in " << PrettyDescriptor(super_method->GetDeclaringClassDescriptor()); } + } else if (super_method->IsDefault()) { + // We didn't directly override this method but we might through default methods... + // Check for default method update. + ArtMethod* default_method = nullptr; + std::string icce_message; + if (!FindDefaultMethodImplementation(self, + super_method, + klass, + /*out*/&default_method, + /*out*/&icce_message)) { + // An error occurred while finding default methods. + // TODO This should actually be thrown when we attempt to invoke this method. + ThrowIncompatibleClassChangeError(klass.Get(), "%s", icce_message.c_str()); + return false; + } + // This should always work because we inherit superclass interfaces. We should either get + // 1) An IncompatibleClassChangeError because of conflicting default method + // implementations. + // 2) The same default method implementation as the superclass. + // 3) A default method that overrides the superclass's. + // Therefore this check should never fail. + CHECK(default_method != nullptr); + if (UNLIKELY(default_method->GetDeclaringClass() != super_method->GetDeclaringClass())) { + // TODO Refactor this add default methods to virtuals here and not in + // LinkInterfaceMethods maybe. + // The problem is default methods might override previously present default-method or + // miranda-method vtable entries from the superclass. Unfortunately we need these to + // be entries in this class's virtuals. We do not give these entries there until + // LinkInterfaceMethods so we pass this map around to let it know which vtable + // entries need to be updated. + // Make a note that vtable entry j must be updated, store what it needs to be updated to. + // We will allocate a virtual method slot in LinkInterfaceMethods and fix it up then. + default_translations->insert({j, default_method}); + VLOG(class_linker) << "Method " << PrettyMethod(super_method) << " overridden by default " + << PrettyMethod(default_method) << " in " << PrettyClass(klass.Get()); + } else { + // They are the same method/no override + // Cannot do direct comparison because we had to copy the ArtMethod object into the + // superclass's vtable. + continue; + } } } - // Add the non overridden methods at the end. size_t actual_count = super_vtable_length; + // Add the non-overridden methods at the end. for (size_t i = 0; i < num_virtual_methods; ++i) { ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_); size_t method_idx = local_method->GetMethodIndexDuringLinking(); @@ -4900,20 +4751,223 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) return true; } -bool ClassLinker::LinkInterfaceMethods(Thread* self, - Handle<mirror::Class> klass, - Handle<mirror::ObjectArray<mirror::Class>> interfaces, - ArtMethod** out_imt) { - StackHandleScope<3> hs(self); - Runtime* const runtime = Runtime::Current(); - const bool has_superclass = klass->HasSuperClass(); - const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U; +// Find the default method implementation for 'interface_method' in 'klass'. Stores it into +// out_default_method and returns true on success. If no default method was found stores nullptr +// into out_default_method and returns true. If an error occurs (such as a default_method conflict) +// it will fill the icce_message with an appropriate message for an IncompatibleClassChangeError, +// which should then be thrown by the caller. +bool ClassLinker::FindDefaultMethodImplementation(Thread* self, + ArtMethod* target_method, + Handle<mirror::Class> klass, + /*out*/ArtMethod** out_default_method, + /*out*/std::string* icce_message) const { + DCHECK(self != nullptr); + DCHECK(target_method != nullptr); + DCHECK(out_default_method != nullptr); + DCHECK(icce_message != nullptr); + + *out_default_method = nullptr; + mirror::Class* chosen_iface = nullptr; + + // We organize the interface table so that, for interface I any subinterfaces J follow it in the + // table. This lets us walk the table backwards when searching for default methods. The first one + // we encounter is the best candidate since it is the most specific. Once we have found it we keep + // track of it and then continue checking all other interfaces, since we need to throw an error if + // we encounter conflicting default method implementations (one is not a subtype of the other). + // + // The order of unrelated interfaces does not matter and is not defined. + size_t iftable_count = klass->GetIfTableCount(); + if (iftable_count == 0) { + // No interfaces. We have already reset out to null so just return true. + return true; + } + + StackHandleScope<1> hs(self); + MutableHandle<mirror::IfTable> iftable(hs.NewHandle(klass->GetIfTable())); + MethodNameAndSignatureComparator target_name_comparator( + target_method->GetInterfaceMethodIfProxy(image_pointer_size_)); + // Iterates over the klass's iftable in reverse + // We have a break at the end because size_t is unsigned. + for (size_t k = iftable_count - 1; /* break if k == 0 at end */; --k) { + DCHECK_LT(k, iftable->Count()); + mirror::Class* iface = iftable->GetInterface(k); + size_t num_instance_methods = iface->NumVirtualMethods(); + // Iterate through every method on this interface. The order does not matter so we go forwards. + for (size_t m = 0; m < num_instance_methods; m++) { + ArtMethod* current_method = iface->GetVirtualMethodUnchecked(m, image_pointer_size_); + // Skip abstract methods and methods with different names. + if (current_method->IsAbstract() || + !target_name_comparator.HasSameNameAndSignature( + current_method->GetInterfaceMethodIfProxy(image_pointer_size_))) { + continue; + } + // The verifier should have caught the non-public method. + DCHECK(current_method->IsPublic()) << "Interface method is not public!"; + if (UNLIKELY(chosen_iface != nullptr)) { + // We have multiple default impls of the same method. We need to check they do not + // conflict and throw an error if they do. Conflicting means that the current iface is not + // masked by the chosen interface. + if (!iface->IsAssignableFrom(chosen_iface)) { + *icce_message = StringPrintf("Conflicting default method implementations: '%s' and '%s'", + PrettyMethod(current_method).c_str(), + PrettyMethod(*out_default_method).c_str()); + return false; + } else { + break; // Continue checking at the next interface. + } + } else { + *out_default_method = current_method; + chosen_iface = iface; + // We should now finish traversing the graph to find if we have default methods that + // conflict. + break; + } + } + if (k == 0) { + break; + } + } + return true; +} + +// Sets imt_ref appropriately for LinkInterfaceMethods. +// If there is no method in the imt location of imt_ref it will store the given method there. +// Otherwise it will set the conflict method which will figure out which method to use during +// runtime. +static void SetIMTRef(ArtMethod* unimplemented_method, + ArtMethod* conflict_method, + size_t image_pointer_size, + ArtMethod* current_method, + /*out*/ArtMethod** imt_ref) + SHARED_REQUIRES(Locks::mutator_lock_) { + // Place method in imt if entry is empty, place conflict otherwise. + if (*imt_ref == unimplemented_method) { + *imt_ref = current_method; + } else if (*imt_ref != conflict_method) { + // If we are not a conflict and we have the same signature and name as the imt + // entry, it must be that we overwrote a superclass vtable entry. + MethodNameAndSignatureComparator imt_comparator( + (*imt_ref)->GetInterfaceMethodIfProxy(image_pointer_size)); + if (imt_comparator.HasSameNameAndSignature( + current_method->GetInterfaceMethodIfProxy(image_pointer_size))) { + *imt_ref = current_method; + } else { + *imt_ref = conflict_method; + } + } +} + +// Simple helper function that checks that no subtypes of 'val' are contained within the 'classes' +// set. +static bool NotSubinterfaceOfAny(const std::unordered_set<mirror::Class*>& classes, + mirror::Class* val) + REQUIRES(Roles::uninterruptible_) + SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(val != nullptr); + for (auto c : classes) { + if (val->IsAssignableFrom(&*c)) { + return false; + } + } + return true; +} + +// Fills in and flattens the interface inheritance hierarchy. +// +// By the end of this function all interfaces in the transitive closure of to_process are added to +// the iftable and every interface precedes all of its sub-interfaces in this list. +// +// all I, J: Interface | I <: J implies J precedes I +// +// (note A <: B means that A is a subtype of B) +// +// This returns the total number of items in the iftable. The iftable might be resized down after +// this call. +// +// We order this backwards so that we do not need to reorder superclass interfaces when new +// interfaces are added in subclass's interface tables. +// +// Upon entry into this function iftable is a copy of the superclass's iftable with the first +// super_ifcount entries filled in with the transitive closure of the interfaces of the superclass. +// The other entries are uninitialized. We will fill in the remaining entries in this function. The +// iftable must be large enough to hold all interfaces without changing its size. +static size_t FillIfTable(mirror::IfTable* iftable, + size_t super_ifcount, + std::vector<mirror::Class*> to_process) + REQUIRES(Roles::uninterruptible_) + SHARED_REQUIRES(Locks::mutator_lock_) { + // This is the set of all class's already in the iftable. Used to make checking if a class has + // already been added quicker. + std::unordered_set<mirror::Class*> classes_in_iftable; + // The first super_ifcount elements are from the superclass. We note that they are already added. + for (size_t i = 0; i < super_ifcount; i++) { + mirror::Class* iface = iftable->GetInterface(i); + DCHECK(NotSubinterfaceOfAny(classes_in_iftable, iface)) << "Bad ordering."; + classes_in_iftable.insert(iface); + } + size_t filled_ifcount = super_ifcount; + for (mirror::Class* interface : to_process) { + // Let us call the first filled_ifcount elements of iftable the current-iface-list. + // At this point in the loop current-iface-list has the invariant that: + // for every pair of interfaces I,J within it: + // if index_of(I) < index_of(J) then I is not a subtype of J + + // If we have already seen this element then all of its super-interfaces must already be in the + // current-iface-list so we can skip adding it. + if (!ContainsElement(classes_in_iftable, interface)) { + // We haven't seen this interface so add all of its super-interfaces onto the + // current-iface-list, skipping those already on it. + int32_t ifcount = interface->GetIfTableCount(); + for (int32_t j = 0; j < ifcount; j++) { + mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j); + if (!ContainsElement(classes_in_iftable, super_interface)) { + DCHECK(NotSubinterfaceOfAny(classes_in_iftable, super_interface)) << "Bad ordering."; + classes_in_iftable.insert(super_interface); + iftable->SetInterface(filled_ifcount, super_interface); + filled_ifcount++; + } + } + DCHECK(NotSubinterfaceOfAny(classes_in_iftable, interface)) << "Bad ordering"; + // Place this interface onto the current-iface-list after all of its super-interfaces. + classes_in_iftable.insert(interface); + iftable->SetInterface(filled_ifcount, interface); + filled_ifcount++; + } else if (kIsDebugBuild) { + // Check all super-interfaces are already in the list. + int32_t ifcount = interface->GetIfTableCount(); + for (int32_t j = 0; j < ifcount; j++) { + mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j); + DCHECK(ContainsElement(classes_in_iftable, super_interface)) + << "Iftable does not contain " << PrettyClass(super_interface) + << ", a superinterface of " << PrettyClass(interface); + } + } + } + if (kIsDebugBuild) { + // Check that the iftable is ordered correctly. + for (size_t i = 0; i < filled_ifcount; i++) { + mirror::Class* if_a = iftable->GetInterface(i); + for (size_t j = i + 1; j < filled_ifcount; j++) { + mirror::Class* if_b = iftable->GetInterface(j); + // !(if_a <: if_b) + CHECK(!if_b->IsAssignableFrom(if_a)) + << "Bad interface order: " << PrettyClass(if_a) << " (index " << i << ") extends " + << PrettyClass(if_b) << " (index " << j << ") and so should be after it in the " + << "interface list."; + } + } + } + return filled_ifcount; +} + +bool ClassLinker::SetupInterfaceLookupTable(Thread* self, Handle<mirror::Class> klass, + Handle<mirror::ObjectArray<mirror::Class>> interfaces) { + StackHandleScope<1> hs(self); + const size_t super_ifcount = + klass->HasSuperClass() ? klass->GetSuperClass()->GetIfTableCount() : 0U; const bool have_interfaces = interfaces.Get() != nullptr; - const size_t num_interfaces = have_interfaces - ? interfaces->GetLength() - : klass->NumDirectInterfaces(); - const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); - const size_t method_size = ArtMethod::Size(image_pointer_size_); + const size_t num_interfaces = + have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces(); if (num_interfaces == 0) { if (super_ifcount == 0) { // Class implements no interfaces. @@ -4937,6 +4991,7 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, } } size_t ifcount = super_ifcount + num_interfaces; + // Check that every class being implemented is an interface. for (size_t i = 0; i < num_interfaces; i++) { mirror::Class* interface = have_interfaces ? interfaces->GetWithoutChecks(i) @@ -4952,11 +5007,13 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, } ifcount += interface->GetIfTableCount(); } + // Create the interface function table. MutableHandle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount))); if (UNLIKELY(iftable.Get() == nullptr)) { self->AssertPendingOOMException(); return false; } + // Fill in table with superclass's iftable. if (super_ifcount != 0) { mirror::IfTable* super_iftable = klass->GetSuperClass()->GetIfTable(); for (size_t i = 0; i < super_ifcount; i++) { @@ -4964,56 +5021,59 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, iftable->SetInterface(i, super_interface); } } + + // Note that AllowThreadSuspension is to thread suspension as pthread_testcancel is to pthread + // cancellation. That is it will suspend if one has a pending suspend request but otherwise + // doesn't really do anything. self->AllowThreadSuspension(); - // Flatten the interface inheritance hierarchy. - size_t idx = super_ifcount; - for (size_t i = 0; i < num_interfaces; i++) { - mirror::Class* interface = have_interfaces ? interfaces->Get(i) : - mirror::Class::GetDirectInterface(self, klass, i); - // Check if interface is already in iftable - bool duplicate = false; - for (size_t j = 0; j < idx; j++) { - mirror::Class* existing_interface = iftable->GetInterface(j); - if (existing_interface == interface) { - duplicate = true; - break; - } - } - if (!duplicate) { - // Add this non-duplicate interface. - iftable->SetInterface(idx++, interface); - // Add this interface's non-duplicate super-interfaces. - for (int32_t j = 0; j < interface->GetIfTableCount(); j++) { - mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j); - bool super_duplicate = false; - for (size_t k = 0; k < idx; k++) { - mirror::Class* existing_interface = iftable->GetInterface(k); - if (existing_interface == super_interface) { - super_duplicate = true; - break; - } - } - if (!super_duplicate) { - iftable->SetInterface(idx++, super_interface); - } - } + + size_t new_ifcount; + { + ScopedAssertNoThreadSuspension nts(self, "Copying mirror::Class*'s for FillIfTable"); + std::vector<mirror::Class*> to_add; + for (size_t i = 0; i < num_interfaces; i++) { + mirror::Class* interface = have_interfaces ? interfaces->Get(i) : + mirror::Class::GetDirectInterface(self, klass, i); + to_add.push_back(interface); } + + new_ifcount = FillIfTable(iftable.Get(), super_ifcount, std::move(to_add)); } + self->AllowThreadSuspension(); + // Shrink iftable in case duplicates were found - if (idx < ifcount) { + if (new_ifcount < ifcount) { DCHECK_NE(num_interfaces, 0U); iftable.Assign(down_cast<mirror::IfTable*>( - iftable->CopyOf(self, idx * mirror::IfTable::kMax))); + iftable->CopyOf(self, new_ifcount * mirror::IfTable::kMax))); if (UNLIKELY(iftable.Get() == nullptr)) { self->AssertPendingOOMException(); return false; } - ifcount = idx; + ifcount = new_ifcount; } else { - DCHECK_EQ(idx, ifcount); + DCHECK_EQ(new_ifcount, ifcount); } klass->SetIfTable(iftable.Get()); + return true; +} + +bool ClassLinker::LinkInterfaceMethods( + Thread* self, + Handle<mirror::Class> klass, + const std::unordered_map<size_t, ArtMethod*>& default_translations, + ArtMethod** out_imt) { + StackHandleScope<3> hs(self); + Runtime* const runtime = Runtime::Current(); + const bool has_superclass = klass->HasSuperClass(); + const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U; + const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); + const size_t method_size = ArtMethod::Size(image_pointer_size_); + const size_t ifcount = klass->GetIfTableCount(); + + MutableHandle<mirror::IfTable> iftable(hs.NewHandle(klass->GetIfTable())); + // If we're an interface, we don't need the vtable pointers, so we're done. if (klass->IsInterface()) { return true; @@ -5026,6 +5086,7 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, ArenaStack stack(runtime->GetLinearAlloc()->GetArenaPool()); ScopedArenaAllocator allocator(&stack); ScopedArenaVector<ArtMethod*> miranda_methods(allocator.Adapter()); + ScopedArenaVector<ArtMethod*> default_methods(allocator.Adapter()); MutableHandle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking())); ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod(); @@ -5055,7 +5116,9 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, for (size_t j = 0; j < num_virtuals; ++j) { auto method = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); DCHECK(method != nullptr) << PrettyClass(super_class); - if (method->IsMiranda()) { + // Miranda methods cannot be used to implement an interface method and defaults should be + // skipped in case we override it. + if (method->IsDefault() || method->IsMiranda()) { continue; } ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); @@ -5076,6 +5139,8 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); if (num_methods > 0) { const bool is_super = i < super_ifcount; + // This is an interface implemented by a super-class. Therefore we can just copy the method + // array from the superclass. const bool super_interface = is_super && extend_super_iftable; mirror::PointerArray* method_array; if (super_interface) { @@ -5119,16 +5184,13 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, input_vtable_array = vtable; input_array_length = input_vtable_array->GetLength(); } - if (input_array_length == 0) { - // If the added virtual methods is empty, do nothing. - DCHECK(super_interface); - continue; - } + // For each method in interface for (size_t j = 0; j < num_methods; ++j) { auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_); MethodNameAndSignatureComparator interface_name_comparator( interface_method->GetInterfaceMethodIfProxy(image_pointer_size_)); - int32_t k; + uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; + ArtMethod** imt_ptr = &out_imt[imt_index]; // For each method listed in the interface's method list, find the // matching method in our class's method list. We want to favor the // subclass over the superclass, which just requires walking @@ -5137,7 +5199,12 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, // it -- otherwise it would use the same vtable slot. In .dex files // those don't end up in the virtual method table, so it shouldn't // matter which direction we go. We walk it backward anyway.) - for (k = input_array_length - 1; k >= 0; --k) { + // + // To find defaults we need to do the same but also go over interfaces. + bool found_impl = false; + ArtMethod* default_impl = nullptr; + bool found_default_impl = false; + for (int32_t k = input_array_length - 1; k >= 0; --k) { ArtMethod* vtable_method = input_virtual_methods != nullptr ? &input_virtual_methods->At(k, method_size, method_alignment) : input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size_); @@ -5153,25 +5220,69 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, "Method '%s' implementing interface method '%s' is not public", PrettyMethod(vtable_method).c_str(), PrettyMethod(interface_method).c_str()); return false; + } else if (vtable_method->IsDefault()) { + // We might have a newer, better, default method for this, so we just skip it. If we + // are still using this we will select it again when scanning for default methods. To + // obviate the need to copy the method again we will make a note that we already found + // a default here. + // TODO This should be much cleaner. + found_default_impl = true; + default_impl = vtable_method; + break; + } else { + found_impl = true; } method_array->SetElementPtrSize(j, vtable_method, image_pointer_size_); // Place method in imt if entry is empty, place conflict otherwise. - uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; - auto** imt_ref = &out_imt[imt_index]; - if (*imt_ref == unimplemented_method) { - *imt_ref = vtable_method; - } else if (*imt_ref != conflict_method) { - // If we are not a conflict and we have the same signature and name as the imt entry, - // it must be that we overwrote a superclass vtable entry. - MethodNameAndSignatureComparator imt_comparator( - (*imt_ref)->GetInterfaceMethodIfProxy(image_pointer_size_)); - *imt_ref = imt_comparator.HasSameNameAndSignature(vtable_method_for_name_comparison) ? - vtable_method : conflict_method; - } + SetIMTRef(unimplemented_method, + conflict_method, + image_pointer_size_, + vtable_method, + /*out*/imt_ptr); break; } } - if (k < 0 && !super_interface) { + // We should only search for default implementations when the class does not implement the + // method directly and either (1) the interface is newly implemented on this class and not + // on any of its superclasses, (2) the superclass's implementation is a default method, or + // (3) the superclass does not have an implementation. + if (!found_impl && (!super_interface || + method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_) + ->IsOverridableByDefaultMethod())) { + ArtMethod* current_method = nullptr; + std::string icce_message; + if (!FindDefaultMethodImplementation(self, + interface_method, + klass, + /*out*/¤t_method, + /*out*/&icce_message)) { + // There was a conflict with default method implementations. + self->EndAssertNoThreadSuspension(old_cause); + // TODO This should actually be thrown when we attempt to invoke this method. + ThrowIncompatibleClassChangeError(klass.Get(), "%s", icce_message.c_str()); + return false; + } else if (current_method != nullptr) { + if (found_default_impl && + current_method->GetDeclaringClass() == default_impl->GetDeclaringClass()) { + // We found a default method but it was the same one we already have from our + // superclass. Don't bother adding it to our vtable again. + current_method = default_impl; + } else { + // We found a default method implementation and there were no conflicts. + // Save the default method. We need to add it to the vtable. + default_methods.push_back(current_method); + } + method_array->SetElementPtrSize(j, current_method, image_pointer_size_); + SetIMTRef(unimplemented_method, + conflict_method, + image_pointer_size_, + current_method, + /*out*/imt_ptr); + found_impl = true; + } + } + if (!found_impl && !super_interface) { + // It is defined in this class or any of its subclasses. ArtMethod* miranda_method = nullptr; for (auto& mir_method : miranda_methods) { if (interface_name_comparator.HasSameNameAndSignature(mir_method)) { @@ -5191,9 +5302,10 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, } } } - if (!miranda_methods.empty()) { + if (!miranda_methods.empty() || !default_methods.empty()) { const size_t old_method_count = klass->NumVirtualMethods(); - const size_t new_method_count = old_method_count + miranda_methods.size(); + const size_t new_method_count = + old_method_count + miranda_methods.size() + default_methods.size(); // Attempt to realloc to save RAM if possible. LengthPrefixedArray<ArtMethod>* old_virtuals = klass->GetVirtualMethodsPtr(); // The Realloced virtual methods aren't visiblef from the class roots, so there is no issue @@ -5228,13 +5340,36 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, ++out; } } - StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment) + old_method_count); + StrideIterator<ArtMethod> out(virtuals->Begin(method_size, method_alignment) + + old_method_count); // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and // we want the roots of the miranda methods to get visited. for (ArtMethod* mir_method : miranda_methods) { - out->CopyFrom(mir_method, image_pointer_size_); - out->SetAccessFlags(out->GetAccessFlags() | kAccMiranda); - move_table.emplace(mir_method, &*out); + ArtMethod& new_method = *out; + new_method.CopyFrom(mir_method, image_pointer_size_); + new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda); + DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u) + << "Miranda method should be abstract!"; + move_table.emplace(mir_method, &new_method); + ++out; + } + // We need to copy the default methods into our own virtual method table since the runtime + // requires that every method on a class's vtable be in that respective class's virtual method + // table. + // NOTE This means that two classes might have the same implementation of a method from the same + // interface but will have different ArtMethod*s for them. This also means we cannot compare a + // default method found on a class with one found on the declaring interface directly and must + // look at the declaring class to determine if they are the same. + for (ArtMethod* def_method : default_methods) { + ArtMethod& new_method = *out; + new_method.CopyFrom(def_method, image_pointer_size_); + new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccDefault); + // Clear the preverified flag if it is present. Since this class hasn't been verified yet it + // shouldn't have methods that are preverified. + // TODO This is rather arbitrary. We should maybe support classes where only some of its + // methods are preverified. + new_method.SetAccessFlags(new_method.GetAccessFlags() & ~kAccPreverified); + move_table.emplace(def_method, &new_method); ++out; } virtuals->SetLength(new_method_count); @@ -5244,7 +5379,8 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, self->EndAssertNoThreadSuspension(old_cause); const size_t old_vtable_count = vtable->GetLength(); - const size_t new_vtable_count = old_vtable_count + miranda_methods.size(); + const size_t new_vtable_count = + old_vtable_count + miranda_methods.size() + default_methods.size(); miranda_methods.clear(); vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count))); if (UNLIKELY(vtable.Get() == nullptr)) { @@ -5261,15 +5397,29 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, ++vtable_pos; } CHECK_EQ(vtable_pos, new_vtable_count); - // Update old vtable methods. + // Update old vtable methods. We use the default_translations map to figure out what each vtable + // entry should be updated to, if they need to be at all. for (size_t i = 0; i < old_vtable_count; ++i) { - auto* m = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_); - DCHECK(m != nullptr) << PrettyClass(klass.Get()); - auto it = move_table.find(m); + ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_); + // Try and find what we need to change this method to. + auto translation_it = default_translations.find(i); + bool found_translation = false; + if (translation_it != default_translations.end()) { + size_t vtable_index; + std::tie(vtable_index, translated_method) = *translation_it; + DCHECK_EQ(vtable_index, i); + found_translation = true; + } + DCHECK(translated_method != nullptr); + auto it = move_table.find(translated_method); if (it != move_table.end()) { - auto* new_m = it->second; - DCHECK(new_m != nullptr) << PrettyClass(klass.Get()); - vtable->SetElementPtrSize(i, new_m, image_pointer_size_); + auto* new_method = it->second; + DCHECK(new_method != nullptr); + vtable->SetElementPtrSize(i, new_method, image_pointer_size_); + } else { + // If it was not going to be updated we wouldn't have put it into the default_translations + // map. + CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail."; } } @@ -5300,7 +5450,11 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods(); for (size_t i = 0, count = klass->GetDexCache()->NumResolvedMethods(); i < count; ++i) { auto* m = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size_); - CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m); + // We don't remove default methods from the move table since we need them to update the + // vtable. Therefore just skip them for this check. + if (!m->IsDefault()) { + CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m); + } } } // Put some random garbage in old virtuals to help find stale pointers. @@ -6075,7 +6229,8 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { } bool ClassLinker::MayBeCalledWithDirectCodePointer(ArtMethod* m) { - if (Runtime::Current()->UseJit()) { + Runtime* const runtime = Runtime::Current(); + if (runtime->UseJit()) { // JIT can have direct code pointers from any method to any other method. return true; } @@ -6097,13 +6252,7 @@ bool ClassLinker::MayBeCalledWithDirectCodePointer(ArtMethod* m) { } else { // The method can be called outside its own oat file. Therefore it won't be called using its // direct code pointer only if all loaded oat files have been compiled in PIC mode. - ReaderMutexLock mu(Thread::Current(), dex_lock_); - for (const OatFile* oat_file : oat_files_) { - if (!oat_file->IsPic()) { - return true; - } - } - return false; + return runtime->GetOatFileManager().HaveNonPicOatFile(); } } @@ -6138,9 +6287,13 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi for (const DexFile* dex_file : dex_files) { StackHandleScope<3> hs2(self); - Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(self, 1)); + // CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the + // oat file but we can leave it null. + Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc( + self, + kDexFileIndexStart + 1)); DCHECK(h_long_array.Get() != nullptr); - h_long_array->Set(0, reinterpret_cast<intptr_t>(dex_file)); + h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file)); Handle<mirror::Object> h_dex_file = hs2.NewHandle( cookie_field->GetDeclaringClass()->AllocObject(self)); |