Finish cleanup of class/field/method caching.
Change-Id: I289ae724cbd98487429275837d23b7b2d7096156
diff --git a/src/class_linker.cc b/src/class_linker.cc
index c1382e2..43f1b42 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -135,25 +135,20 @@
}
static void WrapExceptionInInitializer() {
- JNIEnv* env = Thread::Current()->GetJniEnv();
+ Thread* self = Thread::Current();
+ JNIEnv* env = self->GetJniEnv();
ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
CHECK(cause.get() != NULL);
env->ExceptionClear();
+ bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error);
+ env->Throw(cause.get());
- if (env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error)) {
- // We only wrap non-Error exceptions; an Error can just be used as-is.
- env->Throw(cause.get());
- return;
+ // We only wrap non-Error exceptions; an Error can just be used as-is.
+ if (!is_error) {
+ self->ThrowNewWrappedException("Ljava/lang/ExceptionInInitializerError;", NULL);
}
-
- jmethodID mid = env->GetMethodID(WellKnownClasses::java_lang_ExceptionInInitializerError, "<init>" , "(Ljava/lang/Throwable;)V");
- CHECK(mid != NULL);
-
- ScopedLocalRef<jthrowable> eiie(env,
- reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ExceptionInInitializerError, mid, cause.get())));
- env->Throw(eiie.get());
}
static size_t Hash(const char* s) {
@@ -477,9 +472,6 @@
Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;");
Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;");
- Heap* heap = Runtime::Current()->GetHeap();
- heap->SetWellKnownClasses(java_lang_ref_FinalizerReference, java_lang_ref_ReferenceQueue);
-
const DexFile& java_lang_dex = FindDexFile(java_lang_ref_Reference->GetDexCache());
Field* pendingNext = java_lang_ref_Reference->GetInstanceField(0);
@@ -512,6 +504,7 @@
CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_,
GetClassRoot(kJavaLangObject)->GetDexTypeIndex());
+ Heap* heap = Runtime::Current()->GetHeap();
heap->SetReferenceOffsets(referent->GetOffset(),
queue->GetOffset(),
queueNext->GetOffset(),
@@ -1139,18 +1132,14 @@
std::string class_name_string(DescriptorToDot(descriptor));
ScopedThreadStateChange tsc(self, kNative);
JNIEnv* env = self->GetJniEnv();
- ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
- CHECK(c.get() != NULL);
- // TODO: cache method?
- jmethodID mid = env->GetMethodID(c.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- CHECK(mid != NULL);
ScopedLocalRef<jobject> class_name_object(env, env->NewStringUTF(class_name_string.c_str()));
if (class_name_object.get() == NULL) {
return NULL;
}
ScopedLocalRef<jobject> class_loader_object(env, AddLocalReference<jobject>(env, class_loader));
CHECK(class_loader_object.get() != NULL);
- ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(), mid,
+ ScopedLocalRef<jobject> result(env, env->CallObjectMethod(class_loader_object.get(),
+ WellKnownClasses::java_lang_ClassLoader_loadClass,
class_name_object.get()));
if (env->ExceptionCheck()) {
// If the ClassLoader threw, pass that exception up.
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index a8101ba..1440023 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -760,10 +760,7 @@
// In the case of checked exceptions that aren't declared, the exception must be wrapped by
// a UndeclaredThrowableException.
Throwable* exception = thread->GetException();
- thread->ClearException();
- if (!exception->IsCheckedException()) {
- thread->SetException(exception);
- } else {
+ if (exception->IsCheckedException()) {
SynthesizedProxyClass* proxy_class =
down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
int throws_index = -1;
@@ -782,10 +779,8 @@
Class* declared_exception = declared_exceptions->Get(i);
declares_exception = declared_exception->IsAssignableFrom(exception_class);
}
- if (declares_exception) {
- thread->SetException(exception);
- } else {
- ThrowNewUndeclaredThrowableException(thread, env, exception);
+ if (!declares_exception) {
+ ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
}
}
}
diff --git a/src/heap.cc b/src/heap.cc
index bc59cfc..e50a31c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -142,8 +142,6 @@
is_gc_running_(false),
num_bytes_allocated_(0),
num_objects_allocated_(0),
- java_lang_ref_FinalizerReference_(NULL),
- java_lang_ref_ReferenceQueue_(NULL),
reference_referent_offset_(0),
reference_queue_offset_(0),
reference_queueNext_offset_(0),
@@ -728,14 +726,6 @@
lock_->Unlock();
}
-void Heap::SetWellKnownClasses(Class* java_lang_ref_FinalizerReference,
- Class* java_lang_ref_ReferenceQueue) {
- java_lang_ref_FinalizerReference_ = java_lang_ref_FinalizerReference;
- java_lang_ref_ReferenceQueue_ = java_lang_ref_ReferenceQueue;
- CHECK(java_lang_ref_FinalizerReference_ != NULL);
- CHECK(java_lang_ref_ReferenceQueue_ != NULL);
-}
-
void Heap::SetReferenceOffsets(MemberOffset reference_referent_offset,
MemberOffset reference_queue_offset,
MemberOffset reference_queueNext_offset,
@@ -813,26 +803,19 @@
void Heap::AddFinalizerReference(Thread* self, Object* object) {
ScopedThreadStateChange tsc(self, kRunnable);
- static Method* FinalizerReference_add =
- java_lang_ref_FinalizerReference_->FindDirectMethod("add", "(Ljava/lang/Object;)V");
- DCHECK(FinalizerReference_add != NULL);
JValue args[1];
args[0].SetL(object);
- FinalizerReference_add->Invoke(self, NULL, args, NULL);
+ DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self, NULL, args, NULL);
}
void Heap::EnqueueClearedReferences(Object** cleared) {
DCHECK(cleared != NULL);
if (*cleared != NULL) {
- static Method* ReferenceQueue_add =
- java_lang_ref_ReferenceQueue_->FindDirectMethod("add", "(Ljava/lang/ref/Reference;)V");
- DCHECK(ReferenceQueue_add != NULL);
-
Thread* self = Thread::Current();
ScopedThreadStateChange tsc(self, kRunnable);
JValue args[1];
args[0].SetL(*cleared);
- ReferenceQueue_add->Invoke(self, NULL, args, NULL);
+ DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(self, NULL, args, NULL);
*cleared = NULL;
}
}
diff --git a/src/heap.h b/src/heap.h
index 3f0ffc0..5b6b991 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -139,9 +139,6 @@
return mark_bitmap_;
}
- void SetWellKnownClasses(Class* java_lang_ref_FinalizerReference,
- Class* java_lang_ref_ReferenceQueue);
-
void SetReferenceOffsets(MemberOffset reference_referent_offset,
MemberOffset reference_queue_offset,
MemberOffset reference_queueNext_offset,
@@ -280,9 +277,6 @@
// Number of objects allocated. Adjusted after each allocation and free.
size_t num_objects_allocated_;
- Class* java_lang_ref_FinalizerReference_;
- Class* java_lang_ref_ReferenceQueue_;
-
// offset of java.lang.ref.Reference.referent
MemberOffset reference_referent_offset_;
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 03d668c..87d5449 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -522,6 +522,47 @@
}
}
+int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause) {
+ ScopedJniThreadState ts(env);
+
+ // Turn the const char* into a java.lang.String.
+ ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
+ if (msg != NULL && s.get() == NULL) {
+ return JNI_ERR;
+ }
+
+ // Choose an appropriate constructor and set up the arguments.
+ jvalue args[2];
+ const char* signature;
+ if (msg == NULL && cause == NULL) {
+ signature = "()V";
+ } else if (msg != NULL && cause == NULL) {
+ signature = "(Ljava/lang/String;)V";
+ args[0].l = s.get();
+ } else if (msg == NULL && cause != NULL) {
+ signature = "(Ljava/lang/Throwable;)V";
+ args[0].l = cause;
+ } else {
+ signature = "(Ljava/lang/String;Ljava/lang/Throwable;)V";
+ args[0].l = s.get();
+ args[1].l = cause;
+ }
+ jmethodID mid = env->GetMethodID(exception_class, "<init>", signature);
+ if (mid == NULL) {
+ LOG(ERROR) << "No <init>" << signature << " in " << PrettyClass(Decode<Class*>(env, exception_class));
+ return JNI_ERR;
+ }
+
+ ScopedLocalRef<jthrowable> exception(env, reinterpret_cast<jthrowable>(env->NewObjectA(exception_class, mid, args)));
+ if (exception.get() == NULL) {
+ return JNI_ERR;
+ }
+
+ ts.Self()->SetException(Decode<Throwable*>(ts, exception.get()));
+
+ return JNI_OK;
+}
+
static jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) {
if (vm == NULL || p_env == NULL) {
return JNI_ERR;
@@ -821,29 +862,7 @@
}
static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
- ScopedJniThreadState ts(env);
- // TODO: check for a pending exception to decide what constructor to call.
- jmethodID mid = ((msg != NULL)
- ? env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V")
- : env->GetMethodID(c, "<init>", "()V"));
- if (mid == NULL) {
- return JNI_ERR;
- }
- ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
- if (msg != NULL && s.get() == NULL) {
- return JNI_ERR;
- }
-
- jvalue args[1];
- args[0].l = s.get();
- ScopedLocalRef<jthrowable> exception(env, reinterpret_cast<jthrowable>(env->NewObjectA(c, mid, args)));
- if (exception.get() == NULL) {
- return JNI_ERR;
- }
-
- ts.Self()->SetException(Decode<Throwable*>(ts, exception.get()));
-
- return JNI_OK;
+ return ThrowNewException(env, c, msg, NULL);
}
static jboolean ExceptionCheck(JNIEnv* env) {
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 2964bba..389c96b 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -87,6 +87,8 @@
JValue InvokeWithJValues(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args);
JValue InvokeWithJValues(Thread* self, Object* receiver, Method* m, JValue* args);
+int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
+
struct JavaVMExt : public JavaVM {
JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options);
~JavaVMExt();
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 26f61cf..37cacb4 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -188,10 +188,7 @@
// In the case of checked exceptions that aren't declared, the exception must be wrapped by
// a UndeclaredThrowableException.
Throwable* exception = self->GetException();
- self->ClearException();
- if (!exception->IsCheckedException()) {
- self->SetException(exception);
- } else {
+ if (exception->IsCheckedException()) {
SynthesizedProxyClass* proxy_class =
down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
int throws_index = -1;
@@ -210,10 +207,8 @@
Class* declared_exception = declared_exceptions->Get(i);
declares_exception = declared_exception->IsAssignableFrom(exception_class);
}
- if (declares_exception) {
- self->SetException(exception);
- } else {
- ThrowNewUndeclaredThrowableException(self, env, exception);
+ if (!declares_exception) {
+ self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
}
}
}
diff --git a/src/object.cc b/src/object.cc
index d91e70c..7e73e8d 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -37,6 +37,7 @@
#include "runtime_support.h"
#include "stack.h"
#include "utils.h"
+#include "well_known_classes.h"
#if defined(ART_USE_LLVM_COMPILER)
#include "compiler_llvm/inferred_reg_category_map.h"
@@ -932,8 +933,7 @@
}
bool Class::IsThrowableClass() const {
- Class* throwable = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Throwable;");
- return throwable->IsAssignableFrom(this);
+ return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this);
}
ClassLoader* Class::GetClassLoader() const {
@@ -1485,12 +1485,10 @@
}
bool Throwable::IsCheckedException() const {
- Class* error = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Error;");
- if (InstanceOf(error)) {
+ if (InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Error))) {
return false;
}
- Class* jlre = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/RuntimeException;");
- return !InstanceOf(jlre);
+ return !InstanceOf(WellKnownClasses::ToClass(WellKnownClasses::java_lang_RuntimeException));
}
std::string Throwable::Dump() const {
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 8d649a6..903bbf9 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -609,18 +609,4 @@
return klass;
}
-void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
- jmethodID jlre_UTE_constructor = env->GetMethodID(WellKnownClasses::java_lang_reflect_UndeclaredThrowableException, "<init>",
- "(Ljava/lang/Throwable;)V");
- jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
- ScopedLocalRef<jthrowable> jlr_UTE(env,
- reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_reflect_UndeclaredThrowableException,
- jlre_UTE_constructor, jexception)));
- int rc = env->Throw(jlr_UTE.get());
- if (rc != JNI_OK) {
- LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
- }
- CHECK(self->IsExceptionPending());
-}
-
} // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 50b6735..d96cab9 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -214,8 +214,6 @@
return class_linker->ResolveString(string_idx, referrer);
}
-extern void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception);
-
} // namespace art
#endif // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index 5c221e8..d1458b2 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1440,6 +1440,11 @@
}
void Thread::ThrowNewException(const char* exception_class_descriptor, const char* msg) {
+ CHECK(!IsExceptionPending()); // Callers should either clear or call ThrowNewWrappedException.
+ ThrowNewWrappedException(exception_class_descriptor, msg);
+}
+
+void Thread::ThrowNewWrappedException(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);
@@ -1447,6 +1452,9 @@
descriptor.erase(descriptor.length() - 1);
JNIEnv* env = GetJniEnv();
+ jobject cause = env->ExceptionOccurred();
+ env->ExceptionClear();
+
ScopedLocalRef<jclass> exception_class(env, env->FindClass(descriptor.c_str()));
if (exception_class.get() == NULL) {
LOG(ERROR) << "Couldn't throw new " << descriptor << " because JNI FindClass failed: "
@@ -1473,7 +1481,7 @@
}
return;
}
- int rc = env->ThrowNew(exception_class.get(), msg);
+ int rc = ::art::ThrowNewException(env, exception_class.get(), msg, cause);
if (rc != JNI_OK) {
LOG(ERROR) << "Couldn't throw new " << descriptor << " because JNI ThrowNew failed: "
<< PrettyTypeOf(GetException());
diff --git a/src/thread.h b/src/thread.h
index 91ea568..951aa2a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -247,9 +247,13 @@
top_of_managed_stack_pc_ = pc;
}
- // 'msg' may be NULL.
+ // If 'msg' is NULL, no detail message is set.
void ThrowNewException(const char* exception_class_descriptor, const char* msg);
+ // If 'msg' is NULL, no detail message is set. An exception must be pending, and will be
+ // used as the new exception's cause.
+ void ThrowNewWrappedException(const char* exception_class_descriptor, const char* msg);
+
void ThrowNewExceptionF(const char* exception_class_descriptor, const char* fmt, ...)
__attribute__((format(printf, 3, 4)));
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index c89771a..20e71d5 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -29,23 +29,26 @@
jclass WellKnownClasses::java_lang_ClassNotFoundException;
jclass WellKnownClasses::java_lang_Daemons;
jclass WellKnownClasses::java_lang_Error;
-jclass WellKnownClasses::java_lang_ExceptionInInitializerError;
jclass WellKnownClasses::java_lang_reflect_InvocationHandler;
jclass WellKnownClasses::java_lang_reflect_Method;
jclass WellKnownClasses::java_lang_reflect_Proxy;
-jclass WellKnownClasses::java_lang_reflect_UndeclaredThrowableException;
+jclass WellKnownClasses::java_lang_RuntimeException;
jclass WellKnownClasses::java_lang_Thread;
jclass WellKnownClasses::java_lang_Thread$UncaughtExceptionHandler;
jclass WellKnownClasses::java_lang_ThreadGroup;
jclass WellKnownClasses::java_lang_ThreadLock;
+jclass WellKnownClasses::java_lang_Throwable;
jclass WellKnownClasses::java_nio_ReadWriteDirectByteBuffer;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer;
jmethodID WellKnownClasses::com_android_dex_Dex_create;
jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init;
+jmethodID WellKnownClasses::java_lang_ClassLoader_loadClass;
jmethodID WellKnownClasses::java_lang_Daemons_requestHeapTrim;
jmethodID WellKnownClasses::java_lang_Daemons_start;
+jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
+jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
jmethodID WellKnownClasses::java_lang_reflect_InvocationHandler_invoke;
jmethodID WellKnownClasses::java_lang_Thread_init;
jmethodID WellKnownClasses::java_lang_Thread_run;
@@ -104,23 +107,30 @@
java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
java_lang_Daemons = CacheClass(env, "java/lang/Daemons");
java_lang_Error = CacheClass(env, "java/lang/Error");
- java_lang_ExceptionInInitializerError = CacheClass(env, "java/lang/ExceptionInInitializerError");
java_lang_reflect_InvocationHandler = CacheClass(env, "java/lang/reflect/InvocationHandler");
java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method");
java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy");
- java_lang_reflect_UndeclaredThrowableException = CacheClass(env, "java/lang/reflect/UndeclaredThrowableException");
+ java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException");
java_lang_Thread = CacheClass(env, "java/lang/Thread");
java_lang_Thread$UncaughtExceptionHandler = CacheClass(env, "java/lang/Thread$UncaughtExceptionHandler");
java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup");
java_lang_ThreadLock = CacheClass(env, "java/lang/ThreadLock");
+ java_lang_Throwable = CacheClass(env, "java/lang/Throwable");
java_nio_ReadWriteDirectByteBuffer = CacheClass(env, "java/nio/ReadWriteDirectByteBuffer");
org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
org_apache_harmony_dalvik_ddmc_DdmServer = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
com_android_dex_Dex_create = CacheMethod(env, com_android_dex_Dex, true, "create", "(Ljava/nio/ByteBuffer;)Lcom/android/dex/Dex;");
java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
+
+ ScopedLocalRef<jclass> java_lang_ref_FinalizerReference(env, env->FindClass("java/lang/ref/FinalizerReference"));
+ java_lang_ref_FinalizerReference_add = CacheMethod(env, java_lang_ref_FinalizerReference.get(), true, "add", "(Ljava/lang/Object;)V");
+ ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
+ java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
+
java_lang_reflect_InvocationHandler_invoke = CacheMethod(env, java_lang_reflect_InvocationHandler, false, "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index 613c47e..6a6dd60 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -37,23 +37,26 @@
static jclass java_lang_ClassNotFoundException;
static jclass java_lang_Daemons;
static jclass java_lang_Error;
- static jclass java_lang_ExceptionInInitializerError;
static jclass java_lang_reflect_InvocationHandler;
static jclass java_lang_reflect_Method;
static jclass java_lang_reflect_Proxy;
- static jclass java_lang_reflect_UndeclaredThrowableException;
+ static jclass java_lang_RuntimeException;
static jclass java_lang_Thread;
static jclass java_lang_ThreadGroup;
static jclass java_lang_ThreadLock;
static jclass java_lang_Thread$UncaughtExceptionHandler;
+ static jclass java_lang_Throwable;
static jclass java_nio_ReadWriteDirectByteBuffer;
static jclass org_apache_harmony_dalvik_ddmc_Chunk;
static jclass org_apache_harmony_dalvik_ddmc_DdmServer;
static jmethodID com_android_dex_Dex_create;
+ static jmethodID java_lang_ClassLoader_loadClass;
static jmethodID java_lang_ClassNotFoundException_init;
static jmethodID java_lang_Daemons_requestHeapTrim;
static jmethodID java_lang_Daemons_start;
+ static jmethodID java_lang_ref_FinalizerReference_add;
+ static jmethodID java_lang_ref_ReferenceQueue_add;
static jmethodID java_lang_reflect_InvocationHandler_invoke;
static jmethodID java_lang_Thread_init;
static jmethodID java_lang_Thread_run;