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/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);