Merge "Pre-allocate the NoClassDefFoundError to be thrown for boot classes."
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7ba0d92..0746e0c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2015,10 +2015,18 @@
if (descriptor[0] == '[') {
return CreateArrayClass(self, descriptor, class_loader);
} else if (class_loader.Get() == nullptr) {
+ // The boot class loader, search the boot class path.
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
if (pair.second != nullptr) {
StackHandleScope<1> hs(self);
return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
+ } else {
+ // The boot class loader is searched ahead of the application class loader, failures are
+ // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to
+ // trigger the chaining with a proper stack trace.
+ mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(ThrowLocation(), pre_allocated);
+ return nullptr;
}
} else if (Runtime::Current()->UseCompileTimeClassPath()) {
// First try with the bootstrap class loader.
@@ -2028,7 +2036,8 @@
return EnsureResolved(self, descriptor, klass);
}
}
- // If the lookup failed search the boot class path. We don't perform a recursive call to avoid a NoClassDefFoundError being allocated.
+ // If the lookup failed search the boot class path. We don't perform a recursive call to avoid
+ // a NoClassDefFoundError being allocated.
ClassPathEntry pair = FindInClassPath(descriptor, boot_class_path_);
if (pair.second != nullptr) {
StackHandleScope<1> hs(self);
@@ -2057,6 +2066,7 @@
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);
@@ -2070,7 +2080,7 @@
} else if (result.get() == nullptr) {
// broken loader - throw NPE to be compatible with Dalvik
ThrowNullPointerException(nullptr, StringPrintf("ClassLoader.loadClass returned null for %s",
- class_name_string.c_str()).c_str());
+ class_name_string.c_str()).c_str());
return nullptr;
} else {
// success, return mirror::Class*
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index bb6b1c8..064a85d 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -85,7 +85,7 @@
mirror::Class* FindArrayClass(Thread* self, mirror::Class** element_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Reutrns true if the class linker is initialized.
+ // Returns true if the class linker is initialized.
bool IsInitialized() const;
// Define a new a class based on a ClassDef from a DexFile
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5f9a3e3..1a682fb 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -636,7 +636,7 @@
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
- if (options.get() == NULL) {
+ if (options.get() == nullptr) {
LOG(ERROR) << "Failed to parse options";
return false;
}
@@ -759,9 +759,9 @@
// ClassLinker needs an attached thread, but we can't fully attach a thread without creating
// objects. We can't supply a thread group yet; it will be fixed later. Since we are the main
// thread, we do not get a java peer.
- Thread* self = Thread::Attach("main", false, NULL, false);
+ Thread* self = Thread::Attach("main", false, nullptr, false);
CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);
- CHECK(self != NULL);
+ CHECK(self != nullptr);
// Set us to runnable so tools using a runtime can allocate and GC by default
self->TransitionFromSuspendedToRunnable();
@@ -791,11 +791,11 @@
}
}
} else {
- CHECK(options->boot_class_path_ != NULL);
+ CHECK(options->boot_class_path_ != nullptr);
CHECK_NE(options->boot_class_path_->size(), 0U);
class_linker_->InitWithoutImage(*options->boot_class_path_);
}
- CHECK(class_linker_ != NULL);
+ CHECK(class_linker_ != nullptr);
verifier::MethodVerifier::Init();
method_trace_ = options->method_trace_;
@@ -821,6 +821,13 @@
pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
self->ClearException();
+ // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
+ // ahead of checking the application's class loader.
+ self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;",
+ "Class not found using the boot class loader; no stack available");
+ pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
+ self->ClearException();
+
// Look for a native bridge.
native_bridge_library_filename_ = options->native_bridge_library_filename_;
android::SetupNativeBridge(native_bridge_library_filename_.c_str(), &native_bridge_art_callbacks_);
@@ -1031,12 +1038,20 @@
mirror::Throwable* Runtime::GetPreAllocatedOutOfMemoryError() {
mirror::Throwable* oome = pre_allocated_OutOfMemoryError_.Read();
- if (oome == NULL) {
+ if (oome == nullptr) {
LOG(ERROR) << "Failed to return pre-allocated OOME";
}
return oome;
}
+mirror::Throwable* Runtime::GetPreAllocatedNoClassDefFoundError() {
+ mirror::Throwable* ncdfe = pre_allocated_NoClassDefFoundError_.Read();
+ if (ncdfe == nullptr) {
+ LOG(ERROR) << "Failed to return pre-allocated NoClassDefFoundError";
+ }
+ return ncdfe;
+}
+
void Runtime::VisitConstantRoots(RootCallback* callback, void* arg) {
// Visit the classes held as static in mirror classes, these can be visited concurrently and only
// need to be visited once per GC since they never change.
@@ -1075,6 +1090,10 @@
}
resolution_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
DCHECK(!resolution_method_.IsNull());
+ if (!pre_allocated_NoClassDefFoundError_.IsNull()) {
+ pre_allocated_NoClassDefFoundError_.VisitRoot(callback, arg, 0, kRootVMInternal);
+ DCHECK(!pre_allocated_NoClassDefFoundError_.IsNull());
+ }
if (HasImtConflictMethod()) {
imt_conflict_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e97af17..03952c4 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -246,6 +246,9 @@
mirror::Throwable* GetPreAllocatedOutOfMemoryError() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Throwable* GetPreAllocatedNoClassDefFoundError()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
const std::vector<std::string>& GetProperties() const {
return properties_;
}
@@ -509,6 +512,7 @@
GcRoot<mirror::ArtMethod> callee_save_methods_[kLastCalleeSaveType];
GcRoot<mirror::Throwable> pre_allocated_OutOfMemoryError_;
+ GcRoot<mirror::Throwable> pre_allocated_NoClassDefFoundError_;
GcRoot<mirror::ArtMethod> resolution_method_;
GcRoot<mirror::ArtMethod> imt_conflict_method_;
GcRoot<mirror::ObjectArray<mirror::ArtMethod>> default_imt_;