Fix dex cache resolved types and class table mismatch.
Record class table in ClassLinker::DexCacheData and use
it in DexCache.setResolvedType() to store the type also
in the initiating loader's class table if the dex file
has been registered.
Also throw InternalError when trying to register the
same DexFile with multiple class loaders. (Different
DexFile instances referencing the same file are OK.)
Test: 155-java-set-resolved-type
Test: m test-art-host
Bug: 30627598
Bug: 34193123
Bug: 34839984
Change-Id: Ia48acb300337c45880ea1459d2d32789546d67f4
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index edd6e3b..27ad0d9 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1322,16 +1322,8 @@
// 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.
- ObjPtr<mirror::DexCache> existing_dex_cache = FindDexCacheLocked(self,
- *dex_file,
- /*allow_failure*/true);
- CHECK(existing_dex_cache == nullptr);
- StackHandleScope<1> hs3(self);
- Handle<mirror::DexCache> h_dex_cache = hs3.NewHandle(dex_cache);
- RegisterDexFileLocked(*dex_file, h_dex_cache);
- if (kIsDebugBuild) {
- dex_cache.Assign(h_dex_cache.Get()); // Update dex_cache, used below in debug build.
- }
+ CHECK(!FindDexCacheDataLocked(*dex_file).IsValid());
+ RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get());
}
if (kIsDebugBuild) {
CHECK(new_class_set != nullptr);
@@ -1675,11 +1667,9 @@
return false;
}
- StackHandleScope<1> hs2(self);
- MutableHandle<mirror::DexCache> h_dex_cache(hs2.NewHandle<mirror::DexCache>(nullptr));
for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- h_dex_cache.Assign(dex_caches->Get(i));
- std::string dex_file_location(h_dex_cache->GetLocation()->ToModifiedUtf8());
+ ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
// TODO: Only store qualified paths.
// If non qualified, qualify it.
if (dex_file_location.find('/') == std::string::npos) {
@@ -1699,9 +1689,9 @@
if (app_image) {
// The current dex file field is bogus, overwrite it so that we can get the dex file in the
// loop below.
- h_dex_cache->SetDexFile(dex_file.get());
- GcRoot<mirror::Class>* const types = h_dex_cache->GetResolvedTypes();
- for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) {
+ dex_cache->SetDexFile(dex_file.get());
+ GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes();
+ for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) {
ObjPtr<mirror::Class> klass = types[j].Read();
if (klass != nullptr) {
DCHECK(!klass->IsErroneous()) << klass->GetStatus();
@@ -1711,11 +1701,11 @@
if (kSanityCheckObjects) {
ImageSanityChecks::CheckPointerArray(heap,
this,
- h_dex_cache->GetResolvedMethods(),
- h_dex_cache->NumResolvedMethods());
+ dex_cache->GetResolvedMethods(),
+ dex_cache->NumResolvedMethods());
}
// Register dex files, keep track of existing ones that are conflicts.
- AppendToBootClassPath(*dex_file.get(), h_dex_cache);
+ AppendToBootClassPath(*dex_file.get(), dex_cache);
}
out_dex_files->push_back(std::move(dex_file));
}
@@ -2656,7 +2646,7 @@
}
ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());
if (dex_cache == nullptr) {
- self->AssertPendingOOMException();
+ self->AssertPendingException();
return nullptr;
}
klass->SetDexCache(dex_cache);
@@ -3264,28 +3254,27 @@
}
void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) {
- StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocAndInitializeDexCache(
+ ObjPtr<mirror::DexCache> dex_cache = AllocAndInitializeDexCache(
self,
dex_file,
- Runtime::Current()->GetLinearAlloc())));
- CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
- << dex_file.GetLocation();
+ Runtime::Current()->GetLinearAlloc());
+ CHECK(dex_cache != nullptr) << "Failed to allocate dex cache for " << dex_file.GetLocation();
AppendToBootClassPath(dex_file, dex_cache);
}
void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache) {
- CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
+ ObjPtr<mirror::DexCache> dex_cache) {
+ CHECK(dex_cache != nullptr) << dex_file.GetLocation();
boot_class_path_.push_back(&dex_file);
- RegisterDexFile(dex_file, dex_cache);
+ RegisterBootClassPathDexFile(dex_file, dex_cache);
}
void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache) {
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader) {
Thread* const self = Thread::Current();
Locks::dex_lock_->AssertExclusiveHeld(self);
- CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
+ CHECK(dex_cache != 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.
const std::string dex_cache_location = dex_cache->GetLocation()->ToModifiedUtf8();
@@ -3313,25 +3302,49 @@
++it;
}
}
- jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache.Get());
+ jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache);
dex_cache->SetDexFile(&dex_file);
DexCacheData data;
data.weak_root = dex_cache_jweak;
data.dex_file = dex_cache->GetDexFile();
data.resolved_methods = dex_cache->GetResolvedMethods();
+ data.class_table = ClassTableForClassLoader(class_loader);
+ DCHECK(data.class_table != nullptr);
dex_caches_.push_back(data);
}
-mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file,
- ObjPtr<mirror::ClassLoader> class_loader) {
+ObjPtr<mirror::DexCache> ClassLinker::DecodeDexCache(Thread* self, const DexCacheData& data) {
+ return data.IsValid()
+ ? ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root))
+ : nullptr;
+}
+
+ObjPtr<mirror::DexCache> ClassLinker::EnsureSameClassLoader(
+ Thread* self,
+ ObjPtr<mirror::DexCache> dex_cache,
+ const DexCacheData& data,
+ ObjPtr<mirror::ClassLoader> class_loader) {
+ DCHECK_EQ(dex_cache->GetDexFile(), data.dex_file);
+ if (data.class_table != ClassTableForClassLoader(class_loader)) {
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
+ "Attempt to register dex file %s with multiple class loaders",
+ data.dex_file->GetLocation().c_str());
+ return nullptr;
+ }
+ return dex_cache;
+}
+
+ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file,
+ ObjPtr<mirror::ClassLoader> class_loader) {
Thread* self = Thread::Current();
+ DexCacheData old_data;
{
ReaderMutexLock mu(self, *Locks::dex_lock_);
- ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true);
- if (dex_cache != nullptr) {
- // TODO: Check if the dex file was registered with the same class loader. Bug: 34193123
- return dex_cache.Ptr();
- }
+ old_data = FindDexCacheDataLocked(dex_file);
+ }
+ ObjPtr<mirror::DexCache> old_dex_cache = DecodeDexCache(self, old_data);
+ if (old_dex_cache != nullptr) {
+ return EnsureSameClassLoader(self, old_dex_cache, old_data, class_loader);
}
LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader);
DCHECK(linear_alloc != nullptr);
@@ -3343,7 +3356,8 @@
// Don't alloc while holding the lock, since allocation may need to
// suspend all threads and another thread may need the dex_lock_ to
// get to a suspend point.
- StackHandleScope<2> hs(self);
+ StackHandleScope<3> hs(self);
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
ObjPtr<mirror::String> location;
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(/*out*/&location,
self,
@@ -3351,77 +3365,94 @@
Handle<mirror::String> h_location(hs.NewHandle(location));
{
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.
- // If this thread encountered OOME, ignore it.
- DCHECK_EQ(h_dex_cache.Get() == nullptr, self->IsExceptionPending());
- self->ClearException();
- return dex_cache.Ptr();
+ old_data = FindDexCacheDataLocked(dex_file);
+ old_dex_cache = DecodeDexCache(self, old_data);
+ if (old_dex_cache == nullptr && h_dex_cache.Get() != nullptr) {
+ // 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.
+ mirror::DexCache::InitializeDexCache(self,
+ h_dex_cache.Get(),
+ h_location.Get(),
+ &dex_file,
+ linear_alloc,
+ image_pointer_size_);
+ RegisterDexFileLocked(dex_file, h_dex_cache.Get(), h_class_loader.Get());
}
- if (h_dex_cache.Get() == nullptr) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- // 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.
- mirror::DexCache::InitializeDexCache(self,
- h_dex_cache.Get(),
- h_location.Get(),
- &dex_file,
- linear_alloc,
- image_pointer_size_);
- RegisterDexFileLocked(dex_file, h_dex_cache);
+ }
+ if (old_dex_cache != nullptr) {
+ // Another thread managed to initialize the dex cache faster, so use that DexCache.
+ // If this thread encountered OOME, ignore it.
+ DCHECK_EQ(h_dex_cache.Get() == nullptr, self->IsExceptionPending());
+ self->ClearException();
+ // We cannot call EnsureSameClassLoader() while holding the dex_lock_.
+ return EnsureSameClassLoader(self, old_dex_cache, old_data, h_class_loader.Get());
+ }
+ if (h_dex_cache.Get() == nullptr) {
+ self->AssertPendingOOMException();
+ return nullptr;
}
table->InsertStrongRoot(h_dex_cache.Get());
return h_dex_cache.Get();
}
-void ClassLinker::RegisterDexFile(const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache) {
+void ClassLinker::RegisterBootClassPathDexFile(const DexFile& dex_file,
+ ObjPtr<mirror::DexCache> dex_cache) {
WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_);
- RegisterDexFileLocked(dex_file, dex_cache);
+ RegisterDexFileLocked(dex_file, dex_cache, /* class_loader */ nullptr);
}
-mirror::DexCache* ClassLinker::FindDexCache(Thread* self,
- const DexFile& dex_file,
- bool allow_failure) {
+bool ClassLinker::IsDexFileRegistered(Thread* self, const DexFile& dex_file) {
ReaderMutexLock mu(self, *Locks::dex_lock_);
- return FindDexCacheLocked(self, dex_file, allow_failure);
+ return DecodeDexCache(self, FindDexCacheDataLocked(dex_file)) != nullptr;
}
-mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self,
- const DexFile& dex_file,
- bool allow_failure) {
- // Search assuming unique-ness of dex file.
- for (const DexCacheData& data : dex_caches_) {
- // Avoid decoding (and read barriers) other unrelated dex caches.
- if (data.dex_file == &dex_file) {
- ObjPtr<mirror::DexCache> dex_cache =
- ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
- if (dex_cache != nullptr) {
- return dex_cache.Ptr();
- }
- break;
- }
+ObjPtr<mirror::DexCache> ClassLinker::FindDexCache(Thread* self, const DexFile& dex_file) {
+ ReaderMutexLock mu(self, *Locks::dex_lock_);
+ ObjPtr<mirror::DexCache> dex_cache = DecodeDexCache(self, FindDexCacheDataLocked(dex_file));
+ if (dex_cache != nullptr) {
+ return dex_cache;
}
- if (allow_failure) {
- return nullptr;
- }
- std::string location(dex_file.GetLocation());
// Failure, dump diagnostic and abort.
+ std::string location(dex_file.GetLocation());
for (const DexCacheData& data : dex_caches_) {
- ObjPtr<mirror::DexCache> dex_cache =
- ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
- if (dex_cache != nullptr) {
- LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation();
+ if (DecodeDexCache(self, data) != nullptr) {
+ LOG(ERROR) << "Registered dex file " << data.dex_file->GetLocation();
}
}
LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
UNREACHABLE();
}
+ClassTable* ClassLinker::FindClassTable(Thread* self, ObjPtr<mirror::DexCache> dex_cache) {
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ DCHECK(dex_file != nullptr);
+ ReaderMutexLock mu(self, *Locks::dex_lock_);
+ // Search assuming unique-ness of dex file.
+ for (const DexCacheData& data : dex_caches_) {
+ // Avoid decoding (and read barriers) other unrelated dex caches.
+ if (data.dex_file == dex_file) {
+ ObjPtr<mirror::DexCache> registered_dex_cache = DecodeDexCache(self, data);
+ if (registered_dex_cache != nullptr) {
+ CHECK_EQ(registered_dex_cache, dex_cache) << dex_file->GetLocation();
+ return data.class_table;
+ }
+ }
+ }
+ return nullptr;
+}
+
+ClassLinker::DexCacheData ClassLinker::FindDexCacheDataLocked(const DexFile& dex_file) {
+ // Search assuming unique-ness of dex file.
+ for (const DexCacheData& data : dex_caches_) {
+ // Avoid decoding (and read barriers) other unrelated dex caches.
+ if (data.dex_file == &dex_file) {
+ return data;
+ }
+ }
+ return DexCacheData();
+}
+
void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) {
Thread* const self = Thread::Current();
ReaderMutexLock mu(self, *Locks::dex_lock_);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 5042fb7..62d3c29 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -382,11 +382,11 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- mirror::DexCache* RegisterDexFile(const DexFile& dex_file,
- ObjPtr<mirror::ClassLoader> class_loader)
+ ObjPtr<mirror::DexCache> RegisterDexFile(const DexFile& dex_file,
+ ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
+ void RegisterBootClassPathDexFile(const DexFile& dex_file, ObjPtr<mirror::DexCache> dex_cache)
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -413,9 +413,13 @@
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)
+ bool IsDexFileRegistered(Thread* self, const DexFile& dex_file)
+ REQUIRES(!Locks::dex_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::DexCache> FindDexCache(Thread* self, const DexFile& dex_file)
+ REQUIRES(!Locks::dex_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ ClassTable* FindClassTable(Thread* self, ObjPtr<mirror::DexCache> dex_cache)
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
void FixupDexCaches(ArtMethod* resolution_method)
@@ -655,6 +659,18 @@
REQUIRES(!Locks::dex_lock_);
struct DexCacheData {
+ // Construct an invalid data object.
+ DexCacheData()
+ : weak_root(nullptr),
+ dex_file(nullptr),
+ resolved_methods(nullptr),
+ class_table(nullptr) { }
+
+ // Check if the data is valid.
+ bool IsValid() const {
+ return dex_file != nullptr;
+ }
+
// Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may
// not work properly.
jweak weak_root;
@@ -663,6 +679,11 @@
// class unloading.)
const DexFile* dex_file;
ArtMethod** resolved_methods;
+ // Identify the associated class loader's class table. This is used to make sure that
+ // the Java call to native DexCache.setResolvedType() inserts the resolved type in that
+ // class table. It is also used to make sure we don't register the same dex cache with
+ // multiple class loaders.
+ ClassTable* class_table;
};
private:
@@ -749,7 +770,7 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
- void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
+ void AppendToBootClassPath(const DexFile& dex_file, ObjPtr<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
@@ -810,12 +831,24 @@
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
+ void RegisterDexFileLocked(const DexFile& dex_file,
+ ObjPtr<mirror::DexCache> dex_cache,
+ ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES(Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- mirror::DexCache* FindDexCacheLocked(Thread* self, const DexFile& dex_file, bool allow_failure)
+ DexCacheData FindDexCacheDataLocked(const DexFile& dex_file)
REQUIRES(Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ static ObjPtr<mirror::DexCache> DecodeDexCache(Thread* self, const DexCacheData& data)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ // Called to ensure that the dex cache has been registered with the same class loader.
+ // If yes, returns the dex cache, otherwise throws InternalError and returns null.
+ ObjPtr<mirror::DexCache> EnsureSameClassLoader(Thread* self,
+ ObjPtr<mirror::DexCache> dex_cache,
+ const DexCacheData& data,
+ ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES(!Locks::dex_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
bool InitializeClass(Thread* self,
Handle<mirror::Class> klass,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 17510bb..03105cb 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -439,7 +439,7 @@
TestRootVisitor visitor;
class_linker_->VisitRoots(&visitor, kVisitRootFlagAllRoots);
// Verify the dex cache has resolution methods in all resolved method slots
- mirror::DexCache* dex_cache = class_linker_->FindDexCache(Thread::Current(), dex);
+ ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), dex);
auto* resolved_methods = dex_cache->GetResolvedMethods();
for (size_t i = 0, num_methods = dex_cache->NumResolvedMethods(); i != num_methods; ++i) {
EXPECT_TRUE(
@@ -1454,7 +1454,7 @@
{
WriterMutexLock mu(soa.Self(), *Locks::dex_lock_);
// Check that inserting with a UTF16 name works.
- class_linker->RegisterDexFileLocked(*dex_file, dex_cache);
+ class_linker->RegisterDexFileLocked(*dex_file, dex_cache.Get(), /* class_loader */ nullptr);
}
}
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index ff846a7..1f9dc8c 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -123,6 +123,19 @@
return nullptr;
}
+ObjPtr<mirror::Class> ClassTable::TryInsert(ObjPtr<mirror::Class> klass) {
+ TableSlot slot(klass);
+ WriterMutexLock mu(Thread::Current(), lock_);
+ for (ClassSet& class_set : classes_) {
+ auto it = class_set.Find(slot);
+ if (it != class_set.end()) {
+ return it->Read();
+ }
+ }
+ classes_.back().Insert(slot);
+ return klass;
+}
+
void ClassTable::Insert(ObjPtr<mirror::Class> klass) {
const uint32_t hash = TableSlot::HashDescriptor(klass);
WriterMutexLock mu(Thread::Current(), lock_);
diff --git a/runtime/class_table.h b/runtime/class_table.h
index c8ec28e..711eae4 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -192,6 +192,12 @@
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Try to insert a class and return the inserted class if successful. If another class
+ // with the same descriptor is already in the table, return the existing entry.
+ ObjPtr<mirror::Class> TryInsert(ObjPtr<mirror::Class> klass)
+ REQUIRES(!lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
void Insert(ObjPtr<mirror::Class> klass)
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index cd0e55f..1234933 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -188,7 +188,7 @@
if (array == nullptr) {
ScopedObjectAccess soa(env);
for (auto& dex_file : dex_files) {
- if (linker->FindDexCache(soa.Self(), *dex_file, true) != nullptr) {
+ if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) {
dex_file.release();
}
}
@@ -230,7 +230,7 @@
if (dex_file != nullptr) {
// Only delete the dex file if the dex cache is not found to prevent runtime crashes if there
// are calls to DexFile.close while the ART DexFile is still in use.
- if (class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr) {
+ if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) {
// Clear the element in the array so that we can call close again.
long_dex_files->Set(i, 0);
delete dex_file;
@@ -281,7 +281,13 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
- class_linker->RegisterDexFile(*dex_file, class_loader.Get());
+ ObjPtr<mirror::DexCache> dex_cache =
+ class_linker->RegisterDexFile(*dex_file, class_loader.Get());
+ if (dex_cache == nullptr) {
+ // OOME or InternalError (dexFile already registered with a different class loader).
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),
descriptor.c_str(),
hash,
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index 981be68..0795960 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -128,7 +128,7 @@
if (kIsDebugBuild) {
ScopedObjectAccess soa(env);
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- CHECK(class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr);
+ CHECK(!class_linker->IsDexFileRegistered(soa.Self(), *dex_file));
}
delete dex_file;
}
@@ -153,7 +153,13 @@
StackHandleScope<1> handle_scope(soa.Self());
Handle<mirror::ClassLoader> class_loader(
handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
- class_linker->RegisterDexFile(*dex_file, class_loader.Get());
+ ObjPtr<mirror::DexCache> dex_cache =
+ class_linker->RegisterDexFile(*dex_file, class_loader.Get());
+ if (dex_cache == nullptr) {
+ // OOME or InternalError (dexFile already registered with a different class loader).
+ soa.Self()->AssertPendingException();
+ return nullptr;
+ }
ObjPtr<mirror::Class> result = class_linker->DefineClass(
soa.Self(),
class_descriptor,
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 1af8619..24308d9 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -448,11 +448,8 @@
Thread* const self = Thread::Current();
for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
CHECK(dex_file != nullptr);
- ObjPtr<mirror::DexCache> const dex_cache = class_linker->FindDexCache(self, *dex_file, true);
- // If dex cache was deallocated, just continue.
- if (dex_cache == nullptr) {
- continue;
- }
+ ObjPtr<mirror::DexCache> const dex_cache = class_linker->FindDexCache(self, *dex_file);
+ CHECK(dex_cache != nullptr); // Boot class path dex caches are never unloaded.
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
ObjPtr<mirror::String> string = dex_cache->GetResolvedString(dex::StringIndex(j));
if (string != nullptr) {
@@ -515,7 +512,7 @@
CHECK(dex_file != nullptr);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->RegisterDexFile(*dex_file, nullptr)));
-
+ CHECK(dex_cache.Get() != nullptr); // Boot class path dex caches are never unloaded.
if (kPreloadDexCachesStrings) {
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
PreloadDexCachesResolveString(dex_cache, dex::StringIndex(j), strings);
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index f1c350f..b1ed74a 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -65,12 +65,22 @@
dex_cache->GetResolvedString(dex::StringIndex(string_index)));
}
-static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index,
+static void DexCache_setResolvedType(JNIEnv* env,
+ jobject javaDexCache,
+ jint type_index,
jobject type) {
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
- CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- dex_cache->SetResolvedType(dex::TypeIndex(type_index), soa.Decode<mirror::Class>(type));
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ CHECK_LT(static_cast<size_t>(type_index), dex_file.NumTypeIds());
+ ObjPtr<mirror::Class> t = soa.Decode<mirror::Class>(type);
+ if (t != nullptr && t->DescriptorEquals(dex_file.StringByTypeIdx(dex::TypeIndex(type_index)))) {
+ ClassTable* table =
+ Runtime::Current()->GetClassLinker()->FindClassTable(soa.Self(), dex_cache);
+ if (table != nullptr && table->TryInsert(t) == t) {
+ dex_cache->SetResolvedType(dex::TypeIndex(type_index), t);
+ }
+ }
}
static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
@@ -78,7 +88,10 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
- dex_cache->SetResolvedString(dex::StringIndex(string_index), soa.Decode<mirror::String>(string));
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(string);
+ if (s != nullptr) {
+ dex_cache->SetResolvedString(dex::StringIndex(string_index), s);
+ }
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 4b8108a..dace216 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -378,7 +378,7 @@
art::mirror::DexCache* Redefiner::ClassRedefinition::CreateNewDexCache(
art::Handle<art::mirror::ClassLoader> loader) {
- return driver_->runtime_->GetClassLinker()->RegisterDexFile(*dex_file_, loader.Get());
+ return driver_->runtime_->GetClassLinker()->RegisterDexFile(*dex_file_, loader.Get()).Ptr();
}
void Redefiner::RecordFailure(jvmtiError result,
@@ -732,7 +732,7 @@
}
holder->SetNewDexCache(klass_index, CreateNewDexCache(loader));
if (holder->GetNewDexCache(klass_index) == nullptr) {
- driver_->self_->AssertPendingOOMException();
+ driver_->self_->AssertPendingException();
driver_->self_->ClearException();
RecordFailure(ERR(OUT_OF_MEMORY), "Unable to allocate DexCache");
return false;