ART: Clean up ClassLinker
Try to clean up and simplify ClassLinker.
Move dex_lock to Locks. Remove dead code. Move single-use
code to user. Hide implementation details from header.
Test: m test-art-host
Change-Id: I58150fa9c2a9524f8304370270c2197d655cb3a8
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 6665f95..ce452cb 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -67,6 +67,7 @@
Uninterruptible Roles::uninterruptible_;
ReaderWriterMutex* Locks::jni_globals_lock_ = nullptr;
Mutex* Locks::jni_weak_globals_lock_ = nullptr;
+ReaderWriterMutex* Locks::dex_lock_ = nullptr;
struct AllMutexData {
// A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait).
@@ -961,6 +962,7 @@
DCHECK(thread_suspend_count_lock_ != nullptr);
DCHECK(trace_lock_ != nullptr);
DCHECK(unexpected_signal_lock_ != nullptr);
+ DCHECK(dex_lock_ != nullptr);
} else {
// Create global locks in level order from highest lock level to lowest.
LockLevel current_lock_level = kInstrumentEntrypointsLock;
@@ -1039,6 +1041,10 @@
modify_ldt_lock_ = new Mutex("modify_ldt lock", current_lock_level);
}
+ UPDATE_CURRENT_LOCK_LEVEL(kDexLock);
+ DCHECK(dex_lock_ == nullptr);
+ dex_lock_ = new ReaderWriterMutex("ClassLinker dex lock", current_lock_level);
+
UPDATE_CURRENT_LOCK_LEVEL(kOatFileManagerLock);
DCHECK(oat_file_manager_lock_ == nullptr);
oat_file_manager_lock_ = new ReaderWriterMutex("OatFile manager lock", current_lock_level);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 21b5bb9..255ad71 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -659,8 +659,10 @@
// Guards modification of the LDT on x86.
static Mutex* modify_ldt_lock_ ACQUIRED_AFTER(allocated_thread_ids_lock_);
+ static ReaderWriterMutex* dex_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
+
// Guards opened oat files in OatFileManager.
- static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
+ static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(dex_lock_);
// Guards extra string entries for VerifierDeps.
static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 7005c29..0a65cd1 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -248,7 +248,7 @@
DCHECK(proxy_method->IsProxyMethod<kReadBarrierOption>());
{
Thread* const self = Thread::Current();
- ReaderMutexLock mu(self, dex_lock_);
+ ReaderMutexLock mu(self, *Locks::dex_lock_);
// Locate the dex cache of the original interface/Object
for (const DexCacheData& data : dex_caches_) {
if (!self->IsJWeakCleared(data.weak_root) &&
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e9f5978..992d4bf 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -341,9 +341,7 @@
}
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),
@@ -1329,7 +1327,7 @@
}
}
{
- 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.
@@ -2144,109 +2142,6 @@
: 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) {
@@ -2273,9 +2168,14 @@
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();
}
@@ -3295,7 +3195,7 @@
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.
@@ -3337,7 +3237,7 @@
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();
@@ -3360,7 +3260,7 @@
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.
@@ -3376,7 +3276,12 @@
// 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());
@@ -3385,14 +3290,14 @@
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);
}
@@ -3429,7 +3334,7 @@
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(
@@ -3824,6 +3729,17 @@
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) {
{
@@ -3851,7 +3767,7 @@
// 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()) {
@@ -3870,7 +3786,7 @@
// 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;
}
}
@@ -4005,19 +3921,12 @@
// 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) {
@@ -4987,7 +4896,7 @@
bool can_init_parents) {
DCHECK(c.Get() != nullptr);
if (c->IsInitialized()) {
- EnsureSkipAccessChecksMethods(c);
+ EnsureSkipAccessChecksMethods(c, image_pointer_size_);
self->AssertNoPendingException();
return true;
}
@@ -8010,42 +7919,6 @@
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);
@@ -8065,9 +7938,12 @@
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);
}
@@ -8075,9 +7951,7 @@
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());
}
}
@@ -8128,7 +8002,7 @@
}
pid_t ClassLinker::GetDexLockOwner() {
- return dex_lock_.GetExclusiveOwnerTid();
+ return Locks::dex_lock_->GetExclusiveOwnerTid();
}
void ClassLinker::SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass) {
@@ -8294,20 +8168,6 @@
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;
@@ -8381,7 +8241,7 @@
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)) {
@@ -8450,7 +8310,7 @@
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);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 60755cd..de1f0f0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -140,12 +140,12 @@
bool InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path,
std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Initialize class linker from one or more boot images.
bool InitFromBootImage(std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Add an image space to the class linker, may fix up classloader fields and dex cache fields.
// The dex files that were newly opened for the space are placed in the out argument
@@ -158,13 +158,13 @@
const char* dex_location,
std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
std::string* error_msg)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
bool OpenImageDexFiles(gc::space::ImageSpace* space,
std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
std::string* error_msg)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Finds a class by its descriptor, loading it if necessary.
@@ -173,18 +173,18 @@
const char* descriptor,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Finds a class by its descriptor using the "system" class loader, ie by searching the
// boot_class_path_.
mirror::Class* FindSystemClass(Thread* self, const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Finds the array class given for the element class.
mirror::Class* FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Returns true if the class linker is initialized.
bool IsInitialized() const {
@@ -199,7 +199,7 @@
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Finds a class by its descriptor, returning null if it isn't wasn't loaded
// by the given 'class_loader'.
@@ -224,10 +224,6 @@
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void DumpAllClasses(int flags)
- REQUIRES(!Locks::classlinker_classes_lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_);
size_t NumLoadedClasses()
@@ -261,18 +257,18 @@
dex::TypeIndex type_idx,
ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Resolve a Type with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
// for the type, since it may be referenced from but not contained within the given DexFile.
@@ -291,7 +287,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError
// check should be performed even after a hit.
@@ -313,7 +309,7 @@
ArtMethod* referrer,
InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -325,17 +321,17 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
template <ResolveMode kResolveMode>
ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
ArtMethod* ResolveMethodWithoutInvokeType(const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
ArtField* GetResolvedField(uint32_t field_idx, ObjPtr<mirror::Class> field_declaring_class)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -343,7 +339,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Resolve a field with a given ID from the DexFile, storing the
// result in DexCache. The ClassLinker and ClassLoader are used as
@@ -354,7 +350,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Resolve a field with a given ID from the DexFile, storing the
// result in DexCache. The ClassLinker and ClassLoader are used as
@@ -365,7 +361,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Resolve a method type with a given ID from the DexFile, storing
// the result in the DexCache.
@@ -374,11 +370,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
-
- // Get shorty from method index without resolution. Used to do handlerization.
- const char* MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
@@ -388,20 +380,20 @@
bool can_init_fields,
bool can_init_parents)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Initializes classes that have instances in the image but that have
// <clinit> methods so they could not be initialized by the compiler.
void RunRootClinits()
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
mirror::DexCache* RegisterDexFile(const DexFile& dex_file,
ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
const std::vector<const DexFile*>& GetBootClassPath() {
@@ -418,22 +410,22 @@
// can race with insertion and deletion of classes while the visitor is being called.
void VisitClassesWithoutClassesLock(ClassVisitor* visitor)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
void VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags)
REQUIRES(!Locks::classlinker_classes_lock_, !Locks::trace_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
void VisitRoots(RootVisitor* visitor, VisitRootFlags flags)
- REQUIRES(!dex_lock_, !Locks::classlinker_classes_lock_, !Locks::trace_lock_)
+ REQUIRES(!Locks::dex_lock_, !Locks::classlinker_classes_lock_, !Locks::trace_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
mirror::DexCache* FindDexCache(Thread* self,
const DexFile& dex_file,
bool allow_failure = false)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
void FixupDexCaches(ArtMethod* resolution_method)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Allocate an instance of a java.lang.Object.
@@ -481,18 +473,18 @@
Handle<mirror::Class> klass,
verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file,
ObjPtr<mirror::Class> klass,
mirror::Class::Status& oat_file_class_status)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
void ResolveMethodExceptionHandlerTypes(ArtMethod* klass)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
jstring name,
@@ -505,7 +497,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
ArtMethod* FindMethodForProxy(ObjPtr<mirror::Class> proxy_class, ArtMethod* proxy_method)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the oat code for a method when its class isn't yet initialized.
@@ -568,7 +560,7 @@
// Note: the objects are not completely set up. Do not use this outside of tests and the compiler.
jobject CreatePathClassLoader(Thread* self, const std::vector<const DexFile*>& dex_files)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
PointerSize GetImagePointerSize() const {
return image_pointer_size_;
@@ -579,8 +571,6 @@
REQUIRES(Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* CreateRuntimeMethod(LinearAlloc* linear_alloc);
-
// Clear the ArrayClass cache. This is necessary when cleaning up for the image, as the cache
// entries are roots, but potentially not image classes.
void DropFindArrayClassCache() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -611,11 +601,11 @@
REQUIRES_SHARED(Locks::mutator_lock_);
std::set<DexCacheResolvedClasses> GetResolvedClasses(bool ignore_boot_classes)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
std::unordered_set<std::string> GetClassDescriptorsForProfileKeys(
const std::set<DexCacheResolvedClasses>& classes)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
ObjPtr<mirror::ClassLoader> class_loader)
@@ -650,7 +640,7 @@
// class.
void ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def = false)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Get the actual holding class for a copied method. Pretty slow, don't call often.
mirror::Class* GetHoldingClassOfCopiedMethod(ArtMethod* method)
@@ -680,7 +670,7 @@
bool AttemptSupertypeVerification(Thread* self,
Handle<mirror::Class> klass,
Handle<mirror::Class> supertype)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
static void DeleteClassLoader(Thread* self, const ClassLoaderData& data)
@@ -704,7 +694,7 @@
void FinishInit(Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// For early bootstrapping by Init
mirror::Class* AllocClass(Thread* self,
@@ -731,17 +721,9 @@
const DexFile& dex_file,
LinearAlloc* linear_alloc)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES(!Roles::uninterruptible_);
- void InitializeDexCache(Thread* self,
- ObjPtr<mirror::DexCache> dex_cache,
- ObjPtr<mirror::String> location,
- const DexFile& dex_file,
- LinearAlloc* linear_alloc)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(dex_lock_);
-
mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
@@ -755,14 +737,14 @@
size_t hash,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_, !Roles::uninterruptible_);
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Precomputes size needed for Class, in the case of a non-temporary class this size must be
// sufficient to hold all static fields.
@@ -810,7 +792,7 @@
Handle<mirror::ClassLoader> class_loader,
ObjPtr<mirror::Class>* result)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
// Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
// by the given 'class_loader'. Uses the provided hash for the descriptor.
@@ -822,10 +804,10 @@
REQUIRES_SHARED(Locks::mutator_lock_);
void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
- REQUIRES(dex_lock_)
+ REQUIRES(Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
mirror::DexCache* FindDexCacheLocked(Thread* self, const DexFile& dex_file, bool allow_failure)
- REQUIRES(dex_lock_)
+ REQUIRES(Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
bool InitializeClass(Thread* self,
@@ -833,12 +815,12 @@
bool can_run_clinit,
bool can_init_parents)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
bool InitializeDefaultInterfaceRecursive(Thread* self,
Handle<mirror::Class> klass,
bool can_run_clinit,
bool can_init_parents)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
bool WaitForInitializeClass(Handle<mirror::Class> klass,
Thread* self,
@@ -871,7 +853,7 @@
bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
bool LinkMethods(Thread* self,
Handle<mirror::Class> klass,
@@ -1037,17 +1019,11 @@
void CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const
REQUIRES_SHARED(Locks::mutator_lock_);
- // For use by ImageWriter to find DexCaches for its roots
- ReaderWriterMutex* DexLock()
- REQUIRES_SHARED(Locks::mutator_lock_)
- LOCK_RETURNED(dex_lock_) {
- return &dex_lock_;
- }
- size_t GetDexCacheCount() REQUIRES_SHARED(Locks::mutator_lock_, dex_lock_) {
+ size_t GetDexCacheCount() REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) {
return dex_caches_.size();
}
const std::list<DexCacheData>& GetDexCachesData()
- REQUIRES_SHARED(Locks::mutator_lock_, dex_lock_) {
+ REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) {
return dex_caches_;
}
@@ -1056,12 +1032,6 @@
void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out)
REQUIRES_SHARED(Locks::mutator_lock_);
- // 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.
- void EnsureSkipAccessChecksMethods(Handle<mirror::Class> c)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Register a class loader and create its class table and allocator. Should not be called if
// these are already created.
void RegisterClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
@@ -1086,7 +1056,7 @@
mirror::Class* EnsureResolved(Thread* self, const char* descriptor, ObjPtr<mirror::Class> klass)
WARN_UNUSED
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
+ REQUIRES(!Locks::dex_lock_);
void FixupTemporaryDeclaringClass(ObjPtr<mirror::Class> temp_class,
ObjPtr<mirror::Class> new_class)
@@ -1117,12 +1087,12 @@
ClassTable::ClassSet* new_class_set,
bool* out_forward_dex_cache_array,
std::string* out_error_msg)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Check that c1 == FindSystemClass(self, descriptor). Abort with class dumps otherwise.
void CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor)
- REQUIRES(!dex_lock_)
+ REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Sets imt_ref appropriately for LinkInterfaceMethods.
@@ -1153,10 +1123,9 @@
std::vector<const DexFile*> boot_class_path_;
std::vector<std::unique_ptr<const DexFile>> boot_dex_files_;
- mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
// JNI weak globals and side data to allow dex caches to get unloaded. We lazily delete weak
// globals when we register new dex files.
- std::list<DexCacheData> dex_caches_ GUARDED_BY(dex_lock_);
+ std::list<DexCacheData> dex_caches_ GUARDED_BY(Locks::dex_lock_);
// This contains the class loaders which have class tables. It is populated by
// InsertClassTableForClassLoader.
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7c06ffe..ddb9e59 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1319,7 +1319,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
{
- ReaderMutexLock mu(soa.Self(), *class_linker->DexLock());
+ ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_);
for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
dex_cache.Assign(soa.Self()->DecodeJObject(data.weak_root)->AsDexCache());
if (dex_cache.Get() != nullptr) {
@@ -1343,7 +1343,7 @@
0u,
nullptr));
{
- WriterMutexLock mu(soa.Self(), *class_linker->DexLock());
+ WriterMutexLock mu(soa.Self(), *Locks::dex_lock_);
// Check that inserting with a UTF16 name works.
class_linker->RegisterDexFileLocked(*dex_file, dex_cache);
}
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index a32d51f..741cf3b 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -22,15 +22,123 @@
#include "gc/accounting/card_table-inl.h"
#include "gc/heap.h"
#include "globals.h"
+#include "linear_alloc.h"
#include "object.h"
#include "object-inl.h"
#include "object_array-inl.h"
#include "runtime.h"
#include "string.h"
+#include "thread.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
namespace art {
namespace mirror {
+void DexCache::InitializeDexCache(Thread* self,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::String> location,
+ const DexFile* dex_file,
+ LinearAlloc* linear_alloc,
+ PointerSize image_pointer_size) {
+ DCHECK(dex_file != nullptr);
+ 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);
+}
+
void DexCache::Init(const DexFile* dex_file,
ObjPtr<String> location,
StringDexCacheType* strings,
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index cc4d01a..ec265e5 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -31,6 +31,8 @@
class DexFile;
class ImageWriter;
union JValue;
+class LinearAlloc;
+class Thread;
namespace mirror {
@@ -137,19 +139,14 @@
return sizeof(DexCache);
}
- void Init(const DexFile* dex_file,
- ObjPtr<String> location,
- StringDexCacheType* strings,
- uint32_t num_strings,
- GcRoot<Class>* resolved_types,
- uint32_t num_resolved_types,
- ArtMethod** resolved_methods,
- uint32_t num_resolved_methods,
- ArtField** resolved_fields,
- uint32_t num_resolved_fields,
- MethodTypeDexCacheType* resolved_methodtypes,
- uint32_t num_resolved_methodtypes,
- PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_);
+ static void InitializeDexCache(Thread* self,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::String> location,
+ const DexFile* dex_file,
+ LinearAlloc* linear_alloc,
+ PointerSize image_pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::dex_lock_);
void Fixup(ArtMethod* trampoline, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -339,6 +336,21 @@
static void SetElementPtrSize(PtrType* ptr_array, size_t idx, PtrType ptr, PointerSize ptr_size);
private:
+ void Init(const DexFile* dex_file,
+ ObjPtr<String> location,
+ StringDexCacheType* strings,
+ uint32_t num_strings,
+ GcRoot<Class>* resolved_types,
+ uint32_t num_resolved_types,
+ ArtMethod** resolved_methods,
+ uint32_t num_resolved_methods,
+ ArtField** resolved_fields,
+ uint32_t num_resolved_fields,
+ MethodTypeDexCacheType* resolved_methodtypes,
+ uint32_t num_resolved_methodtypes,
+ PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
// Visit instance fields of the dex cache as well as its associated arrays.
template <bool kVisitNativeRoots,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index adf35b6..67b2e1c 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -177,8 +177,22 @@
}
static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
+ class DumpClassVisitor : public ClassVisitor {
+ public:
+ explicit DumpClassVisitor(int dump_flags) : flags_(dump_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_;
+ };
+ DumpClassVisitor visitor(flags);
+
ScopedFastNativeObjectAccess soa(env);
- return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
+ return Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
}
static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 92e00ec..66bb803 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1736,9 +1736,24 @@
}
}
+static ArtMethod* CreateRuntimeMethod(ClassLinker* class_linker, LinearAlloc* linear_alloc) {
+ const PointerSize image_pointer_size = class_linker->GetImagePointerSize();
+ const size_t method_alignment = ArtMethod::Alignment(image_pointer_size);
+ const size_t method_size = ArtMethod::Size(image_pointer_size);
+ LengthPrefixedArray<ArtMethod>* method_array = class_linker->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;
+}
+
ArtMethod* Runtime::CreateImtConflictMethod(LinearAlloc* linear_alloc) {
ClassLinker* const class_linker = GetClassLinker();
- ArtMethod* method = class_linker->CreateRuntimeMethod(linear_alloc);
+ ArtMethod* method = CreateRuntimeMethod(class_linker, linear_alloc);
// When compiling, the code pointer will get set later when the image is loaded.
const PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_);
if (IsAotCompiler()) {
@@ -1759,7 +1774,7 @@
}
ArtMethod* Runtime::CreateResolutionMethod() {
- auto* method = GetClassLinker()->CreateRuntimeMethod(GetLinearAlloc());
+ auto* method = CreateRuntimeMethod(GetClassLinker(), GetLinearAlloc());
// When compiling, the code pointer will get set later when the image is loaded.
if (IsAotCompiler()) {
PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_);
@@ -1771,7 +1786,7 @@
}
ArtMethod* Runtime::CreateCalleeSaveMethod() {
- auto* method = GetClassLinker()->CreateRuntimeMethod(GetLinearAlloc());
+ auto* method = CreateRuntimeMethod(GetClassLinker(), GetLinearAlloc());
PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set_);
method->SetEntryPointFromQuickCompiledCodePtrSize(nullptr, pointer_size);
DCHECK_NE(instruction_set_, kNone);