Fix exception throwing to support no detail message.
(The empty string as a detail message is distinct from a NULL detail message,
and is treated differently by Throwable.printStackTrace.)
Change-Id: I8c65deac9f18c5782dcf6e72e4c37e6dd4174fe9
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 1963985..eade908 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -61,7 +61,7 @@
if (dex_cache) {
msg << " (defined in " << dex_cache->GetLocation()->ToModifiedUtf8() << ")";
}
- Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", "%s", msg.str().c_str());
+ Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
}
void ThrowEarlierClassFailure(Class* c) {
@@ -76,7 +76,7 @@
if (c->GetVerifyErrorClass() != NULL) {
// TODO: change the verifier to store an _instance_, with a useful detail message?
std::string error_descriptor(c->GetVerifyErrorClass()->GetDescriptor()->ToModifiedUtf8());
- Thread::Current()->ThrowNewException(error_descriptor.c_str(), "%s",
+ Thread::Current()->ThrowNewException(error_descriptor.c_str(),
PrettyDescriptor(c->GetDescriptor()).c_str());
} else {
ThrowNoClassDefFoundError("%s", PrettyDescriptor(c->GetDescriptor()).c_str());
@@ -816,7 +816,7 @@
ObjectLock lock(klass);
// Check for circular dependencies between classes.
if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
- self->ThrowNewException("Ljava/lang/ClassCircularityError;", "%s",
+ self->ThrowNewException("Ljava/lang/ClassCircularityError;",
PrettyDescriptor(klass->GetDescriptor()).c_str());
return NULL;
}
@@ -1416,7 +1416,7 @@
// "interruptShouldThrow" was set), bail out.
if (self->IsExceptionPending()) {
// TODO: set cause of ExceptionInInitializerError to self->GetException()
- self->ThrowNewException("Ljava/lang/ExceptionInInitializerError;",
+ self->ThrowNewExceptionF("Ljava/lang/ExceptionInInitializerError;",
"Exception %s thrown while initializing class %s",
PrettyTypeOf(self->GetException()).c_str(),
PrettyDescriptor(klass->GetDescriptor()).c_str());
@@ -1430,7 +1430,7 @@
if (klass->IsErroneous()) {
// The caller wants an exception, but it was thrown in a
// different thread. Synthesize one here.
- self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
+ self->ThrowNewExceptionF("Ljava/lang/NoClassDefFoundError;",
"<clinit> failed for class %s; see exception in other thread",
PrettyDescriptor(klass->GetDescriptor()).c_str());
return false;
@@ -1722,7 +1722,7 @@
// Verify
if (!klass->CanAccess(interface)) {
// TODO: the RI seemed to ignore this in my testing.
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Interface %s implemented by class %s is inaccessible",
PrettyDescriptor(interface->GetDescriptor()).c_str(),
PrettyDescriptor(klass->GetDescriptor()).c_str());
@@ -1739,7 +1739,7 @@
Class* super = klass->GetSuperClass();
if (klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
if (super != NULL) {
- Thread::Current()->ThrowNewException("Ljava/lang/ClassFormatError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassFormatError;",
"java.lang.Object must not have a superclass");
return false;
}
@@ -1753,7 +1753,7 @@
}
// Verify
if (super->IsFinal() || super->IsInterface()) {
- Thread::Current()->ThrowNewException("Ljava/lang/IncompatibleClassChangeError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
"Superclass %s of %s is %s",
PrettyDescriptor(super->GetDescriptor()).c_str(),
PrettyDescriptor(klass->GetDescriptor()).c_str(),
@@ -1761,7 +1761,7 @@
return false;
}
if (!klass->CanAccess(super)) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Superclass %s is inaccessible by %s",
PrettyDescriptor(super->GetDescriptor()).c_str(),
PrettyDescriptor(klass->GetDescriptor()).c_str());
@@ -1894,7 +1894,7 @@
Class* interface = klass->GetInterface(i);
DCHECK(interface != NULL);
if (!interface->IsInterface()) {
- Thread::Current()->ThrowNewException("Ljava/lang/IncompatibleClassChangeError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
"Class %s implements non-interface class %s",
PrettyDescriptor(klass->GetDescriptor()).c_str(),
PrettyDescriptor(interface->GetDescriptor()).c_str());
@@ -1936,7 +1936,7 @@
Method* vtable_method = vtable->Get(k);
if (interface_method->HasSameNameAndDescriptor(vtable_method)) {
if (!vtable_method->IsPublic()) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Implementation not public: %s", PrettyMethod(vtable_method).c_str());
return false;
}
@@ -2250,7 +2250,7 @@
Class* check = resolved->IsArrayClass() ? resolved->GetComponentType() : resolved;
if (dex_cache != check->GetDexCache()) {
if (check->GetClassLoader() != NULL) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Class with type index %d resolved by unexpected .dex", type_idx);
resolved = NULL;
}
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 1bc1e39..8d4aa8b 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -56,7 +56,7 @@
return NULL;
}
if (length < 0) {
- Thread::Current()->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d", length);
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", length);
return NULL;
}
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index de5315a..a404523 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -38,7 +38,7 @@
// is especially handy for array types, since we want to avoid
// auto-generating bogus array classes.
if (!IsValidClassName(name.c_str(), true, true)) {
- Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassNotFoundException;",
"Invalid name: %s", name.c_str());
return NULL;
}
@@ -53,8 +53,7 @@
// TODO: chain exceptions?
DCHECK(env->ExceptionCheck());
env->ExceptionClear();
- Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;",
- "%s", name.c_str());
+ Thread::Current()->ThrowNewException("Ljava/lang/ClassNotFoundException;", name.c_str());
return NULL;
}
if (initialize) {
@@ -373,7 +372,7 @@
jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
Class* c = Decode<Class*>(env, javaThis);
if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
- Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
"Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
return NULL;
}
@@ -384,7 +383,7 @@
Method* init = c->FindDirectMethod("<init>", "()V");
if (init == NULL) {
- Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
"Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
return NULL;
}
@@ -405,17 +404,17 @@
Class* caller_class = caller_caller->GetDeclaringClass();
if (!caller_class->CanAccess(c)) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
- "Class %s is not accessible from class %s",
- PrettyDescriptor(c->GetDescriptor()).c_str(),
- PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
+ "Class %s is not accessible from class %s",
+ PrettyDescriptor(c->GetDescriptor()).c_str(),
+ PrettyDescriptor(caller_class->GetDescriptor()).c_str());
return NULL;
}
if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalAccessException;",
- "%s is not accessible from class %s",
- PrettyMethod(init).c_str(),
- PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
+ "%s is not accessible from class %s",
+ PrettyMethod(init).c_str(),
+ PrettyDescriptor(caller_class->GetDescriptor()).c_str());
return NULL;
}
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index 42bae22..4a6e8db 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -106,7 +106,8 @@
void ThrowArrayStoreException_NotAnArray(const char* identifier, Object* array) {
std::string actualType(PrettyTypeOf(array));
- Thread::Current()->ThrowNewException("Ljava/lang/ArrayStoreException;", "%s is not an array: %s", identifier, actualType.c_str());
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
+ "%s is not an array: %s", identifier, actualType.c_str());
}
void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) {
@@ -140,7 +141,7 @@
// Bounds checking.
if (srcPos < 0 || dstPos < 0 || length < 0 || srcPos > srcArray->GetLength() - length || dstPos > dstArray->GetLength() - length) {
- self->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ self->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, length);
return;
@@ -155,7 +156,7 @@
if (srcComponentType->IsPrimitive() != dstComponentType->IsPrimitive() || srcComponentType != dstComponentType) {
std::string srcType(PrettyTypeOf(srcArray));
std::string dstType(PrettyTypeOf(dstArray));
- self->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"Incompatible types: src=%s, dst=%s", srcType.c_str(), dstType.c_str());
return;
}
@@ -231,7 +232,7 @@
if (copyCount != length) {
std::string actualSrcType(PrettyTypeOf(srcObj[copyCount]));
std::string dstType(PrettyTypeOf(dstArray));
- self->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"source[%d] of type %s cannot be stored in destination array of type %s",
srcPos + copyCount, actualSrcType.c_str(), dstType.c_str());
return;
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
index 6cc8ea7..4d42450 100644
--- a/src/java_lang_reflect_Constructor.cc
+++ b/src/java_lang_reflect_Constructor.cc
@@ -35,7 +35,7 @@
jobject Constructor_constructNative(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, jclass javaDeclaringClass, jobjectArray javaParams, jint, jboolean) {
Class* c = Decode<Class*>(env, javaDeclaringClass);
if (c->IsAbstract()) {
- Thread::Current()->ThrowNewException("Ljava/lang/InstantiationException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
"Can't instantiate abstract class %s", PrettyDescriptor(c->GetDescriptor()).c_str());
return NULL;
}
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index 185fabc..8e09adb 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -66,7 +66,7 @@
// Never okay.
break;
}
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"Not a primitive field: %s", PrettyField(f).c_str());
return false;
}
@@ -165,7 +165,7 @@
// Else fall through to report an error.
case Class::kPrimVoid:
// Never okay.
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"Not a primitive field: %s", PrettyField(f).c_str());
return;
}
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 144ec22..bc1de52 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -253,7 +253,7 @@
void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const char* name, const char* sig, const char* kind) {
std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
- ts.Self()->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
"no %s method \"%s.%s%s\"", kind, class_descriptor.c_str(), name, sig);
}
@@ -306,7 +306,7 @@
DCHECK(ts.Self()->IsExceptionPending());
ts.Self()->ClearException();
std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
- ts.Self()->ThrowNewException("Ljava/lang/NoSuchFieldError;",
+ ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
"no type \"%s\" found and so no field \"%s\" could be found in class "
"\"%s\" or its superclasses", sig, name, class_descriptor.c_str());
return NULL;
@@ -318,7 +318,7 @@
}
if (field == NULL) {
std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
- ts.Self()->ThrowNewException("Ljava/lang/NoSuchFieldError;",
+ ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
"no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
name, class_descriptor.c_str());
return NULL;
@@ -366,12 +366,12 @@
void ThrowAIOOBE(ScopedJniThreadState& ts, Array* array, jsize start, jsize length, const char* identifier) {
std::string type(PrettyTypeOf(array));
- ts.Self()->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ ts.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"%s offset=%d length=%d %s.length=%d",
type.c_str(), start, length, identifier, array->GetLength());
}
void ThrowSIOOBE(ScopedJniThreadState& ts, jsize start, jsize length, jsize array_length) {
- ts.Self()->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
+ ts.Self()->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;",
"offset=%d length=%d string.length()=%d", start, length, array_length);
}
@@ -697,7 +697,7 @@
return JNI_ERR;
}
ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
- if (s.get() == NULL) {
+ if (msg != NULL && s.get() == NULL) {
return JNI_ERR;
}
@@ -708,8 +708,6 @@
return JNI_ERR;
}
- LOG(INFO) << "Throwing " << PrettyTypeOf(Decode<Throwable*>(ts, exception.get()))
- << ": " << msg;
ts.Self()->SetException(Decode<Throwable*>(ts, exception.get()));
return JNI_OK;
@@ -2824,7 +2822,7 @@
}
// throwing can cause libraries_lock to be reacquired
if (native_method == NULL) {
- Thread::Current()->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", "%s", detail.c_str());
+ Thread::Current()->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", detail.c_str());
}
return native_method;
}
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 74fdb0a..95e22ba 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -1360,9 +1360,17 @@
jclass exception_class = env_->FindClass("java/lang/RuntimeException");
ASSERT_TRUE(exception_class != NULL);
+ jthrowable thrown_exception;
+
EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, "hello world"));
EXPECT_TRUE(env_->ExceptionCheck());
- jthrowable thrown_exception = env_->ExceptionOccurred();
+ thrown_exception = env_->ExceptionOccurred();
+ env_->ExceptionClear();
+ EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, exception_class));
+
+ EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, NULL));
+ EXPECT_TRUE(env_->ExceptionCheck());
+ thrown_exception = env_->ExceptionOccurred();
env_->ExceptionClear();
EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, exception_class));
}
diff --git a/src/monitor.cc b/src/monitor.cc
index 4e71e45..6bd309d 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -367,7 +367,7 @@
}
void ThrowIllegalMonitorStateException(const char* msg) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalMonitorStateException;", "%s", msg);
+ Thread::Current()->ThrowNewException("Ljava/lang/IllegalMonitorStateException;", msg);
}
bool Monitor::Unlock(Thread* self) {
@@ -469,7 +469,7 @@
// Enforce the timeout range.
if (ms < 0 || ns < 0 || ns > 999999) {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"timeout arguments out of range: ms=%lld ns=%d", ms, ns);
return;
}
@@ -582,7 +582,7 @@
*/
self->interrupted_ = false;
if (interruptShouldThrow) {
- Thread::Current()->ThrowNewException("Ljava/lang/InterruptedException;", "%s", "");
+ Thread::Current()->ThrowNewException("Ljava/lang/InterruptedException;", NULL);
}
}
}
diff --git a/src/object.cc b/src/object.cc
index f8c9624..4a6e649 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1225,13 +1225,13 @@
}
bool Array::ThrowArrayIndexOutOfBoundsException(int32_t index) const {
- Thread::Current()->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"length=%i; index=%i", length_, index);
return false;
}
bool Array::ThrowArrayStoreException(Object* object) const {
- Thread::Current()->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"Can't store an element of type %s into an array of type %s",
PrettyTypeOf(object).c_str(), PrettyTypeOf(this).c_str());
return false;
@@ -1296,7 +1296,7 @@
// bounds check itself.
if (index < 0 || index >= count_) {
Thread* self = Thread::Current();
- self->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
+ self->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;",
"length=%i; index=%i", count_, index);
return 0;
}
diff --git a/src/reflection.cc b/src/reflection.cc
index c560053..1294c08 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -77,7 +77,7 @@
ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
if (arg_count != classes->GetLength()) {
- self->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"wrong number of arguments; expected %d, got %d",
classes->GetLength(), arg_count);
return NULL;
@@ -219,7 +219,7 @@
default:
break;
}
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"invalid primitive conversion from %s to %s",
PrettyDescriptor(src_class->GetDescriptor()).c_str(),
PrettyDescriptor(dst_class->GetDescriptor()).c_str());
@@ -333,7 +333,7 @@
src_class = class_linker->FindPrimitiveClass('S');
boxed_value.s = primitive_field->GetShort(o);
} else {
- Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str());
return false;
}
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index e5fbfd2..ca1fdea 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -83,7 +83,7 @@
// Place a special frame at the TOS that will save all callee saves
*sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
- thread->ThrowNewException("Ljava/lang/NullPointerException;", "unexpected null reference");
+ thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL);
thread->DeliverException();
}
@@ -101,8 +101,8 @@
// Place a special frame at the TOS that will save all callee saves
*sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
- thread->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "length=%d; index=%d", limit, index);
+ thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", "length=%d; index=%d",
+ limit, index);
thread->DeliverException();
}
@@ -110,9 +110,8 @@
extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
*sp = Runtime::Current()->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
- thread->ThrowNewException("Ljava/lang/AbstractMethodError;",
- "abstract method \"%s\"",
- PrettyMethod(method).c_str());
+ thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;", "abstract method \"%s\"",
+ PrettyMethod(method).c_str());
thread->DeliverException();
}
@@ -122,9 +121,9 @@
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
thread->SetStackEndForStackOverflow(); // Allow space on the stack for constructor to execute
- thread->ThrowNewException("Ljava/lang/StackOverflowError;",
- "stack size %zdkb; default stack size: %zdkb",
- thread->GetStackSize() / KB, runtime->GetDefaultStackSize() / KB);
+ thread->ThrowNewExceptionF("Ljava/lang/StackOverflowError;",
+ "stack size %zdkb; default stack size: %zdkb",
+ thread->GetStackSize() / KB, runtime->GetDefaultStackSize() / KB);
thread->ResetDefaultStackEnd(); // Return to default stack size
thread->DeliverException();
}
@@ -135,8 +134,8 @@
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
LOG(WARNING) << "TODO: verifcation error detail message. src1=" << src1 << " ref=" << ref;
- thread->ThrowNewException("Ljava/lang/VerifyError;",
- "TODO: verifcation error detail message. src1=%d; ref=%d", src1, ref);
+ thread->ThrowNewExceptionF("Ljava/lang/VerifyError;",
+ "TODO: verification error detail message. src1=%d; ref=%d", src1, ref);
thread->DeliverException();
}
@@ -146,7 +145,7 @@
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
LOG(WARNING) << "TODO: internal error detail message. errnum=" << errnum;
- thread->ThrowNewException("Ljava/lang/InternalError;", "errnum=%d", errnum);
+ thread->ThrowNewExceptionF("Ljava/lang/InternalError;", "errnum=%d", errnum);
thread->DeliverException();
}
@@ -156,7 +155,7 @@
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
LOG(WARNING) << "TODO: runtime exception detail message. errnum=" << errnum;
- thread->ThrowNewException("Ljava/lang/RuntimeException;", "errnum=%d", errnum);
+ thread->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "errnum=%d", errnum);
thread->DeliverException();
}
@@ -166,7 +165,7 @@
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
LOG(WARNING) << "TODO: no such method exception detail message. method_idx=" << method_idx;
- thread->ThrowNewException("Ljava/lang/NoSuchMethodError;", "method_idx=%d", method_idx);
+ thread->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;", "method_idx=%d", method_idx);
thread->DeliverException();
}
@@ -176,7 +175,7 @@
Runtime* runtime = Runtime::Current();
*sp = runtime->GetCalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
- thread->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d", size);
+ thread->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", size);
thread->DeliverException();
}
@@ -226,7 +225,7 @@
extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
int32_t component_count) {
if (component_count < 0) {
- Thread::Current()->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
component_count);
return NULL; // Failure
}
@@ -240,11 +239,11 @@
}
if (klass->IsPrimitive() && !klass->IsPrimitiveInt()) {
if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
- Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
"Bad filled array request for type %s",
PrettyDescriptor(klass->GetDescriptor()).c_str());
} else {
- Thread::Current()->ThrowNewException("Ljava/lang/InternalError;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Found type %s; filled-new-array not implemented for anything but \'int\'",
PrettyDescriptor(klass->GetDescriptor()).c_str());
}
@@ -259,7 +258,7 @@
// it cannot be resolved, throw an error. If it can, use it to create an array.
extern "C" Array* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
if (component_count < 0) {
- Thread::Current()->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
component_count);
return NULL; // Failure
}
@@ -282,7 +281,7 @@
if (b->IsAssignableFrom(a)) {
return 0; // Success
} else {
- Thread::Current()->ThrowNewException("Ljava/lang/ClassCastException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
"%s cannot be cast to %s",
PrettyDescriptor(a->GetDescriptor()).c_str(),
PrettyDescriptor(b->GetDescriptor()).c_str());
@@ -300,7 +299,7 @@
if (component_type->IsAssignableFrom(element_class)) {
return 0; // Success
} else {
- Thread::Current()->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"Cannot store an object of type %s in to an array of type %s",
PrettyDescriptor(element_class->GetDescriptor()).c_str(),
PrettyDescriptor(array_class->GetDescriptor()).c_str());
@@ -343,16 +342,15 @@
extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table) {
DCHECK_EQ(table[0], 0x0300);
if (array == NULL) {
- Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;",
- "null array in fill array");
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "null array in fill array");
return -1; // Error
}
DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
if (static_cast<int32_t>(size) > array->GetLength()) {
- Thread::Current()->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
- "failed array fill. length=%d; index=%d",
- array->GetLength(), size);
+ Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "failed array fill. length=%d; index=%d", array->GetLength(), size);
return -1; // Error
}
uint16_t width = table[1];
@@ -367,8 +365,8 @@
Method* caller_method) {
Thread* thread = Thread::Current();
if (this_object == NULL) {
- thread->ThrowNewException("Ljava/lang/NullPointerException;",
- "null receiver during interface dispatch");
+ thread->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "null receiver during interface dispatch");
return 0;
}
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/src/thread.cc b/src/thread.cc
index 0df4929..0dd3766 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1076,7 +1076,7 @@
return result;
}
-void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
+void Thread::ThrowNewExceptionF(const char* exception_class_descriptor, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
ThrowNewExceptionV(exception_class_descriptor, fmt, args);
@@ -1086,7 +1086,10 @@
void Thread::ThrowNewExceptionV(const char* exception_class_descriptor, const char* fmt, va_list ap) {
std::string msg;
StringAppendV(&msg, fmt, ap);
+ ThrowNewException(exception_class_descriptor, msg.c_str());
+}
+void Thread::ThrowNewException(const char* exception_class_descriptor, const char* msg) {
// Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
CHECK_EQ('L', exception_class_descriptor[0]);
std::string descriptor(exception_class_descriptor + 1);
@@ -1096,7 +1099,7 @@
JNIEnv* env = GetJniEnv();
jclass exception_class = env->FindClass(descriptor.c_str());
CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
- int rc = env->ThrowNew(exception_class, msg.c_str());
+ int rc = env->ThrowNew(exception_class, msg);
CHECK_EQ(rc, JNI_OK);
env->DeleteLocalRef(exception_class);
}
diff --git a/src/thread.h b/src/thread.h
index e9491dd..4f85b70 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -360,7 +360,10 @@
top_of_managed_stack_pc_ = pc;
}
- void ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...)
+ // 'msg' may be NULL.
+ void ThrowNewException(const char* exception_class_descriptor, const char* msg);
+
+ void ThrowNewExceptionF(const char* exception_class_descriptor, const char* fmt, ...)
__attribute__ ((format(printf, 3, 4)));
void ThrowNewExceptionV(const char* exception_class_descriptor, const char* fmt, va_list ap);
diff --git a/test/034-call-null/expected.txt b/test/034-call-null/expected.txt
index 5ffbe05..7697a32 100644
--- a/test/034-call-null/expected.txt
+++ b/test/034-call-null/expected.txt
@@ -1,3 +1,2 @@
java.lang.NullPointerException
at Main.main(Main.java:12)
- at dalvik.system.NativeStart.main(Native Method)
diff --git a/test/038-inner-null/expected.txt b/test/038-inner-null/expected.txt
index 0be8ffd..6932c50 100644
--- a/test/038-inner-null/expected.txt
+++ b/test/038-inner-null/expected.txt
@@ -2,4 +2,3 @@
java.lang.NullPointerException
at Main$Special.callInner(Main.java:17)
at Main.main(Main.java:6)
- at dalvik.system.NativeStart.main(Native Method)
diff --git a/test/054-uncaught/expected.txt b/test/054-uncaught/expected.txt
index e7473be..e443a07 100644
--- a/test/054-uncaught/expected.txt
+++ b/test/054-uncaught/expected.txt
@@ -18,4 +18,3 @@
java.lang.NullPointerException: Hi diddly-ho, neighborino.
at Main.catchTheUncaught(Main.java:49)
at Main.main(Main.java:12)
- at dalvik.system.NativeStart.main(Native Method)