summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc90
1 files changed, 63 insertions, 27 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index da70456369..5dac95d3b3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -104,12 +104,13 @@ static void ThrowNoClassDefFoundError(const char* fmt, ...) {
va_end(args);
}
-bool ClassLinker::HasInitWithString(Thread* self, const char* descriptor) {
+static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const char* descriptor)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
ArtMethod* method = self->GetCurrentMethod(nullptr);
StackHandleScope<1> hs(self);
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(method != nullptr ?
method->GetDeclaringClass()->GetClassLoader() : nullptr));
- mirror::Class* exception_class = FindClass(self, descriptor, class_loader);
+ mirror::Class* exception_class = class_linker->FindClass(self, descriptor, class_loader);
if (exception_class == nullptr) {
// No exc class ~ no <init>-with-string.
@@ -119,11 +120,40 @@ bool ClassLinker::HasInitWithString(Thread* self, const char* descriptor) {
}
ArtMethod* exception_init_method = exception_class->FindDeclaredDirectMethod(
- "<init>", "(Ljava/lang/String;)V", image_pointer_size_);
+ "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
return exception_init_method != nullptr;
}
-void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c) {
+// Helper for ThrowEarlierClassFailure. Throws the stored error.
+static void HandleEarlierVerifyError(Thread* self, ClassLinker* class_linker, mirror::Class* c)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ mirror::Object* obj = c->GetVerifyError();
+ DCHECK(obj != nullptr);
+ self->AssertNoPendingException();
+ if (obj->IsClass()) {
+ // Previous error has been stored as class. Create a new exception of that type.
+
+ // It's possible the exception doesn't have a <init>(String).
+ std::string temp;
+ const char* descriptor = obj->AsClass()->GetDescriptor(&temp);
+
+ if (HasInitWithString(self, class_linker, descriptor)) {
+ self->ThrowNewException(descriptor, PrettyDescriptor(c).c_str());
+ } else {
+ self->ThrowNewException(descriptor, nullptr);
+ }
+ } else {
+ // Previous error has been stored as an instance. Just rethrow.
+ mirror::Class* throwable_class =
+ self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass();
+ mirror::Class* error_class = obj->GetClass();
+ CHECK(throwable_class->IsAssignableFrom(error_class));
+ self->SetException(obj->AsThrowable());
+ }
+ self->AssertPendingException();
+}
+
+void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def) {
// The class failed to initialize on a previous attempt, so we want to throw
// a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we
// failed in verification, in which case v2 5.4.1 says we need to re-throw
@@ -131,8 +161,11 @@ void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c) {
Runtime* const runtime = Runtime::Current();
if (!runtime->IsAotCompiler()) { // Give info if this occurs at runtime.
std::string extra;
- if (c->GetVerifyErrorClass() != nullptr) {
- extra = PrettyDescriptor(c->GetVerifyErrorClass());
+ if (c->GetVerifyError() != nullptr) {
+ mirror::Class* descr_from = c->GetVerifyError()->IsClass()
+ ? c->GetVerifyError()->AsClass()
+ : c->GetVerifyError()->GetClass();
+ extra = PrettyDescriptor(descr_from);
}
LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c) << ": " << extra;
}
@@ -144,20 +177,16 @@ void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c) {
mirror::Throwable* pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
} else {
- if (c->GetVerifyErrorClass() != nullptr) {
- // TODO: change the verifier to store an _instance_, with a useful detail message?
- // It's possible the exception doesn't have a <init>(String).
- std::string temp;
- const char* descriptor = c->GetVerifyErrorClass()->GetDescriptor(&temp);
-
- if (HasInitWithString(self, descriptor)) {
- self->ThrowNewException(descriptor, PrettyDescriptor(c).c_str());
- } else {
- self->ThrowNewException(descriptor, nullptr);
- }
- } else {
- self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
- PrettyDescriptor(c).c_str());
+ if (c->GetVerifyError() != nullptr) {
+ // Rethrow stored error.
+ HandleEarlierVerifyError(self, this, c);
+ }
+ if (c->GetVerifyError() == nullptr || wrap_in_no_class_def) {
+ // If there isn't a recorded earlier error, or this is a repeat throw from initialization,
+ // the top-level exception must be a NoClassDefFoundError. The potentially already pending
+ // exception will be a cause.
+ self->ThrowNewWrappedException("Ljava/lang/NoClassDefFoundError;",
+ PrettyDescriptor(c).c_str());
}
}
}
@@ -847,8 +876,8 @@ void ClassLinker::InitFromImage() {
hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
- space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
- AsObjectArray<mirror::Class>()));
+ space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
+ AsObjectArray<mirror::Class>()));
class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
// Special case of setting up the String class early so that we can test arbitrary objects
@@ -857,7 +886,7 @@ void ClassLinker::InitFromImage() {
mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
java_lang_Object->SetObjectSize(sizeof(mirror::Object));
- Runtime::Current()->SetSentinel(Runtime::Current()->GetHeap()->AllocObject<true>(self,
+ Runtime::Current()->SetSentinel(heap->AllocObject<true>(self,
java_lang_Object,
java_lang_Object->GetObjectSize(),
VoidFunctor()));
@@ -2126,8 +2155,6 @@ void ClassLinker::LoadClassMembers(Thread* self,
last_field_idx = field_idx;
}
}
- klass->SetSFieldsPtr(sfields);
- DCHECK_EQ(klass->NumStaticFields(), num_sfields);
// Load instance fields.
LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
allocator,
@@ -2149,8 +2176,17 @@ void ClassLinker::LoadClassMembers(Thread* self,
LOG(WARNING) << "Duplicate fields in class " << PrettyDescriptor(klass.Get())
<< " (unique static fields: " << num_sfields << "/" << it.NumStaticFields()
<< ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")";
- // NOTE: Not shrinking the over-allocated sfields/ifields.
+ // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.
+ if (sfields != nullptr) {
+ sfields->SetSize(num_sfields);
+ }
+ if (ifields != nullptr) {
+ ifields->SetSize(num_ifields);
+ }
}
+ // Set the field arrays.
+ klass->SetSFieldsPtr(sfields);
+ DCHECK_EQ(klass->NumStaticFields(), num_sfields);
klass->SetIFieldsPtr(ifields);
DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
// Load methods.
@@ -3399,7 +3435,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// Was the class already found to be erroneous? Done under the lock to match the JLS.
if (klass->IsErroneous()) {
- ThrowEarlierClassFailure(klass.Get());
+ ThrowEarlierClassFailure(klass.Get(), true);
VlogClassInitializationFailure(klass);
return false;
}