Merge "Verify for type_id out of range errors"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c62e214..e155e10 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1980,8 +1980,16 @@
// non boot image compilation. The verifier will need it to record the new dependencies.
// Then dex2oat can update the vdex file with these new dependencies.
if (!GetCompilerOptions().IsBootImage()) {
+ // Create the main VerifierDeps, and set it to this thread.
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files));
+ Thread::Current()->SetVerifierDeps(
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps());
+ // Create per-thread VerifierDeps to avoid contention on the main one.
+ // We will merge them after verification.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files));
+ }
}
// Note: verification should not be pulling in classes anymore when compiling the boot image,
// as all should have been resolved before. As such, doing this in parallel should still
@@ -1995,6 +2003,19 @@
parallel_thread_count_,
timings);
}
+
+ if (!GetCompilerOptions().IsBootImage()) {
+ verifier::VerifierDeps* main_deps =
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
+ // Merge all VerifierDeps into the main one.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
+ worker->GetThread()->SetVerifierDeps(nullptr);
+ main_deps->MergeWith(*thread_deps, dex_files);;
+ delete thread_deps;
+ }
+ Thread::Current()->SetVerifierDeps(nullptr);
+ }
}
class VerifyClassVisitor : public CompilationVisitor {
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index a882a88..a706697 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -838,64 +838,19 @@
return true;
}
-class ImageWriter::PruneClassesVisitor : public ClassVisitor {
+class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
public:
- PruneClassesVisitor(ImageWriter* image_writer, ObjPtr<mirror::ClassLoader> class_loader)
- : image_writer_(image_writer),
- class_loader_(class_loader),
- classes_to_prune_(),
- defined_class_count_(0u) { }
+ explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
- bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool operator()(ObjPtr<Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
if (!image_writer_->KeepClass(klass.Ptr())) {
classes_to_prune_.insert(klass.Ptr());
- if (klass->GetClassLoader() == class_loader_) {
- ++defined_class_count_;
- }
}
return true;
}
- size_t Prune() REQUIRES_SHARED(Locks::mutator_lock_) {
- ClassTable* class_table =
- Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader_);
- for (mirror::Class* klass : classes_to_prune_) {
- std::string storage;
- const char* descriptor = klass->GetDescriptor(&storage);
- bool result = class_table->Remove(descriptor);
- DCHECK(result);
- }
- return defined_class_count_;
- }
-
- private:
- ImageWriter* const image_writer_;
- const ObjPtr<mirror::ClassLoader> class_loader_;
std::unordered_set<mirror::Class*> classes_to_prune_;
- size_t defined_class_count_;
-};
-
-class ImageWriter::PruneClassLoaderClassesVisitor : public ClassLoaderVisitor {
- public:
- explicit PruneClassLoaderClassesVisitor(ImageWriter* image_writer)
- : image_writer_(image_writer), removed_class_count_(0) {}
-
- virtual void Visit(ObjPtr<mirror::ClassLoader> class_loader) OVERRIDE
- REQUIRES_SHARED(Locks::mutator_lock_) {
- PruneClassesVisitor classes_visitor(image_writer_, class_loader);
- ClassTable* class_table =
- Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader);
- class_table->Visit(classes_visitor);
- removed_class_count_ += classes_visitor.Prune();
- }
-
- size_t GetRemovedClassCount() const {
- return removed_class_count_;
- }
-
- private:
ImageWriter* const image_writer_;
- size_t removed_class_count_;
};
void ImageWriter::PruneNonImageClasses() {
@@ -907,13 +862,21 @@
// path dex caches.
class_linker->ClearClassTableStrongRoots();
+ // Make a list of classes we would like to prune.
+ NonImageClassesVisitor visitor(this);
+ class_linker->VisitClasses(&visitor);
+
// Remove the undesired classes from the class roots.
- {
- ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- PruneClassLoaderClassesVisitor class_loader_visitor(this);
- class_loader_visitor.Visit(nullptr); // Visit boot class loader.
- class_linker->VisitClassLoaders(&class_loader_visitor);
- VLOG(compiler) << "Pruned " << class_loader_visitor.GetRemovedClassCount() << " classes";
+ VLOG(compiler) << "Pruning " << visitor.classes_to_prune_.size() << " classes";
+ for (mirror::Class* klass : visitor.classes_to_prune_) {
+ std::string temp;
+ const char* name = klass->GetDescriptor(&temp);
+ VLOG(compiler) << "Pruning class " << name;
+ if (!compile_app_image_) {
+ DCHECK(IsBootClassLoaderClass(klass));
+ }
+ bool result = class_linker->RemoveClass(name, klass->GetClassLoader());
+ DCHECK(result);
}
// Clear references to removed classes from the DexCaches.
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index ad6ffd8..24fad46 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -588,8 +588,7 @@
class FixupVisitor;
class GetRootsVisitor;
class NativeLocationVisitor;
- class PruneClassesVisitor;
- class PruneClassLoaderClassesVisitor;
+ class NonImageClassesVisitor;
class VisitReferencesVisitor;
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 604d99c..2382b72 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1211,7 +1211,7 @@
roots);
if (code == nullptr) {
- code_cache->ClearData(self, stack_map_data);
+ code_cache->ClearData(self, stack_map_data, roots_data);
return false;
}
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 03d3f4e..dcf3619 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -154,6 +154,7 @@
}
CHECK(method != nullptr);
+ Thread::Current()->SetVerifierDeps(callbacks_->GetVerifierDeps());
MethodVerifier verifier(Thread::Current(),
primary_dex_file_,
dex_cache_handle,
@@ -169,6 +170,7 @@
false /* verify to dump */,
true /* allow_thread_suspension */);
verifier.Verify();
+ Thread::Current()->SetVerifierDeps(nullptr);
return !verifier.HasFailures();
}
@@ -230,7 +232,6 @@
const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
DCHECK(type_id != nullptr);
dex::TypeIndex index = primary_dex_file_->GetIndexForTypeId(*type_id);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const auto& dex_dep : verifier_deps_->dex_deps_) {
for (dex::TypeIndex entry : dex_dep.second->unverified_classes_) {
if (index == entry) {
@@ -246,7 +247,6 @@
bool HasAssignable(const std::string& expected_destination,
const std::string& expected_source,
bool expected_is_assignable) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
const DexFile& dex_file = *dex_dep.first;
auto& storage = expected_is_assignable ? dex_dep.second->assignable_types_
@@ -268,7 +268,6 @@
bool HasClass(const std::string& expected_klass,
bool expected_resolved,
const std::string& expected_access_flags = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->classes_) {
if (expected_resolved != entry.IsResolved()) {
@@ -303,7 +302,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->fields_) {
if (expected_resolved != entry.IsResolved()) {
@@ -357,7 +355,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
auto& storage = (expected_kind == "direct") ? dex_dep.second->direct_methods_
: (expected_kind == "virtual") ? dex_dep.second->virtual_methods_
@@ -406,13 +403,10 @@
}
size_t NumberOfCompiledDexFiles() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
return verifier_deps_->dex_deps_.size();
}
size_t HasEachKindOfRecord() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
bool has_strings = false;
bool has_assignability = false;
bool has_classes = false;
@@ -463,8 +457,6 @@
ScopedObjectAccess soa(Thread::Current());
LoadDexFile(&soa);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
uint32_t id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
ASSERT_LT(id_Main1, primary_dex_file_->NumStringIds());
ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Main1));
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 5d92298..e8ef69f 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -48,7 +48,7 @@
Mutex* Locks::modify_ldt_lock_ = nullptr;
MutatorMutex* Locks::mutator_lock_ = nullptr;
Mutex* Locks::profiler_lock_ = nullptr;
-Mutex* Locks::verifier_deps_lock_ = nullptr;
+ReaderWriterMutex* Locks::verifier_deps_lock_ = nullptr;
ReaderWriterMutex* Locks::oat_file_manager_lock_ = nullptr;
Mutex* Locks::host_dlopen_handles_lock_ = nullptr;
Mutex* Locks::reference_processor_lock_ = nullptr;
@@ -672,7 +672,7 @@
ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
++num_pending_readers_;
if (futex(state_.Address(), FUTEX_WAIT, cur_state, nullptr, nullptr, 0) != 0) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex wait failed for " << name_;
}
}
@@ -796,7 +796,7 @@
reinterpret_cast<const timespec*>(std::numeric_limits<int32_t>::max()),
guard_.state_.Address(), cur_sequence) != -1;
if (!done) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex cmp requeue failed for " << name_;
}
}
@@ -1039,7 +1039,7 @@
UPDATE_CURRENT_LOCK_LEVEL(kVerifierDepsLock);
DCHECK(verifier_deps_lock_ == nullptr);
- verifier_deps_lock_ = new Mutex("verifier deps lock", current_lock_level);
+ verifier_deps_lock_ = new ReaderWriterMutex("verifier deps lock", current_lock_level);
UPDATE_CURRENT_LOCK_LEVEL(kHostDlOpenHandlesLock);
DCHECK(host_dlopen_handles_lock_ == nullptr);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 74b786c..7e73e0d 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -658,8 +658,8 @@
// Guards opened oat files in OatFileManager.
static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
- // Guards verifier dependency collection in VerifierDeps.
- static Mutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
+ // Guards extra string entries for VerifierDeps.
+ static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
// Guards dlopen_handles_ in DlOpenOatFile.
static Mutex* host_dlopen_handles_lock_ ACQUIRED_AFTER(verifier_deps_lock_);
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a53dcea..d5f375a 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_BASE_STL_UTIL_H_
#include <algorithm>
+#include <set>
#include <sstream>
#include "base/logging.h"
@@ -187,6 +188,12 @@
using type = T;
};
+// Merge `other` entries into `to_update`.
+template <typename T>
+static inline void MergeSets(std::set<T>& to_update, const std::set<T>& other) {
+ to_update.insert(other.begin(), other.end());
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_STL_UTIL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0fdf4e1..f3aba97 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1949,36 +1949,13 @@
void Visit(ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
ClassTable* const class_table = class_loader->GetClassTable();
- if (!done_ && class_table != nullptr) {
- DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_);
- if (!class_table->Visit(visitor)) {
- // If the visitor ClassTable returns false it means that we don't need to continue.
- done_ = true;
- }
+ if (!done_ && class_table != nullptr && !class_table->Visit(*visitor_)) {
+ // If the visitor ClassTable returns false it means that we don't need to continue.
+ done_ = true;
}
}
private:
- // Class visitor that limits the class visits from a ClassTable to the classes with
- // the provided defining class loader. This filter is used to avoid multiple visits
- // of the same class which can be recorded for multiple initiating class loaders.
- class DefiningClassLoaderFilterVisitor : public ClassVisitor {
- public:
- DefiningClassLoaderFilterVisitor(ObjPtr<mirror::ClassLoader> defining_class_loader,
- ClassVisitor* visitor)
- : defining_class_loader_(defining_class_loader), visitor_(visitor) { }
-
- bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- if (klass->GetClassLoader() != defining_class_loader_) {
- return true;
- }
- return (*visitor_)(klass);
- }
-
- ObjPtr<mirror::ClassLoader> const defining_class_loader_;
- ClassVisitor* const visitor_;
- };
-
ClassVisitor* const visitor_;
// If done is true then we don't need to do any more visiting.
bool done_;
@@ -2563,109 +2540,56 @@
}
} else {
ScopedObjectAccessUnchecked soa(self);
- ObjPtr<mirror::Class> result_ptr;
- bool descriptor_equals;
- bool known_hierarchy =
- FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
- if (result_ptr != nullptr) {
- // The chain was understood and we found the class. We still need to add the class to
- // the class table to protect from racy programs that can try and redefine the path list
- // which would change the Class<?> returned for subsequent evaluation of const-class.
- DCHECK(known_hierarchy);
- DCHECK(result_ptr->DescriptorEquals(descriptor));
- descriptor_equals = true;
- } else {
- // Either the chain wasn't understood or the class wasn't found.
- //
- // If the chain was understood and but we did not find the class, let the Java-side
- // rediscover all this and throw the exception with the right stack trace. Note that
- // the Java-side could still succeed for racy programs if another thread is actively
- // modifying the class loader's path list.
+ ObjPtr<mirror::Class> cp_klass;
+ if (FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
+ // The chain was understood. So the value in cp_klass is either the class we were looking
+ // for, or not found.
+ if (cp_klass != nullptr) {
+ return cp_klass.Ptr();
+ }
+ // TODO: We handle the boot classpath loader in FindClassInBaseDexClassLoader. Try to unify
+ // this and the branch above. TODO: throw the right exception here.
- if (Runtime::Current()->IsAotCompiler()) {
- // Oops, compile-time, can't run actual class-loader code.
- ObjPtr<mirror::Throwable> pre_allocated =
- Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
- self->SetException(pre_allocated);
- return nullptr;
- }
-
- ScopedLocalRef<jobject> class_loader_object(
- soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
- std::string class_name_string(DescriptorToDot(descriptor));
- ScopedLocalRef<jobject> result(soa.Env(), nullptr);
- {
- ScopedThreadStateChange tsc(self, kNative);
- ScopedLocalRef<jobject> class_name_object(
- soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str()));
- if (class_name_object.get() == nullptr) {
- DCHECK(self->IsExceptionPending()); // OOME.
- return nullptr;
- }
- CHECK(class_loader_object.get() != nullptr);
- result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
- WellKnownClasses::java_lang_ClassLoader_loadClass,
- class_name_object.get()));
- }
- if (self->IsExceptionPending()) {
- // If the ClassLoader threw, pass that exception up.
- // However, to comply with the RI behavior, first check if another thread succeeded.
- result_ptr = LookupClass(self, descriptor, hash, class_loader.Get());
- if (result_ptr != nullptr && result_ptr->IsResolved()) {
- self->ClearException();
- return result_ptr.Ptr();
- }
- return nullptr;
- } else if (result.get() == nullptr) {
- // broken loader - throw NPE to be compatible with Dalvik
- ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
- class_name_string.c_str()).c_str());
- return nullptr;
- }
- result_ptr = soa.Decode<mirror::Class>(result.get());
- // Check the name of the returned class.
- descriptor_equals = result_ptr->DescriptorEquals(descriptor);
+ // We'll let the Java-side rediscover all this and throw the exception with the right stack
+ // trace.
}
- // Try to insert the class to the class table, checking for mismatch.
- ObjPtr<mirror::Class> old;
- {
- ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
- ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
- old = class_table->Lookup(descriptor, hash);
- if (old == nullptr) {
- old = result_ptr; // For the comparison below, after releasing the lock.
- if (descriptor_equals) {
- class_table->InsertWithHash(result_ptr.Ptr(), hash);
- Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
- } // else throw below, after releasing the lock.
- }
- }
- if (UNLIKELY(old != result_ptr)) {
- // Return `old` (even if `!descriptor_equals`) to mimic the RI behavior for parallel
- // capable class loaders. (All class loaders are considered parallel capable on Android.)
- mirror::Class* loader_class = class_loader->GetClass();
- const char* loader_class_name =
- loader_class->GetDexFile().StringByTypeIdx(loader_class->GetDexTypeIndex());
- LOG(WARNING) << "Initiating class loader of type " << DescriptorToDot(loader_class_name)
- << " is not well-behaved; it a returned different Class for racing loadClass(\""
- << DescriptorToDot(descriptor) << "\").";
- return old.Ptr();
- }
- if (UNLIKELY(!descriptor_equals)) {
- std::string result_storage;
- const char* result_name = result_ptr->GetDescriptor(&result_storage);
- std::string loader_storage;
- const char* loader_class_name = class_loader->GetClass()->GetDescriptor(&loader_storage);
- ThrowNoClassDefFoundError(
- "Initiating class loader of type %s returned class %s instead of %s.",
- DescriptorToDot(loader_class_name).c_str(),
- DescriptorToDot(result_name).c_str(),
- DescriptorToDot(descriptor).c_str());
+ if (Runtime::Current()->IsAotCompiler()) {
+ // Oops, compile-time, can't run actual class-loader code.
+ ObjPtr<mirror::Throwable> pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
return nullptr;
}
- // success, return mirror::Class*
- return result_ptr.Ptr();
+
+ ScopedLocalRef<jobject> class_loader_object(soa.Env(),
+ soa.AddLocalReference<jobject>(class_loader.Get()));
+ std::string class_name_string(DescriptorToDot(descriptor));
+ ScopedLocalRef<jobject> result(soa.Env(), nullptr);
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ ScopedLocalRef<jobject> class_name_object(soa.Env(),
+ soa.Env()->NewStringUTF(class_name_string.c_str()));
+ if (class_name_object.get() == nullptr) {
+ DCHECK(self->IsExceptionPending()); // OOME.
+ return nullptr;
+ }
+ CHECK(class_loader_object.get() != nullptr);
+ result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
+ WellKnownClasses::java_lang_ClassLoader_loadClass,
+ class_name_object.get()));
+ }
+ if (self->IsExceptionPending()) {
+ // If the ClassLoader threw, pass that exception up.
+ return nullptr;
+ } else if (result.get() == nullptr) {
+ // broken loader - throw NPE to be compatible with Dalvik
+ ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
+ class_name_string.c_str()).c_str());
+ return nullptr;
+ } else {
+ // success, return mirror::Class*
+ return soa.Decode<mirror::Class>(result.get()).Ptr();
+ }
}
UNREACHABLE();
}
@@ -3746,6 +3670,12 @@
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass);
}
+bool ClassLinker::RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader) {
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ ClassTable* const class_table = ClassTableForClassLoader(class_loader);
+ return class_table != nullptr && class_table->Remove(descriptor);
+}
+
mirror::Class* ClassLinker::LookupClass(Thread* self,
const char* descriptor,
size_t hash,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 88028ea..9563448 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -218,6 +218,12 @@
mirror::Class* FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
+ // General class unloading is not supported, this is used to prune
+ // unwanted classes during image writing.
+ bool RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader)
+ REQUIRES(!Locks::classlinker_classes_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
void DumpAllClasses(int flags)
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index bd477ea..0fcce6b 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -142,6 +142,7 @@
bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
const GcRoot<mirror::Class>& b) const {
+ DCHECK_EQ(a.Read()->GetClassLoader(), b.Read()->GetClassLoader());
std::string temp;
return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp));
}
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index b0463d7..1283660 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -94,8 +94,8 @@
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, stack_trace_sample, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, deps_or_stack_trace_sample, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, deps_or_stack_trace_sample, wait_next, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, sizeof(void*));
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 719faed..9d881f2 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -482,9 +482,16 @@
return used_memory_for_data_;
}
-void JitCodeCache::ClearData(Thread* self, void* data) {
+static const uint8_t* FromStackMapToRoots(const uint8_t* stack_map_data) {
+ return stack_map_data - ComputeRootTableSize(GetNumberOfRoots(stack_map_data));
+}
+
+void JitCodeCache::ClearData(Thread* self,
+ uint8_t* stack_map_data,
+ uint8_t* roots_data) {
+ DCHECK_EQ(FromStackMapToRoots(stack_map_data), roots_data);
MutexLock mu(self, lock_);
- FreeData(reinterpret_cast<uint8_t*>(data));
+ FreeData(reinterpret_cast<uint8_t*>(roots_data));
}
void JitCodeCache::ReserveData(Thread* self,
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index a97ef68..40112fe 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -122,7 +122,7 @@
REQUIRES(!lock_);
// Clear data from the data portion of the code cache.
- void ClearData(Thread* self, void* data)
+ void ClearData(Thread* self, uint8_t* stack_map_data, uint8_t* roots_data)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b99df26..65c8681 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1900,7 +1900,7 @@
}
delete tlsPtr_.instrumentation_stack;
delete tlsPtr_.name;
- delete tlsPtr_.stack_trace_sample;
+ delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
free(tlsPtr_.nested_signal_state);
Runtime::Current()->GetHeap()->AssertThreadLocalBuffersAreRevoked(this);
diff --git a/runtime/thread.h b/runtime/thread.h
index b2983cc..3f13db1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -70,7 +70,8 @@
} // namespace mirror
namespace verifier {
-class MethodVerifier;
+ class MethodVerifier;
+ class VerifierDeps;
} // namespace verifier
class ArtMethod;
@@ -947,11 +948,25 @@
}
std::vector<ArtMethod*>* GetStackTraceSample() const {
- return tlsPtr_.stack_trace_sample;
+ return tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
}
void SetStackTraceSample(std::vector<ArtMethod*>* sample) {
- tlsPtr_.stack_trace_sample = sample;
+ DCHECK(sample == nullptr || tlsPtr_.deps_or_stack_trace_sample.verifier_deps == nullptr);
+ tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample = sample;
+ }
+
+ verifier::VerifierDeps* GetVerifierDeps() const {
+ return tlsPtr_.deps_or_stack_trace_sample.verifier_deps;
+ }
+
+ // It is the responsability of the caller to make sure the verifier_deps
+ // entry in the thread is cleared before destruction of the actual VerifierDeps
+ // object, or the thread.
+ void SetVerifierDeps(verifier::VerifierDeps* verifier_deps) {
+ DCHECK(verifier_deps == nullptr ||
+ tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample == nullptr);
+ tlsPtr_.deps_or_stack_trace_sample.verifier_deps = verifier_deps;
}
uint64_t GetTraceClockBase() const {
@@ -1378,7 +1393,7 @@
tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
- stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
+ deps_or_stack_trace_sample(), wait_next(nullptr), monitor_enter_object(nullptr),
top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
@@ -1432,8 +1447,18 @@
// Size of the stack.
size_t stack_size;
- // Pointer to previous stack trace captured by sampling profiler.
- std::vector<ArtMethod*>* stack_trace_sample;
+ // Sampling profiler and AOT verification cannot happen on the same run, so we share
+ // the same entry for the stack trace and the verifier deps.
+ union DepsOrStackTraceSample {
+ DepsOrStackTraceSample() {
+ verifier_deps = nullptr;
+ stack_trace_sample = nullptr;
+ }
+ // Pointer to previous stack trace captured by sampling profiler.
+ std::vector<ArtMethod*>* stack_trace_sample;
+ // When doing AOT verification, per-thread VerifierDeps.
+ verifier::VerifierDeps* verifier_deps;
+ } deps_or_stack_trace_sample;
// The next thread in the wait set this thread is part of or null if not waiting.
Thread* wait_next;
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index 65fd999..d9d2ea3 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -85,6 +85,7 @@
ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
Runtime* runtime = Runtime::Current();
CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, nullptr, false));
+ worker->thread_ = Thread::Current();
// Do work until its time to shut down.
worker->Run();
runtime->DetachCurrentThread();
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index 2ff33a6..eaadfe0 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -62,6 +62,8 @@
// Set the "nice" priorty for this worker.
void SetPthreadPriority(int priority);
+ Thread* GetThread() const { return thread_; }
+
protected:
ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
static void* Callback(void* arg) REQUIRES(!Locks::mutator_lock_);
@@ -71,6 +73,7 @@
const std::string name_;
std::unique_ptr<MemMap> stack_;
pthread_t pthread_;
+ Thread* thread_;
private:
friend class ThreadPool;
@@ -84,6 +87,10 @@
return threads_.size();
}
+ const std::vector<ThreadPoolWorker*>& GetWorkers() const {
+ return threads_;
+ }
+
// Broadcast to the workers and tell them to empty out the work queue.
void StartWorkers(Thread* self) REQUIRES(!task_queue_lock_);
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index a65e82b..fefe5a3 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -18,6 +18,7 @@
#include <cstring>
+#include "base/stl_util.h"
#include "compiler_callbacks.h"
#include "leb128.h"
#include "mirror/class-inl.h"
@@ -28,7 +29,6 @@
namespace verifier {
VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
DCHECK(GetDexFileDeps(*dex_file) == nullptr);
std::unique_ptr<DexFileDeps> deps(new DexFileDeps());
@@ -36,6 +36,28 @@
}
}
+void VerifierDeps::MergeWith(const VerifierDeps& other,
+ const std::vector<const DexFile*>& dex_files) {
+ DCHECK(dex_deps_.size() == other.dex_deps_.size());
+ for (const DexFile* dex_file : dex_files) {
+ DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
+ const DexFileDeps& other_deps = *other.GetDexFileDeps(*dex_file);
+ // We currently collect extra strings only on the main `VerifierDeps`,
+ // which should be the one passed as `this` in this method.
+ DCHECK(other_deps.strings_.empty());
+ MergeSets(my_deps->assignable_types_, other_deps.assignable_types_);
+ MergeSets(my_deps->unassignable_types_, other_deps.unassignable_types_);
+ MergeSets(my_deps->classes_, other_deps.classes_);
+ MergeSets(my_deps->fields_, other_deps.fields_);
+ MergeSets(my_deps->direct_methods_, other_deps.direct_methods_);
+ MergeSets(my_deps->virtual_methods_, other_deps.virtual_methods_);
+ MergeSets(my_deps->interface_methods_, other_deps.interface_methods_);
+ for (dex::TypeIndex entry : other_deps.unverified_classes_) {
+ my_deps->unverified_classes_.push_back(entry);
+ }
+ }
+}
+
VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
auto it = dex_deps_.find(&dex_file);
return (it == dex_deps_.end()) ? nullptr : it->second.get();
@@ -134,6 +156,38 @@
return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
}
+static inline VerifierDeps* GetMainVerifierDeps() {
+ // The main VerifierDeps is the one set in the compiler callbacks, which at the
+ // end of verification will have all the per-thread VerifierDeps merged into it.
+ CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
+ if (callbacks == nullptr) {
+ return nullptr;
+ }
+ return callbacks->GetVerifierDeps();
+}
+
+static inline VerifierDeps* GetThreadLocalVerifierDeps() {
+ // During AOT, each thread has its own VerifierDeps, to avoid lock contention. At the end
+ // of full verification, these VerifierDeps will be merged into the main one.
+ if (!Runtime::Current()->IsAotCompiler()) {
+ return nullptr;
+ }
+ return Thread::Current()->GetVerifierDeps();
+}
+
+static bool FindExistingStringId(const std::vector<std::string>& strings,
+ const std::string& str,
+ uint32_t* found_id) {
+ uint32_t num_extra_ids = strings.size();
+ for (size_t i = 0; i < num_extra_ids; ++i) {
+ if (strings[i] == str) {
+ *found_id = i;
+ return true;
+ }
+ }
+ return false;
+}
+
uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
const DexFile::StringId* string_id = dex_file.FindStringId(str.c_str());
if (string_id != nullptr) {
@@ -144,25 +198,32 @@
// String is not in the DEX file. Assign a new ID to it which is higher than
// the number of strings in the DEX file.
- DexFileDeps* deps = GetDexFileDeps(dex_file);
+ // We use the main `VerifierDeps` for adding new strings to simplify
+ // synchronization/merging of these entries between threads.
+ VerifierDeps* singleton = GetMainVerifierDeps();
+ DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
DCHECK(deps != nullptr);
uint32_t num_ids_in_dex = dex_file.NumStringIds();
- uint32_t num_extra_ids = deps->strings_.size();
+ uint32_t found_id;
- for (size_t i = 0; i < num_extra_ids; ++i) {
- if (deps->strings_[i] == str) {
- return num_ids_in_dex + i;
+ {
+ ReaderMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
}
}
-
- deps->strings_.push_back(str);
-
- uint32_t new_id = num_ids_in_dex + num_extra_ids;
- CHECK_GE(new_id, num_ids_in_dex); // check for overflows
- DCHECK_EQ(str, GetStringFromId(dex_file, new_id));
-
- return new_id;
+ {
+ WriterMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
+ }
+ deps->strings_.push_back(str);
+ uint32_t new_id = num_ids_in_dex + deps->strings_.size() - 1;
+ CHECK_GE(new_id, num_ids_in_dex); // check for overflows
+ DCHECK_EQ(str, singleton->GetStringFromId(dex_file, new_id));
+ return new_id;
+ }
}
std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) const {
@@ -216,7 +277,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
dex_deps->classes_.emplace(ClassResolution(type_idx, GetAccessFlags(klass)));
}
@@ -235,7 +295,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
dex_deps->fields_.emplace(FieldResolution(field_idx,
GetAccessFlags(field),
GetFieldDeclaringClassStringId(dex_file,
@@ -259,7 +318,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
MethodResolution method_tuple(method_idx,
GetAccessFlags(method),
GetMethodDeclaringClassStringId(dex_file, method_idx, method));
@@ -328,8 +386,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
// Get string IDs for both descriptors and store in the appropriate set.
uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
@@ -341,14 +397,6 @@
}
}
-static inline VerifierDeps* GetVerifierDepsSingleton() {
- CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
- if (callbacks == nullptr) {
- return nullptr;
- }
- return callbacks->GetVerifierDeps();
-}
-
void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind) {
@@ -357,10 +405,9 @@
return;
}
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- DexFileDeps* dex_deps = singleton->GetDexFileDeps(dex_file);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ DexFileDeps* dex_deps = thread_deps->GetDexFileDeps(dex_file);
dex_deps->unverified_classes_.push_back(type_idx);
}
}
@@ -368,18 +415,18 @@
void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
dex::TypeIndex type_idx,
mirror::Class* klass) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddClassResolution(dex_file, type_idx, klass);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddClassResolution(dex_file, type_idx, klass);
}
}
void VerifierDeps::MaybeRecordFieldResolution(const DexFile& dex_file,
uint32_t field_idx,
ArtField* field) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddFieldResolution(dex_file, field_idx, field);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddFieldResolution(dex_file, field_idx, field);
}
}
@@ -387,9 +434,9 @@
uint32_t method_idx,
MethodResolutionKind resolution_kind,
ArtMethod* method) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
}
}
@@ -398,9 +445,9 @@
mirror::Class* source,
bool is_strict,
bool is_assignable) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
}
}
@@ -533,7 +580,6 @@
void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
std::vector<uint8_t>* buffer) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
EncodeStringVector(buffer, deps.strings_);
@@ -575,8 +621,6 @@
}
bool VerifierDeps::Equals(const VerifierDeps& rhs) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
if (dex_deps_.size() != rhs.dex_deps_.size()) {
return false;
}
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index e35af41..a12071b 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -42,18 +42,19 @@
// which are being compiled. Classes defined in DEX files outside of this set
// (or synthesized classes without associated DEX files) are considered being
// in the classpath.
-// During code-flow verification, the MethodVerifier informs the VerifierDeps
-// singleton about the outcome of every resolution and assignability test, and
-// the singleton records them if their outcome may change with changes in the
-// classpath.
+// During code-flow verification, the MethodVerifier informs VerifierDeps
+// about the outcome of every resolution and assignability test, and
+// the VerifierDeps object records them if their outcome may change with
+// changes in the classpath.
class VerifierDeps {
public:
- explicit VerifierDeps(const std::vector<const DexFile*>& dex_files)
- REQUIRES(!Locks::verifier_deps_lock_);
+ explicit VerifierDeps(const std::vector<const DexFile*>& dex_files);
- VerifierDeps(const std::vector<const DexFile*>& dex_files,
- ArrayRef<const uint8_t> data)
- REQUIRES(!Locks::verifier_deps_lock_);
+ VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data);
+
+ // Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the
+ // same set of dex files.
+ void MergeWith(const VerifierDeps& other, const std::vector<const DexFile*>& dex_files);
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
@@ -101,23 +102,15 @@
// Serialize the recorded dependencies and store the data into `buffer`.
// `dex_files` provides the order of the dex files in which the dependencies
// should be emitted.
- void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const;
- // NO_THREAD_SAFETY_ANALYSIS as Dump iterates over dex_deps_, which is guarded by
- // verifier_deps_lock_, but we expect Dump to be called once the deps collection is done.
- void Dump(VariableIndentationOutputStream* vios) const
- NO_THREAD_SAFETY_ANALYSIS;
+ void Dump(VariableIndentationOutputStream* vios) const;
// Verify the encoded dependencies of this `VerifierDeps` are still valid.
- // NO_THREAD_SAFETY_ANALYSIS, as this must be called on a read-only `VerifierDeps`.
bool ValidateDependencies(Handle<mirror::ClassLoader> class_loader, Thread* self) const
- NO_THREAD_SAFETY_ANALYSIS;
+ REQUIRES_SHARED(Locks::mutator_lock_);
- // NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are
- // fully created.
- const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS {
+ const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const {
return GetDexFileDeps(dex_file)->unverified_classes_;
}
@@ -200,13 +193,9 @@
// Finds the DexFileDep instance associated with `dex_file`, or nullptr if
// `dex_file` is not reported as being compiled.
- // We disable thread safety analysis. The method only reads the key set of
- // `dex_deps_` which stays constant after initialization.
- DexFileDeps* GetDexFileDeps(const DexFile& dex_file)
- NO_THREAD_SAFETY_ANALYSIS;
+ DexFileDeps* GetDexFileDeps(const DexFile& dex_file);
- const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS;
+ const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const;
// Returns true if `klass` is null or not defined in any of dex files which
// were reported as being compiled.
@@ -218,11 +207,10 @@
// of the corresponding DexFileDeps structure (either provided or inferred from
// `dex_file`).
uint32_t GetIdFromString(const DexFile& dex_file, const std::string& str)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Returns the string represented by `id`.
- std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const
- REQUIRES(Locks::verifier_deps_lock_);
+ std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const;
// Returns the bytecode access flags of `element` (bottom 16 bits), or
// `kUnresolvedMarker` if `element` is null.
@@ -235,18 +223,16 @@
uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
uint32_t dex_method_idx,
ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
uint32_t dex_field_idx,
ArtField* field)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a string ID of the descriptor of the class.
uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
void AddClassResolution(const DexFile& dex_file,
dex::TypeIndex type_idx,
@@ -272,11 +258,9 @@
mirror::Class* source,
bool is_strict,
bool is_assignable)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
- bool Equals(const VerifierDeps& rhs) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ bool Equals(const VerifierDeps& rhs) const;
// Verify `dex_file` according to the `deps`, that is going over each
// `DexFileDeps` field, and checking that the recorded information still
@@ -285,16 +269,14 @@
const DexFile& dex_file,
const DexFileDeps& deps,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
bool VerifyAssignability(Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const std::set<TypeAssignability>& assignables,
bool expected_assignability,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved classes at the point of creation
// of this `VerifierDeps` is still the same.
@@ -302,8 +284,7 @@
const DexFile& dex_file,
const std::set<ClassResolution>& classes,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved fields at the point of creation
// of this `VerifierDeps` is still the same, and each field resolves to the
@@ -313,7 +294,7 @@
const std::set<FieldResolution>& classes,
Thread* self) const
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Verify that the set of resolved methods at the point of creation
// of this `VerifierDeps` is still the same, and each method resolves to the
@@ -323,12 +304,10 @@
const std::set<MethodResolution>& methods,
MethodResolutionKind kind,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Map from DexFiles into dependencies collected from verification of their methods.
- std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_
- GUARDED_BY(Locks::verifier_deps_lock_);
+ std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_;
friend class VerifierDepsTest;
ART_FRIEND_TEST(VerifierDepsTest, StringToId);
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
deleted file mode 100644
index ff33709..0000000
--- a/test/626-const-class-linking/clear_dex_cache_types.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "jni.h"
-#include "scoped_thread_state_change-inl.h"
-
-namespace art {
-
-namespace {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_clearResolvedTypes(JNIEnv*, jclass, jclass cls) {
- ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
- for (size_t i = 0, num_types = dex_cache->NumResolvedTypes(); i != num_types; ++i) {
- dex_cache->SetResolvedType(dex::TypeIndex(i), ObjPtr<mirror::Class>(nullptr));
- }
-}
-
-} // namespace
-
-} // namespace art
diff --git a/test/626-const-class-linking/expected.txt b/test/626-const-class-linking/expected.txt
deleted file mode 100644
index 1243226..0000000
--- a/test/626-const-class-linking/expected.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-JNI_OnLoad called
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-testClearDexCache done
-first: Helper1 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-first: Helper2 class loader: DelegatingLoader
-second: Test class loader: DefiningLoader
-testMultiDex done
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyLoader done
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyLoader
-second: Test class loader: DefiningLoader
-first: Helper3 class loader: RacyLoader
-second: Test3 class loader: DefiningLoader
-first: Helper3 class loader: RacyLoader
-second: Test3 class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (2 unique)
-testRacyLoader2 done
-java.lang.NoClassDefFoundError: Initiating class loader of type MisbehavingLoader returned class Helper2 instead of Test.
-testMisbehavingLoader done
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyMisbehavingLoader done
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-first: Helper1 class loader: RacyMisbehavingLoader
-second: Test class loader: DefiningLoader
-total: 4
- throwables: 0
- class_weaks: 4 (1 unique)
-testRacyMisbehavingLoader2 done
diff --git a/test/626-const-class-linking/info.txt b/test/626-const-class-linking/info.txt
deleted file mode 100644
index 9c19a46..0000000
--- a/test/626-const-class-linking/info.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Test that once a const-class instruction is linked, it will keep referring
-to the same class even in the presence of custom class loaders even after
-clearing the dex cache type array.
diff --git a/test/626-const-class-linking/multidex.jpp b/test/626-const-class-linking/multidex.jpp
deleted file mode 100644
index c7a6648..0000000
--- a/test/626-const-class-linking/multidex.jpp
+++ /dev/null
@@ -1,27 +0,0 @@
-ClassPair:
- @@com.android.jack.annotations.ForceInMainDex
- class ClassPair
-DefiningLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class DefiningLoader
-DelegatingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class DelegatingLoader
-Helper1:
- @@com.android.jack.annotations.ForceInMainDex
- class Helper1
-Main:
- @@com.android.jack.annotations.ForceInMainDex
- class Main
-MisbehavingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class MisbehavingLoader
-RacyLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyLoader
-RacyMisbehavingHelper:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyMisbehavingHelper
-RacyMisbehavingLoader:
- @@com.android.jack.annotations.ForceInMainDex
- class RacyMisbehavingLoader
diff --git a/test/626-const-class-linking/src-multidex/Helper2.java b/test/626-const-class-linking/src-multidex/Helper2.java
deleted file mode 100644
index 5bb31ee..0000000
--- a/test/626-const-class-linking/src-multidex/Helper2.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Helper2 {
- public static ClassPair get() {
- Class<?> helper2_class = Helper2.class;
- Class<?> test_class = Test.class;
- return new ClassPair(helper2_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src-multidex/Helper3.java b/test/626-const-class-linking/src-multidex/Helper3.java
deleted file mode 100644
index af996de..0000000
--- a/test/626-const-class-linking/src-multidex/Helper3.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Helper3 {
- public static ClassPair get() {
- Class<?> helper3_class = Helper3.class;
- Class<?> test3_class = Test3.class;
- return new ClassPair(helper3_class, test3_class);
- }
-}
diff --git a/test/626-const-class-linking/src-multidex/Test.java b/test/626-const-class-linking/src-multidex/Test.java
deleted file mode 100644
index 1b0cc2a..0000000
--- a/test/626-const-class-linking/src-multidex/Test.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Test {
-}
diff --git a/test/626-const-class-linking/src-multidex/Test3.java b/test/626-const-class-linking/src-multidex/Test3.java
deleted file mode 100644
index c4b134d..0000000
--- a/test/626-const-class-linking/src-multidex/Test3.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Test3 {
-}
diff --git a/test/626-const-class-linking/src/ClassPair.java b/test/626-const-class-linking/src/ClassPair.java
deleted file mode 100644
index b07036c..0000000
--- a/test/626-const-class-linking/src/ClassPair.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class ClassPair {
- public Class<?> first;
- public Class<?> second;
-
- public ClassPair(Class<?> first, Class<?> second) {
- this.first = first;
- this.second = second;
- }
-
- public void print() {
- String first_loader_name = first.getClassLoader().getClass().getName();
- System.out.println("first: " + first.getName() + " class loader: " + first_loader_name);
- String second_loader_name = second.getClassLoader().getClass().getName();
- System.out.println("second: " + second.getName() + " class loader: " + second_loader_name);
- }
-}
diff --git a/test/626-const-class-linking/src/DefiningLoader.java b/test/626-const-class-linking/src/DefiningLoader.java
deleted file mode 100644
index b17ab77..0000000
--- a/test/626-const-class-linking/src/DefiningLoader.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * A class loader with atypical behavior: we try to load a private
- * class implementation before asking the system or boot loader. This
- * is used to create multiple classes with identical names in a single VM.
- *
- * If DexFile is available, we use that; if not, we assume we're not in
- * Dalvik and instantiate the class with defineClass().
- *
- * The location of the DEX files and class data is dependent upon the
- * test framework.
- */
-public class DefiningLoader extends ClassLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- /* this is where the .class files live */
- static final String CLASS_PATH1 = "classes/";
- static final String CLASS_PATH2 = "classes2/";
-
- /* this is the DEX/Jar file */
- static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/626-const-class-linking.jar";
-
- /* on Dalvik, this is a DexFile; otherwise, it's null */
- private Class<?> mDexClass;
-
- private Object mDexFile;
-
- /**
- * Construct DefiningLoader, grabbing a reference to the DexFile class
- * if we're running under Dalvik.
- */
- public DefiningLoader(ClassLoader parent) {
- super(parent);
-
- try {
- mDexClass = parent.loadClass("dalvik.system.DexFile");
- } catch (ClassNotFoundException cnfe) {
- // ignore -- not running Dalvik
- }
- }
-
- /**
- * Finds the class with the specified binary name.
- *
- * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
- * If we don't find a match, we throw an exception.
- */
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (mDexClass != null) {
- return findClassDalvik(name);
- } else {
- return findClassNonDalvik(name);
- }
- }
-
- /**
- * Finds the class with the specified binary name, from a DEX file.
- */
- private Class<?> findClassDalvik(String name)
- throws ClassNotFoundException {
-
- if (mDexFile == null) {
- synchronized (DefiningLoader.class) {
- Constructor<?> ctor;
- /*
- * Construct a DexFile object through reflection.
- */
- try {
- ctor = mDexClass.getConstructor(String.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getConstructor failed",
- nsme);
- }
-
- try {
- mDexFile = ctor.newInstance(DEX_FILE);
- } catch (InstantiationException ie) {
- throw new ClassNotFoundException("newInstance failed", ie);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("newInstance failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("newInstance failed", ite);
- }
- }
- }
-
- /*
- * Call DexFile.loadClass(String, ClassLoader).
- */
- Method meth;
-
- try {
- meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getMethod failed", nsme);
- }
-
- try {
- meth.invoke(mDexFile, name, this);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("loadClass failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("loadClass failed",
- ite.getCause());
- }
-
- return null;
- }
-
- /**
- * Finds the class with the specified binary name, from .class files.
- */
- private Class<?> findClassNonDalvik(String name)
- throws ClassNotFoundException {
-
- String[] pathNames = { CLASS_PATH1 + name + ".class", CLASS_PATH2 + name + ".class" };
-
- String pathName = null;
- RandomAccessFile raf = null;
-
- for (String pn : pathNames) {
- pathName = pn;
- try {
- //System.out.println("--- Defining: looking for " + pathName);
- raf = new RandomAccessFile(new File(pathName), "r");
- break;
- } catch (FileNotFoundException fnfe) {
- }
- }
- if (raf == null) {
- throw new ClassNotFoundException("Not found: " + pathNames[0] + ":" + pathNames[1]);
- }
-
- /* read the entire file in */
- byte[] fileData;
- try {
- fileData = new byte[(int) raf.length()];
- raf.readFully(fileData);
- } catch (IOException ioe) {
- throw new ClassNotFoundException("Read error: " + pathName);
- } finally {
- try {
- raf.close();
- } catch (IOException ioe) {
- // drop
- }
- }
-
- /* create the class */
- //System.out.println("--- Defining: defining " + name);
- try {
- return defineClass(name, fileData, 0, fileData.length);
- } catch (Throwable th) {
- throw new ClassNotFoundException("defineClass failed", th);
- }
- }
-
- /**
- * Load a class.
- *
- * Normally a class loader wouldn't override this, but we want our
- * version of the class to take precedence over an already-loaded
- * version.
- *
- * We still want the system classes (e.g. java.lang.Object) from the
- * bootstrap class loader.
- */
- synchronized protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- Class<?> res;
-
- /*
- * 1. Invoke findLoadedClass(String) to check if the class has
- * already been loaded.
- *
- * This doesn't change.
- */
- res = findLoadedClass(name);
- if (res != null) {
- // System.out.println("FancyLoader.loadClass: " + name + " already loaded");
- if (resolve)
- resolveClass(res);
- return res;
- }
-
- /*
- * 3. Invoke the findClass(String) method to find the class.
- */
- try {
- res = findClass(name);
- if (resolve)
- resolveClass(res);
- }
- catch (ClassNotFoundException e) {
- // we couldn't find it, so eat the exception and keep going
- }
-
- /*
- * 2. Invoke the loadClass method on the parent class loader. If
- * the parent loader is null the class loader built-in to the
- * virtual machine is used, instead.
- *
- * (Since we're not in java.lang, we can't actually invoke the
- * parent's loadClass() method, but we passed our parent to the
- * super-class which can take care of it for us.)
- */
- res = super.loadClass(name, resolve); // returns class or throws
- return res;
- }
-}
diff --git a/test/626-const-class-linking/src/DelegatingLoader.java b/test/626-const-class-linking/src/DelegatingLoader.java
deleted file mode 100644
index 49955d4..0000000
--- a/test/626-const-class-linking/src/DelegatingLoader.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class DelegatingLoader extends DefiningLoader {
- private DefiningLoader defining_loader;
-
- public DelegatingLoader(ClassLoader parent, DefiningLoader defining_loader) {
- super(parent);
- this.defining_loader = defining_loader;
- }
-
- public void resetDefiningLoader(DefiningLoader defining_loader) {
- this.defining_loader = defining_loader;
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- throw new Error("Unexpected DelegatingLoader.findClass(\"Test\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- return defining_loader.loadClass(name, resolve);
- }
- return super.loadClass(name, resolve);
- }
-}
diff --git a/test/626-const-class-linking/src/Helper1.java b/test/626-const-class-linking/src/Helper1.java
deleted file mode 100644
index ff9cd1a..0000000
--- a/test/626-const-class-linking/src/Helper1.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Helper1 {
- public static ClassPair get() {
- Class<?> helper1_class = Helper1.class;
- Class<?> test_class = Test.class;
- return new ClassPair(helper1_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src/Main.java b/test/626-const-class-linking/src/Main.java
deleted file mode 100644
index 05a6bac..0000000
--- a/test/626-const-class-linking/src/Main.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- try {
- System.loadLibrary(args[0]);
- } catch (UnsatisfiedLinkError ule) {
- usingRI = true;
- // Add expected JNI_OnLoad log line to match expected.txt.
- System.out.println("JNI_OnLoad called");
- }
-
- testClearDexCache();
- testMultiDex();
- testRacyLoader();
- testRacyLoader2();
- testMisbehavingLoader();
- testRacyMisbehavingLoader();
- testRacyMisbehavingLoader2();
- }
-
- private static void testClearDexCache() throws Exception {
- DelegatingLoader delegating_loader = createDelegatingLoader();
- Class<?> helper = delegating_loader.loadClass("Helper1");
-
- WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper);
- changeInner(delegating_loader);
- if (!usingRI) {
- clearResolvedTypes(helper);
- }
- Runtime.getRuntime().gc();
- WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper);
- Runtime.getRuntime().gc();
-
- Class<?> test1 = weak_test1.get();
- if (test1 == null) {
- System.out.println("test1 disappeared");
- }
- Class<?> test2 = weak_test2.get();
- if (test2 == null) {
- System.out.println("test2 disappeared");
- }
- if (test1 != test2) {
- System.out.println("test1 != test2");
- }
-
- System.out.println("testClearDexCache done");
- }
-
- private static void testMultiDex() throws Exception {
- DelegatingLoader delegating_loader = createDelegatingLoader();
-
- Class<?> helper1 = delegating_loader.loadClass("Helper1");
- WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1);
-
- changeInner(delegating_loader);
-
- Class<?> helper2 = delegating_loader.loadClass("Helper2");
- WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2);
-
- Runtime.getRuntime().gc();
-
- Class<?> test1 = weak_test1.get();
- if (test1 == null) {
- System.out.println("test1 disappeared");
- }
- Class<?> test2 = weak_test2.get();
- if (test2 == null) {
- System.out.println("test2 disappeared");
- }
- if (test1 != test2) {
- System.out.println("test1 != test2");
- }
-
- System.out.println("testMultiDex done");
- }
-
- private static void testMisbehavingLoader() throws Exception {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- MisbehavingLoader misbehaving_loader =
- new MisbehavingLoader(system_loader, defining_loader);
- Class<?> helper = misbehaving_loader.loadClass("Helper1");
-
- try {
- WeakReference<Class<?>> weak_test = wrapHelperGet(helper);
- } catch (InvocationTargetException ite) {
- String message = ite.getCause().getMessage();
- if (usingRI && "Test".equals(message)) {
- // Replace RI message with dalvik message to match expected.txt.
- message = "Initiating class loader of type " +
- misbehaving_loader.getClass().getName() +
- " returned class Helper2 instead of Test.";
- }
- System.out.println(ite.getCause().getClass().getName() + ": " + message);
- }
- System.out.println("testMisbehavingLoader done");
- }
-
- private static void testRacyLoader() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
- final Class<?> helper1 = racy_loader.loadClass("Helper1");
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyLoader done");
- }
-
- private static void testRacyLoader2() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
- final Class<?> helper1 = racy_loader.loadClass("Helper1");
- final Class<?> helper3 = racy_loader.loadClass("Helper3");
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3;
- Method get = helper.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyLoader2 done");
- }
-
- private static void dumpResultStats(Object[] results) throws Exception {
- int throwables = 0;
- int class_weaks = 0;
- int unique_class_weaks = 0;
- for (int i = 0; i != results.length; ++i) {
- Object r = results[i];
- if (r instanceof Throwable) {
- ++throwables;
- System.out.println(((Throwable) r).getMessage());
- } else if (isClassPair(r)) {
- printPair(r);
- Object ref = getSecond(r);
- ++class_weaks;
- ++unique_class_weaks;
- for (int j = 0; j != i; ++j) {
- Object rj = results[j];
- if (isClassPair(results[j]) && getSecond(results[j]) == ref) {
- --unique_class_weaks;
- break;
- }
- }
- }
- }
- System.out.println("total: " + results.length);
- System.out.println(" throwables: " + throwables);
- System.out.println(" class_weaks: " + class_weaks
- + " (" + unique_class_weaks + " unique)");
- }
-
- private static void testRacyMisbehavingLoader() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyMisbehavingLoader racy_loader =
- new RacyMisbehavingLoader(system_loader, threads.length, false);
- final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyMisbehavingLoader done");
- }
-
- private static void testRacyMisbehavingLoader2() throws Exception {
- final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
-
- final Thread[] threads = new Thread[4];
- final Object[] results = new Object[threads.length];
-
- final RacyMisbehavingLoader racy_loader =
- new RacyMisbehavingLoader(system_loader, threads.length, true);
- final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
-
- for (int i = 0; i != threads.length; ++i) {
- final int my_index = i;
- Thread t = new Thread() {
- public void run() {
- try {
- Method get = helper1.getDeclaredMethod("get");
- results[my_index] = get.invoke(null);
- } catch (InvocationTargetException ite) {
- results[my_index] = ite.getCause();
- } catch (Throwable t) {
- results[my_index] = t;
- }
- }
- };
- t.start();
- threads[i] = t;
- }
- for (Thread t : threads) {
- t.join();
- }
- dumpResultStats(results);
- System.out.println("testRacyMisbehavingLoader2 done");
- }
-
- private static DelegatingLoader createDelegatingLoader() {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- return new DelegatingLoader(system_loader, defining_loader);
- }
-
- private static void changeInner(DelegatingLoader delegating_loader) {
- ClassLoader system_loader = ClassLoader.getSystemClassLoader();
- DefiningLoader defining_loader = new DefiningLoader(system_loader);
- delegating_loader.resetDefiningLoader(defining_loader);
- }
-
- private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception {
- Method get = helper.getDeclaredMethod("get");
- Object pair = get.invoke(null);
- printPair(pair);
- return new WeakReference<Class<?>>(getSecond(pair));
- }
-
- private static void printPair(Object pair) throws Exception {
- Method print = pair.getClass().getDeclaredMethod("print");
- print.invoke(pair);
- }
-
- private static Class<?> getSecond(Object pair) throws Exception {
- Field second = pair.getClass().getDeclaredField("second");
- return (Class<?>) second.get(pair);
- }
-
- private static boolean isClassPair(Object r) {
- return r != null && r.getClass().getName().equals("ClassPair");
- }
-
- public static native void clearResolvedTypes(Class<?> c);
-
- static boolean usingRI = false;
-}
diff --git a/test/626-const-class-linking/src/MisbehavingLoader.java b/test/626-const-class-linking/src/MisbehavingLoader.java
deleted file mode 100644
index ca9783e..0000000
--- a/test/626-const-class-linking/src/MisbehavingLoader.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Class loader that returns Helper2.class when asked to load "Test".
-public class MisbehavingLoader extends DefiningLoader {
- private DefiningLoader defining_loader;
-
- public MisbehavingLoader(ClassLoader parent, DefiningLoader defining_loader) {
- super(parent);
- this.defining_loader = defining_loader;
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Helper1") || name.equals("Helper2")) {
- return super.findClass(name);
- } else if (name.equals("Test")) {
- throw new Error("Unexpected MisbehavingLoader.findClass(\"Test\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Helper1") || name.equals("Helper2")) {
- return super.loadClass(name, resolve);
- } else if (name.equals("Test")) {
- // Ask for a different class.
- return defining_loader.loadClass("Helper2", resolve);
- }
- return super.loadClass(name, resolve);
- }
-}
diff --git a/test/626-const-class-linking/src/RacyLoader.java b/test/626-const-class-linking/src/RacyLoader.java
deleted file mode 100644
index abfc8ed..0000000
--- a/test/626-const-class-linking/src/RacyLoader.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class RacyLoader extends DefiningLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- private Object lock = new Object();
- private int index = 0;
- private int count;
-
- private DefiningLoader[] defining_loaders;
-
- public RacyLoader(ClassLoader parent, int count) {
- super(parent);
- this.count = count;
- defining_loaders = new DefiningLoader[2];
- for (int i = 0; i != defining_loaders.length; ++i) {
- defining_loaders[i] = new DefiningLoader(parent);
- }
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test") || name.equals("Test3")) {
- throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test") || name.equals("Test3")) {
- int my_index = syncWithOtherInstances(count);
- Class<?> result = defining_loaders[my_index & 1].loadClass(name, resolve);
- syncWithOtherInstances(2 * count);
- return result;
- }
- return super.loadClass(name, resolve);
- }
-
- private int syncWithOtherInstances(int limit) {
- int my_index;
- synchronized (lock) {
- my_index = index;
- ++index;
- if (index != limit) {
- try {
- lock.wait(2000);
- if (index < limit) {
- throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
- }
- } catch (InterruptedException ie) {
- throw new Error(ie);
- }
- } else {
- lock.notifyAll();
- }
- }
- return my_index;
- }
-}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingHelper.java b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
deleted file mode 100644
index 4525278..0000000
--- a/test/626-const-class-linking/src/RacyMisbehavingHelper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.lang.reflect.Method;
-
-public class RacyMisbehavingHelper {
- public static ClassPair get() {
- Class<?> helper1_class = Helper1.class;
- Class<?> test_class = Test.class;
- try {
- // After loading the correct class, allow loading the incorrect class.
- ClassLoader loader = helper1_class.getClassLoader();
- Method reportAfterLoading = loader.getClass().getDeclaredMethod("reportAfterLoading");
- reportAfterLoading.invoke(loader);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return new ClassPair(helper1_class, test_class);
- }
-}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingLoader.java b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
deleted file mode 100644
index d09888e..0000000
--- a/test/626-const-class-linking/src/RacyMisbehavingLoader.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class RacyMisbehavingLoader extends DefiningLoader {
- static {
- // For JVM, register as parallel capable.
- // Android treats all class loaders as parallel capable and makes this a no-op.
- registerAsParallelCapable();
- }
-
- private Object lock = new Object();
- private int index = 0;
- private int count;
- private boolean throw_error;
-
- private DefiningLoader[] defining_loaders;
-
- public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
- super(parent);
- this.count = count;
- this.throw_error = throw_error;
- defining_loaders = new DefiningLoader[2];
- for (int i = 0; i != defining_loaders.length; ++i) {
- defining_loaders[i] = new DefiningLoader(parent);
- }
- }
-
- public void reportAfterLoading() {
- synchronized (lock) {
- ++index;
- if (index == 2 * count) {
- lock.notifyAll();
- }
- }
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
- }
- return super.findClass(name);
- }
-
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- if (name.equals("Test")) {
- int my_index = syncWithOtherInstances(count);
- Class<?> result;
- if ((my_index & 1) == 0) {
- // Do not delay loading the correct class.
- result = defining_loaders[my_index & 1].loadClass(name, resolve);
- } else {
- // Delay loading the wrong class.
- syncWithOtherInstances(2 * count);
- if (throw_error) {
- throw new Error("RacyMisbehavingLoader throw_error=true");
- }
- result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
- }
- return result;
- }
- return super.loadClass(name, resolve);
- }
-
- private int syncWithOtherInstances(int limit) {
- int my_index;
- synchronized (lock) {
- my_index = index;
- ++index;
- if (index != limit) {
- try {
- lock.wait(2000);
- if (index < limit) {
- throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
- }
- } catch (InterruptedException ie) {
- throw new Error(ie);
- }
- } else {
- lock.notifyAll();
- }
- }
- return my_index;
- }
-}
diff --git a/test/Android.bp b/test/Android.bp
index 39a4059..fe20f29 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -314,7 +314,6 @@
"595-profile-saving/profile-saving.cc",
"596-app-images/app_images.cc",
"597-deopt-new-string/deopt.cc",
- "626-const-class-linking/clear_dex_cache_types.cc",
],
shared_libs: [
"libbacktrace",
diff --git a/test/etc/default-build b/test/etc/default-build
index 408dcfd..e663496 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -273,10 +273,8 @@
fi
# Create a single jar with two dex files for multidex.
-if [ ${NEED_DEX} = "true" ]; then
- if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
- zip $TEST_NAME.jar classes.dex classes2.dex
- else
- zip $TEST_NAME.jar classes.dex
- fi
+if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
+ zip $TEST_NAME.jar classes.dex classes2.dex
+elif [ ${NEED_DEX} = "true" ]; then
+ zip $TEST_NAME.jar classes.dex
fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 368c663..06e4219 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -312,8 +312,7 @@
if [ "$USE_JVM" = "y" ]; then
export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64
# Xmx is necessary since we don't pass down the ART flags to JVM.
- # We pass the classes2 path whether it's used (src-multidex) or not.
- cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes:classes2 ${FLAGS} $MAIN $@ ${ARGS}"
+ cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes ${FLAGS} $MAIN $@ ${ARGS}"
if [ "$DEV_MODE" = "y" ]; then
echo $cmdline
fi