summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc526
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);