Merge "Revert "Quick: Rewrite type inference pass.""
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c344eb4..dc8bf2a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -92,8 +92,28 @@
va_end(args);
}
-static void ThrowEarlierClassFailure(mirror::Class* c)
+static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const char* descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::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 = class_linker->FindClass(self, descriptor, class_loader);
+
+ if (exception_class == nullptr) {
+ // No exc class ~ no <init>-with-string.
+ CHECK(self->IsExceptionPending());
+ self->ClearException();
+ return false;
+ }
+
+ mirror::ArtMethod* exception_init_method =
+ exception_class->FindDeclaredDirectMethod("<init>", "(Ljava/lang/String;)V");
+ return exception_init_method != nullptr;
+}
+
+void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c) {
// 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
@@ -112,9 +132,15 @@
} 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;
- self->ThrowNewException(c->GetVerifyErrorClass()->GetDescriptor(&temp),
- PrettyDescriptor(c).c_str());
+ const char* descriptor = c->GetVerifyErrorClass()->GetDescriptor(&temp);
+
+ if (HasInitWithString(self, this, descriptor)) {
+ self->ThrowNewException(descriptor, PrettyDescriptor(c).c_str());
+ } else {
+ self->ThrowNewException(descriptor, nullptr);
+ }
} else {
self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
PrettyDescriptor(c).c_str());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 8e27413..1bd9f0a 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -657,6 +657,12 @@
// Return the quick generic JNI stub for testing.
const void* GetRuntimeQuickGenericJniStub() const;
+ // Throw the class initialization failure recorded when first trying to initialize the given
+ // class.
+ // Note: Currently we only store the descriptor, so we cannot throw the exact throwable, only
+ // a recreation with a custom string.
+ void ThrowEarlierClassFailure(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
std::vector<const DexFile*> boot_class_path_;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
diff --git a/test/008-exceptions/expected.txt b/test/008-exceptions/expected.txt
index ef6eaff..92c79dc 100644
--- a/test/008-exceptions/expected.txt
+++ b/test/008-exceptions/expected.txt
@@ -1,9 +1,12 @@
Got an NPE: second throw
java.lang.NullPointerException: second throw
- at Main.catchAndRethrow(Main.java:39)
- at Main.exceptions_007(Main.java:23)
- at Main.main(Main.java:31)
+ at Main.catchAndRethrow(Main.java:58)
+ at Main.exceptions_007(Main.java:41)
+ at Main.main(Main.java:49)
Caused by: java.lang.NullPointerException: first throw
- at Main.throwNullPointerException(Main.java:46)
- at Main.catchAndRethrow(Main.java:36)
+ at Main.throwNullPointerException(Main.java:65)
+ at Main.catchAndRethrow(Main.java:55)
... 2 more
+Static Init
+BadError: This is bad by convention
+BadError: This is bad by convention
diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java
index 1f76f12..7f6d0c5 100644
--- a/test/008-exceptions/src/Main.java
+++ b/test/008-exceptions/src/Main.java
@@ -14,6 +14,24 @@
* limitations under the License.
*/
+// An exception that doesn't have a <init>(String) method.
+class BadError extends Error {
+ public BadError() {
+ super("This is bad by convention");
+ }
+}
+
+// A class that throws BadException during static initialization.
+class BadInit {
+ static int dummy;
+ static {
+ System.out.println("Static Init");
+ if (true) {
+ throw new BadError();
+ }
+ }
+}
+
/**
* Exceptions across method calls
*/
@@ -29,6 +47,7 @@
}
public static void main (String args[]) {
exceptions_007();
+ exceptionsRethrowClassInitFailure();
}
private static void catchAndRethrow() {
@@ -45,4 +64,26 @@
private static void throwNullPointerException() {
throw new NullPointerException("first throw");
}
+
+ private static void exceptionsRethrowClassInitFailure() {
+ try {
+ try {
+ BadInit.dummy = 1;
+ throw new IllegalStateException("Should not reach here.");
+ } catch (BadError e) {
+ System.out.println(e);
+ }
+
+ // Check if it works a second time.
+
+ try {
+ BadInit.dummy = 1;
+ throw new IllegalStateException("Should not reach here.");
+ } catch (BadError e) {
+ System.out.println(e);
+ }
+ } catch (Exception error) {
+ error.printStackTrace();
+ }
+ }
}