diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 526 |
1 files changed, 215 insertions, 311 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0de647f509..674bad7a3c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -40,6 +40,7 @@ #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "base/value_object.h" +#include "cha.h" #include "class_linker-inl.h" #include "class_table-inl.h" #include "compiler_callbacks.h" @@ -96,6 +97,7 @@ #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" +#include "thread_list.h" #include "trace.h" #include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" @@ -240,10 +242,11 @@ static void WrapExceptionInInitializer(Handle<mirror::Class> klass) ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred()); CHECK(cause.get() != nullptr); - // Boot classpath classes should not fail initialization. - if (!Runtime::Current()->IsAotCompiler()) { + // Boot classpath classes should not fail initialization. This is a sanity debug check. This + // cannot in general be guaranteed, but in all likelihood leads to breakage down the line. + if (klass->GetClassLoader() == nullptr && !Runtime::Current()->IsAotCompiler()) { std::string tmp; - CHECK(klass->GetClassLoader() != nullptr) << klass->GetDescriptor(&tmp); + LOG(kIsDebugBuild ? FATAL : WARNING) << klass->GetDescriptor(&tmp) << " failed initialization"; } env->ExceptionClear(); @@ -339,9 +342,7 @@ static void ShuffleForward(size_t* current_field_idx, } ClassLinker::ClassLinker(InternTable* intern_table) - // dex_lock_ is recursive as it may be used in stack dumping. - : dex_lock_("ClassLinker dex lock", kDexLock), - failed_dex_cache_class_lookups_(0), + : failed_dex_cache_class_lookups_(0), class_roots_(nullptr), array_iftable_(nullptr), find_array_class_cache_next_victim_(0), @@ -820,123 +821,6 @@ void ClassLinker::RunRootClinits() { } } -static void SanityCheckArtMethod(ArtMethod* m, - ObjPtr<mirror::Class> expected_class, - const std::vector<gc::space::ImageSpace*>& spaces) - REQUIRES_SHARED(Locks::mutator_lock_) { - if (m->IsRuntimeMethod()) { - ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClassUnchecked(); - CHECK(declaring_class == nullptr) << declaring_class << " " << m->PrettyMethod(); - } else if (m->IsCopied()) { - CHECK(m->GetDeclaringClass() != nullptr) << m->PrettyMethod(); - } else if (expected_class != nullptr) { - CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << m->PrettyMethod(); - } - if (!spaces.empty()) { - bool contains = false; - for (gc::space::ImageSpace* space : spaces) { - auto& header = space->GetImageHeader(); - size_t offset = reinterpret_cast<uint8_t*>(m) - space->Begin(); - - const ImageSection& methods = header.GetMethodsSection(); - contains = contains || methods.Contains(offset); - - const ImageSection& runtime_methods = header.GetRuntimeMethodsSection(); - contains = contains || runtime_methods.Contains(offset); - } - CHECK(contains) << m << " not found"; - } -} - -static void SanityCheckArtMethodPointerArray(ObjPtr<mirror::PointerArray> arr, - ObjPtr<mirror::Class> expected_class, - PointerSize pointer_size, - const std::vector<gc::space::ImageSpace*>& spaces) - REQUIRES_SHARED(Locks::mutator_lock_) { - CHECK(arr != nullptr); - for (int32_t j = 0; j < arr->GetLength(); ++j) { - auto* method = arr->GetElementPtrSize<ArtMethod*>(j, pointer_size); - // expected_class == null means we are a dex cache. - if (expected_class != nullptr) { - CHECK(method != nullptr); - } - if (method != nullptr) { - SanityCheckArtMethod(method, expected_class, spaces); - } - } -} - -static void SanityCheckArtMethodPointerArray(ArtMethod** arr, - size_t size, - PointerSize pointer_size, - const std::vector<gc::space::ImageSpace*>& spaces) - REQUIRES_SHARED(Locks::mutator_lock_) { - CHECK_EQ(arr != nullptr, size != 0u); - if (arr != nullptr) { - bool contains = false; - for (auto space : spaces) { - auto offset = reinterpret_cast<uint8_t*>(arr) - space->Begin(); - if (space->GetImageHeader().GetImageSection( - ImageHeader::kSectionDexCacheArrays).Contains(offset)) { - contains = true; - break; - } - } - CHECK(contains); - } - for (size_t j = 0; j < size; ++j) { - ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size); - // expected_class == null means we are a dex cache. - if (method != nullptr) { - SanityCheckArtMethod(method, nullptr, spaces); - } - } -} - -static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED) - REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(obj != nullptr); - CHECK(obj->GetClass() != nullptr) << "Null class in object " << obj; - CHECK(obj->GetClass()->GetClass() != nullptr) << "Null class class " << obj; - if (obj->IsClass()) { - auto klass = obj->AsClass(); - for (ArtField& field : klass->GetIFields()) { - CHECK_EQ(field.GetDeclaringClass(), klass); - } - for (ArtField& field : klass->GetSFields()) { - CHECK_EQ(field.GetDeclaringClass(), klass); - } - auto* runtime = Runtime::Current(); - auto image_spaces = runtime->GetHeap()->GetBootImageSpaces(); - auto pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); - for (auto& m : klass->GetMethods(pointer_size)) { - SanityCheckArtMethod(&m, klass, image_spaces); - } - auto* vtable = klass->GetVTable(); - if (vtable != nullptr) { - SanityCheckArtMethodPointerArray(vtable, nullptr, pointer_size, image_spaces); - } - if (klass->ShouldHaveImt()) { - ImTable* imt = klass->GetImt(pointer_size); - for (size_t i = 0; i < ImTable::kSize; ++i) { - SanityCheckArtMethod(imt->Get(i, pointer_size), nullptr, image_spaces); - } - } - if (klass->ShouldHaveEmbeddedVTable()) { - for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { - SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr, image_spaces); - } - } - mirror::IfTable* iftable = klass->GetIfTable(); - for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { - if (iftable->GetMethodArrayCount(i) > 0) { - SanityCheckArtMethodPointerArray( - iftable->GetMethodArray(i), nullptr, pointer_size, image_spaces); - } - } - } -} - // Set image methods' entry point to interpreter. class SetInterpreterEntrypointArtMethodVisitor : public ArtMethodVisitor { public: @@ -1444,7 +1328,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } } { - WriterMutexLock mu2(self, dex_lock_); + WriterMutexLock mu2(self, *Locks::dex_lock_); // Make sure to do this after we update the arrays since we store the resolved types array // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the // BSS. @@ -1607,6 +1491,153 @@ bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space, return true; } +// Helper class for ArtMethod checks when adding an image. Keeps all required functionality +// together and caches some intermediate results. +class ImageSanityChecks FINAL { + public: + static void CheckObjects(gc::Heap* heap, ClassLinker* class_linker) + REQUIRES_SHARED(Locks::mutator_lock_) { + ImageSanityChecks isc(heap, class_linker); + heap->VisitObjects(ImageSanityChecks::SanityCheckObjectsCallback, &isc); + } + + static void CheckPointerArray(gc::Heap* heap, + ClassLinker* class_linker, + ArtMethod** arr, + size_t size) + REQUIRES_SHARED(Locks::mutator_lock_) { + ImageSanityChecks isc(heap, class_linker); + isc.SanityCheckArtMethodPointerArray(arr, size); + } + + static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(obj != nullptr); + CHECK(obj->GetClass() != nullptr) << "Null class in object " << obj; + CHECK(obj->GetClass()->GetClass() != nullptr) << "Null class class " << obj; + if (obj->IsClass()) { + ImageSanityChecks* isc = reinterpret_cast<ImageSanityChecks*>(arg); + + auto klass = obj->AsClass(); + for (ArtField& field : klass->GetIFields()) { + CHECK_EQ(field.GetDeclaringClass(), klass); + } + for (ArtField& field : klass->GetSFields()) { + CHECK_EQ(field.GetDeclaringClass(), klass); + } + const auto pointer_size = isc->pointer_size_; + for (auto& m : klass->GetMethods(pointer_size)) { + isc->SanityCheckArtMethod(&m, klass); + } + auto* vtable = klass->GetVTable(); + if (vtable != nullptr) { + isc->SanityCheckArtMethodPointerArray(vtable, nullptr); + } + if (klass->ShouldHaveImt()) { + ImTable* imt = klass->GetImt(pointer_size); + for (size_t i = 0; i < ImTable::kSize; ++i) { + isc->SanityCheckArtMethod(imt->Get(i, pointer_size), nullptr); + } + } + if (klass->ShouldHaveEmbeddedVTable()) { + for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { + isc->SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr); + } + } + mirror::IfTable* iftable = klass->GetIfTable(); + for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { + if (iftable->GetMethodArrayCount(i) > 0) { + isc->SanityCheckArtMethodPointerArray(iftable->GetMethodArray(i), nullptr); + } + } + } + } + + private: + ImageSanityChecks(gc::Heap* heap, ClassLinker* class_linker) + : spaces_(heap->GetBootImageSpaces()), + pointer_size_(class_linker->GetImagePointerSize()) { + space_begin_.reserve(spaces_.size()); + method_sections_.reserve(spaces_.size()); + runtime_method_sections_.reserve(spaces_.size()); + for (gc::space::ImageSpace* space : spaces_) { + space_begin_.push_back(space->Begin()); + auto& header = space->GetImageHeader(); + method_sections_.push_back(&header.GetMethodsSection()); + runtime_method_sections_.push_back(&header.GetRuntimeMethodsSection()); + } + } + + void SanityCheckArtMethod(ArtMethod* m, ObjPtr<mirror::Class> expected_class) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (m->IsRuntimeMethod()) { + ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClassUnchecked(); + CHECK(declaring_class == nullptr) << declaring_class << " " << m->PrettyMethod(); + } else if (m->IsCopied()) { + CHECK(m->GetDeclaringClass() != nullptr) << m->PrettyMethod(); + } else if (expected_class != nullptr) { + CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << m->PrettyMethod(); + } + if (!spaces_.empty()) { + bool contains = false; + for (size_t i = 0; !contains && i != space_begin_.size(); ++i) { + const size_t offset = reinterpret_cast<uint8_t*>(m) - space_begin_[i]; + contains = method_sections_[i]->Contains(offset) || + runtime_method_sections_[i]->Contains(offset); + } + CHECK(contains) << m << " not found"; + } + } + + void SanityCheckArtMethodPointerArray(ObjPtr<mirror::PointerArray> arr, + ObjPtr<mirror::Class> expected_class) + REQUIRES_SHARED(Locks::mutator_lock_) { + CHECK(arr != nullptr); + for (int32_t j = 0; j < arr->GetLength(); ++j) { + auto* method = arr->GetElementPtrSize<ArtMethod*>(j, pointer_size_); + // expected_class == null means we are a dex cache. + if (expected_class != nullptr) { + CHECK(method != nullptr); + } + if (method != nullptr) { + SanityCheckArtMethod(method, expected_class); + } + } + } + + void SanityCheckArtMethodPointerArray(ArtMethod** arr, size_t size) + REQUIRES_SHARED(Locks::mutator_lock_) { + CHECK_EQ(arr != nullptr, size != 0u); + if (arr != nullptr) { + bool contains = false; + for (auto space : spaces_) { + auto offset = reinterpret_cast<uint8_t*>(arr) - space->Begin(); + if (space->GetImageHeader().GetImageSection( + ImageHeader::kSectionDexCacheArrays).Contains(offset)) { + contains = true; + break; + } + } + CHECK(contains); + } + for (size_t j = 0; j < size; ++j) { + ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size_); + // expected_class == null means we are a dex cache. + if (method != nullptr) { + SanityCheckArtMethod(method, nullptr); + } + } + } + + const std::vector<gc::space::ImageSpace*>& spaces_; + const PointerSize pointer_size_; + + // Cached sections from the spaces. + std::vector<const uint8_t*> space_begin_; + std::vector<const ImageSection*> method_sections_; + std::vector<const ImageSection*> runtime_method_sections_; +}; + bool ClassLinker::AddImageSpace( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -1697,10 +1728,10 @@ bool ClassLinker::AddImageSpace( } } else { if (kSanityCheckObjects) { - SanityCheckArtMethodPointerArray(h_dex_cache->GetResolvedMethods(), - h_dex_cache->NumResolvedMethods(), - image_pointer_size_, - heap->GetBootImageSpaces()); + ImageSanityChecks::CheckPointerArray(heap, + this, + h_dex_cache->GetResolvedMethods(), + h_dex_cache->NumResolvedMethods()); } // Register dex files, keep track of existing ones that are conflicts. AppendToBootClassPath(*dex_file.get(), h_dex_cache); @@ -1785,7 +1816,7 @@ bool ClassLinker::AddImageSpace( } } if (!app_image) { - heap->VisitObjects(SanityCheckObjectsCallback, nullptr); + ImageSanityChecks::CheckObjects(heap, this); } } @@ -2112,109 +2143,6 @@ mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length : static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length))); } -void ClassLinker::InitializeDexCache(Thread* self, - ObjPtr<mirror::DexCache> dex_cache, - ObjPtr<mirror::String> location, - const DexFile& dex_file, - LinearAlloc* linear_alloc) { - ScopedAssertNoThreadSuspension sants(__FUNCTION__); - DexCacheArraysLayout layout(image_pointer_size_, &dex_file); - uint8_t* raw_arrays = nullptr; - - const OatDexFile* const oat_dex = dex_file.GetOatDexFile(); - if (oat_dex != nullptr && oat_dex->GetDexCacheArrays() != nullptr) { - raw_arrays = oat_dex->GetDexCacheArrays(); - } else if (dex_file.NumStringIds() != 0u || - dex_file.NumTypeIds() != 0u || - dex_file.NumMethodIds() != 0u || - dex_file.NumFieldIds() != 0u) { - // Zero-initialized. - raw_arrays = reinterpret_cast<uint8_t*>(linear_alloc->Alloc(self, layout.Size())); - } - - mirror::StringDexCacheType* strings = (dex_file.NumStringIds() == 0u) ? nullptr : - reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); - GcRoot<mirror::Class>* types = (dex_file.NumTypeIds() == 0u) ? nullptr : - reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); - ArtMethod** methods = (dex_file.NumMethodIds() == 0u) ? nullptr : - reinterpret_cast<ArtMethod**>(raw_arrays + layout.MethodsOffset()); - ArtField** fields = (dex_file.NumFieldIds() == 0u) ? nullptr : - reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset()); - - size_t num_strings = mirror::DexCache::kDexCacheStringCacheSize; - if (dex_file.NumStringIds() < num_strings) { - num_strings = dex_file.NumStringIds(); - } - - // Note that we allocate the method type dex caches regardless of this flag, - // and we make sure here that they're not used by the runtime. This is in the - // interest of simplicity and to avoid extensive compiler and layout class changes. - // - // If this needs to be mitigated in a production system running this code, - // DexCache::kDexCacheMethodTypeCacheSize can be set to zero. - mirror::MethodTypeDexCacheType* method_types = nullptr; - size_t num_method_types = 0; - - if (dex_file.NumProtoIds() < mirror::DexCache::kDexCacheMethodTypeCacheSize) { - num_method_types = dex_file.NumProtoIds(); - } else { - num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; - } - - if (num_method_types > 0) { - method_types = reinterpret_cast<mirror::MethodTypeDexCacheType*>( - raw_arrays + layout.MethodTypesOffset()); - } - - DCHECK_ALIGNED(raw_arrays, alignof(mirror::StringDexCacheType)) << - "Expected raw_arrays to align to StringDexCacheType."; - DCHECK_ALIGNED(layout.StringsOffset(), alignof(mirror::StringDexCacheType)) << - "Expected StringsOffset() to align to StringDexCacheType."; - DCHECK_ALIGNED(strings, alignof(mirror::StringDexCacheType)) << - "Expected strings to align to StringDexCacheType."; - static_assert(alignof(mirror::StringDexCacheType) == 8u, - "Expected StringDexCacheType to have align of 8."); - if (kIsDebugBuild) { - // Sanity check to make sure all the dex cache arrays are empty. b/28992179 - for (size_t i = 0; i < num_strings; ++i) { - CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u); - CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull()); - } - for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) { - CHECK(types[i].IsNull()); - } - for (size_t i = 0; i < dex_file.NumMethodIds(); ++i) { - CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size_) == nullptr); - } - for (size_t i = 0; i < dex_file.NumFieldIds(); ++i) { - CHECK(mirror::DexCache::GetElementPtrSize(fields, i, image_pointer_size_) == nullptr); - } - for (size_t i = 0; i < num_method_types; ++i) { - CHECK_EQ(method_types[i].load(std::memory_order_relaxed).index, 0u); - CHECK(method_types[i].load(std::memory_order_relaxed).object.IsNull()); - } - } - if (strings != nullptr) { - mirror::StringDexCachePair::Initialize(strings); - } - if (method_types != nullptr) { - mirror::MethodTypeDexCachePair::Initialize(method_types); - } - dex_cache->Init(&dex_file, - location, - strings, - num_strings, - types, - dex_file.NumTypeIds(), - methods, - dex_file.NumMethodIds(), - fields, - dex_file.NumFieldIds(), - method_types, - num_method_types, - image_pointer_size_); -} - mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr<mirror::String>* out_location, Thread* self, const DexFile& dex_file) { @@ -2241,9 +2169,14 @@ mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, ObjPtr<mirror::String> location = nullptr; ObjPtr<mirror::DexCache> dex_cache = AllocDexCache(&location, self, dex_file); if (dex_cache != nullptr) { - WriterMutexLock mu(self, dex_lock_); + WriterMutexLock mu(self, *Locks::dex_lock_); DCHECK(location != nullptr); - InitializeDexCache(self, dex_cache, location, dex_file, linear_alloc); + mirror::DexCache::InitializeDexCache(self, + dex_cache, + location, + &dex_file, + linear_alloc, + image_pointer_size_); } return dex_cache.Ptr(); } @@ -3263,7 +3196,7 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) { Thread* const self = Thread::Current(); - dex_lock_.AssertExclusiveHeld(self); + Locks::dex_lock_->AssertExclusiveHeld(self); CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); // For app images, the dex cache location may be a suffix of the dex file location since the // dex file location is an absolute path. @@ -3305,7 +3238,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, ObjPtr<mirror::ClassLoader> class_loader) { Thread* self = Thread::Current(); { - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { return dex_cache.Ptr(); @@ -3328,7 +3261,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, dex_file))); Handle<mirror::String> h_location(hs.NewHandle(location)); { - WriterMutexLock mu(self, dex_lock_); + WriterMutexLock mu(self, *Locks::dex_lock_); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { // Another thread managed to initialize the dex cache faster, so use that DexCache. @@ -3344,7 +3277,12 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, // Do InitializeDexCache while holding dex lock to make sure two threads don't call it at the // same time with the same dex cache. Since the .bss is shared this can cause failing DCHECK // that the arrays are null. - InitializeDexCache(self, h_dex_cache.Get(), h_location.Get(), dex_file, linear_alloc); + mirror::DexCache::InitializeDexCache(self, + h_dex_cache.Get(), + h_location.Get(), + &dex_file, + linear_alloc, + image_pointer_size_); RegisterDexFileLocked(dex_file, h_dex_cache); } table->InsertStrongRoot(h_dex_cache.Get()); @@ -3353,14 +3291,14 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, void ClassLinker::RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) { - WriterMutexLock mu(Thread::Current(), dex_lock_); + WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_); RegisterDexFileLocked(dex_file, dex_cache); } mirror::DexCache* ClassLinker::FindDexCache(Thread* self, const DexFile& dex_file, bool allow_failure) { - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); return FindDexCacheLocked(self, dex_file, allow_failure); } @@ -3397,7 +3335,7 @@ mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { Thread* const self = Thread::Current(); - ReaderMutexLock mu(self, dex_lock_); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const DexCacheData& data : dex_caches_) { if (!self->IsJWeakCleared(data.weak_root)) { ObjPtr<mirror::DexCache> dex_cache = ObjPtr<mirror::DexCache>::DownCast( @@ -3792,6 +3730,17 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, return false; } +// Ensures that methods have the kAccSkipAccessChecks bit set. We use the +// kAccVerificationAttempted bit on the class access flags to determine whether this has been done +// before. +static void EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass, PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (!klass->WasVerificationAttempted()) { + klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size); + klass->SetVerificationAttempted(); + } +} + verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( Thread* self, Handle<mirror::Class> klass, verifier::HardFailLogMode log_level) { { @@ -3819,7 +3768,7 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Don't attempt to re-verify if already sufficiently verified. if (klass->IsVerified()) { - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); return verifier::MethodVerifier::kNoFailure; } if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { @@ -3838,7 +3787,7 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); return verifier::MethodVerifier::kNoFailure; } } @@ -3973,19 +3922,12 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( // Mark the class as having a verification attempt to avoid re-running the verifier. klass->SetVerificationAttempted(); } else { - EnsureSkipAccessChecksMethods(klass); + EnsureSkipAccessChecksMethods(klass, image_pointer_size_); } } return verifier_failure; } -void ClassLinker::EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass) { - if (!klass->WasVerificationAttempted()) { - klass->SetSkipAccessChecksFlagOnAllMethods(image_pointer_size_); - klass->SetVerificationAttempted(); - } -} - bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, ObjPtr<mirror::Class> klass, mirror::Class::Status& oat_file_class_status) { @@ -4955,7 +4897,7 @@ bool ClassLinker::EnsureInitialized(Thread* self, bool can_init_parents) { DCHECK(c.Get() != nullptr); if (c->IsInitialized()) { - EnsureSkipAccessChecksMethods(c); + EnsureSkipAccessChecksMethods(c, image_pointer_size_); self->AssertNoPendingException(); return true; } @@ -5111,6 +5053,12 @@ bool ClassLinker::LinkClass(Thread* self, if (klass->ShouldHaveImt()) { klass->SetImt(imt, image_pointer_size_); } + + // Update CHA info based on whether we override methods. + // Have to do this before setting the class as resolved which allows + // instantiation of klass. + Runtime::Current()->GetClassHierarchyAnalysis()->UpdateAfterLoadingOf(klass); + // This will notify waiters on klass that saw the not yet resolved // class in the class_table_ during EnsureResolved. mirror::Class::SetStatus(klass, mirror::Class::kStatusResolved, self); @@ -5154,6 +5102,11 @@ bool ClassLinker::LinkClass(Thread* self, } } + // Update CHA info based on whether we override methods. + // Have to do this before setting the class as resolved which allows + // instantiation of klass. + Runtime::Current()->GetClassHierarchyAnalysis()->UpdateAfterLoadingOf(h_new_class); + // This will notify waiters on temp class that saw the not yet resolved class in the // class_table_ during EnsureResolved. mirror::Class::SetStatus(klass, mirror::Class::kStatusRetired, self); @@ -7967,42 +7920,6 @@ mirror::MethodType* ClassLinker::ResolveMethodType(const DexFile& dex_file, return type.Get(); } -const char* ClassLinker::MethodShorty(uint32_t method_idx, - ArtMethod* referrer, - uint32_t* length) { - ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass(); - ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache(); - const DexFile& dex_file = *dex_cache->GetDexFile(); - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - return dex_file.GetMethodShorty(method_id, length); -} - -class DumpClassVisitor : public ClassVisitor { - public: - explicit DumpClassVisitor(int flags) : flags_(flags) {} - - bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - klass->DumpClass(LOG_STREAM(ERROR), flags_); - return true; - } - - private: - const int flags_; -}; - -void ClassLinker::DumpAllClasses(int flags) { - DumpClassVisitor visitor(flags); - VisitClasses(&visitor); -} - -static OatFile::OatMethod CreateOatMethod(const void* code) { - CHECK(code != nullptr); - const uint8_t* base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code. - base -= sizeof(void*); // Move backward so that code_offset != 0. - const uint32_t code_offset = sizeof(void*); - return OatFile::OatMethod(base, code_offset); -} - bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const { return (entry_point == GetQuickResolutionStub()) || (quick_resolution_trampoline_ == entry_point); @@ -8022,9 +7939,12 @@ const void* ClassLinker::GetRuntimeQuickGenericJniStub() const { return GetQuickGenericJniStub(); } -void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, - const void* method_code) const { - OatFile::OatMethod oat_method = CreateOatMethod(method_code); +void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, const void* code) const { + CHECK(code != nullptr); + const uint8_t* base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code. + base -= sizeof(void*); // Move backward so that code_offset != 0. + const uint32_t code_offset = sizeof(void*); + OatFile::OatMethod oat_method(base, code_offset); oat_method.LinkMethod(method); } @@ -8032,9 +7952,7 @@ void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const { if (!method->IsNative()) { method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); } else { - const void* quick_method_code = GetQuickGenericJniStub(); - OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code); - oat_method.LinkMethod(method); + SetEntryPointsToCompiledCode(method, GetQuickGenericJniStub()); } } @@ -8085,7 +8003,7 @@ pid_t ClassLinker::GetClassesLockOwner() { } pid_t ClassLinker::GetDexLockOwner() { - return dex_lock_.GetExclusiveOwnerTid(); + return Locks::dex_lock_->GetExclusiveOwnerTid(); } void ClassLinker::SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass) { @@ -8251,20 +8169,6 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, return soa.Env()->NewGlobalRef(local_ref.get()); } -ArtMethod* ClassLinker::CreateRuntimeMethod(LinearAlloc* linear_alloc) { - const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); - const size_t method_size = ArtMethod::Size(image_pointer_size_); - LengthPrefixedArray<ArtMethod>* method_array = AllocArtMethodArray( - Thread::Current(), - linear_alloc, - 1); - ArtMethod* method = &method_array->At(0, method_size, method_alignment); - CHECK(method != nullptr); - method->SetDexMethodIndex(DexFile::kDexNoIndex); - CHECK(method->IsRuntimeMethod()); - return method; -} - void ClassLinker::DropFindArrayClassCache() { std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot<mirror::Class>(nullptr)); find_array_class_cache_next_victim_ = 0; @@ -8338,7 +8242,7 @@ std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_bo std::set<DexCacheResolvedClasses> ret; VLOG(class_linker) << "Collecting resolved classes"; const uint64_t start_time = NanoTime(); - ReaderMutexLock mu(soa.Self(), *DexLock()); + ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_); // Loop through all the dex caches and inspect resolved classes. for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (soa.Self()->IsJWeakCleared(data.weak_root)) { @@ -8407,7 +8311,7 @@ std::unordered_set<std::string> ClassLinker::GetClassDescriptorsForProfileKeys( std::unordered_map<std::string, const DexFile*> location_to_dex_file; ScopedObjectAccess soa(self); ScopedAssertNoThreadSuspension ants(__FUNCTION__); - ReaderMutexLock mu(self, *DexLock()); + ReaderMutexLock mu(self, *Locks::dex_lock_); for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { if (!self->IsJWeakCleared(data.weak_root)) { ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); |