diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 90 |
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; } |