DO NOT MERGE Fix all unsafe caching to be like libcore.

This way, if a runtime is restarted within a process, we re-initialize all
the cached data.

Conflicts:

	src/native/java_lang_Runtime.cc -- nativeExit lost an argument in dalvik-dev

(cherry picked from commit 7756d5473fa27ce7e6ac7c31770eef7030431da4)

Change-Id: I6184fc20c2a9ec16c4b053584a4d1c3b64452d0f
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 57baee7..9af92da 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -194,6 +194,7 @@
 	src/trace.cc \
 	src/utf.cc \
 	src/utils.cc \
+	src/well_known_classes.cc \
 	src/zip_archive.cc \
 	src/verifier/gc_map.cc \
 	src/verifier/method_verifier.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index b73c2b0..c1382e2 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -52,6 +52,7 @@
 #include "thread.h"
 #include "UniquePtr.h"
 #include "utils.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -141,24 +142,17 @@
 
   env->ExceptionClear();
 
-  // TODO: add java.lang.Error to JniConstants?
-  ScopedLocalRef<jclass> error_class(env, env->FindClass("java/lang/Error"));
-  CHECK(error_class.get() != NULL);
-  if (env->IsInstanceOf(cause.get(), error_class.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;
   }
 
-  // TODO: add java.lang.ExceptionInInitializerError to JniConstants?
-  ScopedLocalRef<jclass> eiie_class(env, env->FindClass("java/lang/ExceptionInInitializerError"));
-  CHECK(eiie_class.get() != NULL);
-
-  jmethodID mid = env->GetMethodID(eiie_class.get(), "<init>" , "(Ljava/lang/Throwable;)V");
+  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(eiie_class.get(), mid, cause.get())));
+      reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ExceptionInInitializerError, mid, cause.get())));
   env->Throw(eiie.get());
 }
 
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 0db3187..a8101ba 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -28,6 +28,7 @@
 #include "thread.h"
 #include "thread_list.h"
 #include "verifier/method_verifier.h"
+#include "well_known_classes.h"
 
 #include <algorithm>
 #include <cstdarg>
@@ -729,22 +730,11 @@
     args->Set(i, val.GetL());
   }
 
-  // Get the InvocationHandler method and the field that holds it within the Proxy object
-  static jmethodID inv_hand_invoke_mid = NULL;
-  static jfieldID proxy_inv_hand_fid = NULL;
-  if (proxy_inv_hand_fid == NULL) {
-    ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
-    proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
-    ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
-    inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
-        "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
-  }
+  DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
 
-  DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
-
-  jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
+  jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
   // Call InvocationHandler.invoke
-  jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
+  jobject result = env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke, args_jobj);
 
   // Place result in stack args
   if (!thread->IsExceptionPending()) {
diff --git a/src/debugger.cc b/src/debugger.cc
index 2156482..342d548 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -34,6 +34,7 @@
 #include "space.h"
 #include "stack_indirect_reference_table.h"
 #include "thread_list.h"
+#include "well_known_classes.h"
 
 extern "C" void dlmalloc_walk_heap(void(*)(const void*, size_t, const void*, size_t, void*), void*);
 #ifndef HAVE_ANDROID_OS
@@ -2322,14 +2323,6 @@
   Thread* self = Thread::Current();
   JNIEnv* env = self->GetJniEnv();
 
-  static jclass Chunk_class = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
-  static jclass DdmServer_class = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
-  static jmethodID dispatch_mid = env->GetStaticMethodID(DdmServer_class, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
-  static jfieldID data_fid = env->GetFieldID(Chunk_class, "data", "[B");
-  static jfieldID length_fid = env->GetFieldID(Chunk_class, "length", "I");
-  static jfieldID offset_fid = env->GetFieldID(Chunk_class, "offset", "I");
-  static jfieldID type_fid = env->GetFieldID(Chunk_class, "type", "I");
-
   // Create a byte[] corresponding to 'buf'.
   ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(dataLen));
   if (dataArray.get() == NULL) {
@@ -2352,7 +2345,9 @@
   }
 
   // Call "private static Chunk dispatch(int type, byte[] data, int offset, int length)".
-  ScopedLocalRef<jobject> chunk(env, env->CallStaticObjectMethod(DdmServer_class, dispatch_mid, type, dataArray.get(), offset, length));
+  ScopedLocalRef<jobject> chunk(env, env->CallStaticObjectMethod(WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer,
+                                                                 WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch,
+                                                                 type, dataArray.get(), offset, length));
   if (env->ExceptionCheck()) {
     LOG(INFO) << StringPrintf("Exception thrown by dispatcher for 0x%08x", type);
     env->ExceptionDescribe();
@@ -2376,10 +2371,10 @@
    *
    * So we're pretty much stuck with copying data around multiple times.
    */
-  ScopedLocalRef<jbyteArray> replyData(env, reinterpret_cast<jbyteArray>(env->GetObjectField(chunk.get(), data_fid)));
-  length = env->GetIntField(chunk.get(), length_fid);
-  offset = env->GetIntField(chunk.get(), offset_fid);
-  type = env->GetIntField(chunk.get(), type_fid);
+  ScopedLocalRef<jbyteArray> replyData(env, reinterpret_cast<jbyteArray>(env->GetObjectField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data)));
+  length = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length);
+  offset = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset);
+  type = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type);
 
   VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", type, replyData.get(), offset, length);
   if (length == 0 || replyData.get() == NULL) {
@@ -2418,10 +2413,10 @@
   }
 
   JNIEnv* env = self->GetJniEnv();
-  static jclass DdmServer_class = CacheClass(env, "org/apache/harmony/dalvik/ddmc/DdmServer");
-  static jmethodID broadcast_mid = env->GetStaticMethodID(DdmServer_class, "broadcast", "(I)V");
   jint event = connect ? 1 /*DdmServer.CONNECTED*/ : 2 /*DdmServer.DISCONNECTED*/;
-  env->CallStaticVoidMethod(DdmServer_class, broadcast_mid, event);
+  env->CallStaticVoidMethod(WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer,
+                            WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast,
+                            event);
   if (env->ExceptionCheck()) {
     LOG(ERROR) << "DdmServer.broadcast " << event << " failed";
     env->ExceptionDescribe();
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 78f0fdc..f18b215 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -38,6 +38,7 @@
 #include "UniquePtr.h"
 #include "utf.h"
 #include "utils.h"
+#include "well_known_classes.h"
 #include "zip_archive.h"
 
 namespace art {
@@ -234,19 +235,11 @@
     return NULL;
   }
 
-  jclass c = env->FindClass("com/android/dex/Dex");
-  if (c == NULL) {
-    return NULL;
-  }
-
-  jmethodID mid = env->GetStaticMethodID(c, "create", "(Ljava/nio/ByteBuffer;)Lcom/android/dex/Dex;");
-  if (mid == NULL) {
-    return NULL;
-  }
-
   jvalue args[1];
   args[0].l = byte_buffer;
-  jobject local = env->CallStaticObjectMethodA(c, mid, args);
+  jobject local = env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex,
+                                               WellKnownClasses::com_android_dex_Dex_create,
+                                               args);
   if (local == NULL) {
     return NULL;
   }
diff --git a/src/heap.cc b/src/heap.cc
index 02e3ac7..bc59cfc 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -35,6 +35,7 @@
 #include "thread_list.h"
 #include "timing_logger.h"
 #include "UniquePtr.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -854,9 +855,7 @@
     return;
   }
   JNIEnv* env = Thread::Current()->GetJniEnv();
-  static jclass Daemons_class = CacheClass(env, "java/lang/Daemons");
-  static jmethodID Daemons_requestHeapTrim = env->GetStaticMethodID(Daemons_class, "requestHeapTrim", "()V");
-  env->CallStaticVoidMethod(Daemons_class, Daemons_requestHeapTrim);
+  env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons, WellKnownClasses::java_lang_Daemons_requestHeapTrim);
   CHECK(!env->ExceptionCheck());
 }
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 61f7c3c..03d668c 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -37,6 +37,7 @@
 #include "stringpiece.h"
 #include "thread.h"
 #include "UniquePtr.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -55,6 +56,16 @@
 static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
 static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check.
 
+void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods, size_t method_count) {
+  ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
+  if (c.get() == NULL) {
+    LOG(FATAL) << "Couldn't find class: " << jni_class_name;
+  }
+  if (env->RegisterNatives(c.get(), methods, method_count) != JNI_OK) {
+    LOG(FATAL) << "Failed to register natives methods: " << jni_class_name;
+  }
+}
+
 void SetJniGlobalsMax(size_t max) {
   if (max != 0) {
     gGlobalsMax = max;
@@ -511,17 +522,6 @@
   }
 }
 
-static jclass InitDirectByteBufferClass(JNIEnv* env) {
-  ScopedLocalRef<jclass> buffer_class(env, env->FindClass("java/nio/ReadWriteDirectByteBuffer"));
-  CHECK(buffer_class.get() != NULL);
-  return reinterpret_cast<jclass>(env->NewGlobalRef(buffer_class.get()));
-}
-
-static jclass GetDirectByteBufferClass(JNIEnv* env) {
-  static jclass buffer_class = InitDirectByteBufferClass(env);
-  return buffer_class;
-}
-
 static jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) {
   if (vm == NULL || p_env == NULL) {
     return JNI_ERR;
@@ -2315,32 +2315,26 @@
     CHECK(address != NULL); // TODO: ReportJniError
     CHECK_GT(capacity, 0); // TODO: ReportJniError
 
-    jclass buffer_class = GetDirectByteBufferClass(env);
-    jmethodID mid = env->GetMethodID(buffer_class, "<init>", "(II)V");
-    if (mid == NULL) {
-      return NULL;
-    }
-
     // At the moment, the Java side is limited to 32 bits.
     CHECK_LE(reinterpret_cast<uintptr_t>(address), 0xffffffff);
     CHECK_LE(capacity, 0xffffffff);
     jint address_arg = reinterpret_cast<jint>(address);
     jint capacity_arg = static_cast<jint>(capacity);
 
-    jobject result = env->NewObject(buffer_class, mid, address_arg, capacity_arg);
+    jobject result = env->NewObject(WellKnownClasses::java_nio_ReadWriteDirectByteBuffer,
+                                    WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_init,
+                                    address_arg, capacity_arg);
     return ts.Self()->IsExceptionPending() ? NULL : result;
   }
 
   static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
     ScopedJniThreadState ts(env);
-    static jfieldID fid = env->GetFieldID(GetDirectByteBufferClass(env), "effectiveDirectAddress", "I");
-    return reinterpret_cast<void*>(env->GetIntField(java_buffer, fid));
+    return reinterpret_cast<void*>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress));
   }
 
   static jlong GetDirectBufferCapacity(JNIEnv* env, jobject java_buffer) {
     ScopedJniThreadState ts(env);
-    static jfieldID fid = env->GetFieldID(GetDirectByteBufferClass(env), "capacity", "I");
-    return static_cast<jlong>(env->GetIntField(java_buffer, fid));
+    return static_cast<jlong>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_capacity));
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
@@ -3011,14 +3005,6 @@
   // The weak_globals table is visited by the GC itself (because it mutates the table).
 }
 
-jclass CacheClass(JNIEnv* env, const char* jni_class_name) {
-  ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
-  if (c.get() == NULL) {
-    return NULL;
-  }
-  return reinterpret_cast<jclass>(env->NewGlobalRef(c.get()));
-}
-
 }  // namespace art
 
 std::ostream& operator<<(std::ostream& os, const jobjectRefType& rhs) {
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 0d97aa4..2964bba 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -29,6 +29,13 @@
 #include <iosfwd>
 #include <string>
 
+#ifndef NATIVE_METHOD
+#define NATIVE_METHOD(className, functionName, signature) \
+  { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }
+#endif
+#define REGISTER_NATIVE_METHODS(jni_class_name) \
+  RegisterNativeMethods(env, jni_class_name, gMethods, arraysize(gMethods))
+
 namespace art {
 
 class ClassLoader;
@@ -41,7 +48,7 @@
 void SetJniGlobalsMax(size_t max);
 void JniAbort(const char* jni_function_name);
 void* FindNativeMethod(Thread* thread);
-jclass CacheClass(JNIEnv* env, const char* jni_class_name);
+void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods, size_t method_count);
 
 template<typename T> T Decode(JNIEnv*, jobject);
 template<typename T> T AddLocalReference(JNIEnv*, const Object*);
diff --git a/src/native/dalvik_system_DexFile.cc b/src/native/dalvik_system_DexFile.cc
index 96a1ac1..afa09b3 100644
--- a/src/native/dalvik_system_DexFile.cc
+++ b/src/native/dalvik_system_DexFile.cc
@@ -16,20 +16,19 @@
 
 #include <unistd.h>
 
-#include "class_loader.h"
 #include "class_linker.h"
+#include "class_loader.h"
 #include "dex_file.h"
 #include "image.h"
+#include "jni_internal.h"
 #include "logging.h"
 #include "os.h"
 #include "runtime.h"
-#include "space.h"
-#include "zip_archive.h"
-#include "toStringArray.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+#include "space.h"
+#include "toStringArray.h"
+#include "zip_archive.h"
 
 namespace art {
 
@@ -98,23 +97,23 @@
   }
   if (dex_file == NULL) {
     LOG(WARNING) << "Failed to open dex file: " << source;
-    jniThrowExceptionFmt(env, "java/io/IOException", "unable to open dex file: %s",
-                         source.c_str());
+    Thread::Current()->ThrowNewExceptionF("Ljava/io/IOException;", "Unable to open dex file: %s",
+                                          source.c_str());
     return 0;
   }
   return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
 }
 
-static const DexFile* toDexFile(JNIEnv* env, int dex_file_address) {
+static const DexFile* toDexFile(int dex_file_address) {
   const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
   if (dex_file == NULL) {
-    jniThrowNullPointerException(env, "dex_file == null");
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;", "dex_file == null");
   }
   return dex_file;
 }
 
-static void DexFile_closeDexFile(JNIEnv* env, jclass, jint cookie) {
-  const DexFile* dex_file = toDexFile(env, cookie);
+static void DexFile_closeDexFile(JNIEnv*, jclass, jint cookie) {
+  const DexFile* dex_file = toDexFile(cookie);
   if (dex_file == NULL) {
     return;
   }
@@ -127,7 +126,7 @@
 static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
                                         jint cookie) {
   ScopedThreadStateChange tsc(Thread::Current(), kRunnable);
-  const DexFile* dex_file = toDexFile(env, cookie);
+  const DexFile* dex_file = toDexFile(cookie);
   if (dex_file == NULL) {
     return NULL;
   }
@@ -150,7 +149,7 @@
 }
 
 static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jint cookie) {
-  const DexFile* dex_file = toDexFile(env, cookie);
+  const DexFile* dex_file = toDexFile(cookie);
   if (dex_file == NULL) {
     return NULL;
   }
@@ -175,7 +174,7 @@
 
   if (!OS::FileExists(filename.c_str())) {
     LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename.c_str() << "' does not exist";
-    jniThrowExceptionFmt(env, "java/io/FileNotFoundException", "%s", filename.c_str());
+    Thread::Current()->ThrowNewExceptionF("Ljava/io/FileNotFoundException;", "%s", filename.c_str());
     return JNI_TRUE;
   }
 
@@ -265,7 +264,7 @@
 };
 
 void register_dalvik_system_DexFile(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "dalvik/system/DexFile", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("dalvik/system/DexFile");
 }
 
 }  // namespace art
diff --git a/src/native/dalvik_system_VMDebug.cc b/src/native/dalvik_system_VMDebug.cc
index 49ef593..bb6f8bc 100644
--- a/src/native/dalvik_system_VMDebug.cc
+++ b/src/native/dalvik_system_VMDebug.cc
@@ -14,19 +14,17 @@
  * limitations under the License.
  */
 
-#include "class_linker.h"
-#include "debugger.h"
-#include "jni_internal.h"
-#include "trace.h"
-#include "hprof/hprof.h"
-#include "ScopedUtfChars.h"
-#include "toStringArray.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 #include <string.h>
 #include <unistd.h>
 
+#include "class_linker.h"
+#include "debugger.h"
+#include "hprof/hprof.h"
+#include "jni_internal.h"
+#include "ScopedUtfChars.h"
+#include "toStringArray.h"
+#include "trace.h"
+
 namespace art {
 
 static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) {
@@ -66,7 +64,7 @@
 
   int fd = dup(originalFd);
   if (fd < 0) {
-    jniThrowExceptionFmt(env, "java/lang/RuntimeException", "dup(%d) failed: %s", originalFd, strerror(errno));
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "dup(%d) failed: %s", originalFd, strerror(errno));
     return;
   }
 
@@ -115,20 +113,20 @@
   return Dbg::LastDebuggerActivity();
 }
 
-static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) {
-  jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
+static void VMDebug_startInstructionCounting(JNIEnv*, jclass) {
+  Thread::Current()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", "");
 }
 
-static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) {
-  jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
+static void VMDebug_stopInstructionCounting(JNIEnv*, jclass) {
+  Thread::Current()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", "");
 }
 
-static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) {
-  jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
+static void VMDebug_getInstructionCount(JNIEnv*, jclass, jintArray /*javaCounts*/) {
+  Thread::Current()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", "");
 }
 
-static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
-  jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
+static void VMDebug_resetInstructionCount(JNIEnv*, jclass) {
+  Thread::Current()->ThrowNewException("Ljava/lang/UnsupportedOperationException;", "");
 }
 
 static void VMDebug_printLoadedClasses(JNIEnv*, jclass, jint flags) {
@@ -156,7 +154,7 @@
 static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jobject javaFd) {
   // Only one of these may be NULL.
   if (javaFilename == NULL && javaFd == NULL) {
-    jniThrowNullPointerException(env, "fileName == null && fd == null");
+    Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "fileName == null && fd == null");
     return;
   }
 
@@ -175,7 +173,7 @@
   if (javaFd != NULL) {
     fd = jniGetFDFromFileDescriptor(env, javaFd);
     if (fd < 0) {
-      jniThrowException(env, "Ljava/lang/RuntimeException;", "Invalid file descriptor");
+      Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;", "Invalid file descriptor");
       return;
     }
   }
@@ -183,16 +181,16 @@
   int result = hprof::DumpHeap(filename.c_str(), fd, false);
   if (result != 0) {
     // TODO: ideally we'd throw something more specific based on actual failure
-    jniThrowException(env, "Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details");
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details: %d", result);
     return;
   }
 }
 
-static void VMDebug_dumpHprofDataDdms(JNIEnv* env, jclass) {
+static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
   int result = hprof::DumpHeap("[DDMS]", -1, true);
   if (result != 0) {
     // TODO: ideally we'd throw something more specific based on actual failure
-    jniThrowException(env, "Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details");
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details: %d", result);
     return;
   }
 }
@@ -255,7 +253,7 @@
 };
 
 void register_dalvik_system_VMDebug(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "dalvik/system/VMDebug", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
 }
 
 }  // namespace art
diff --git a/src/native/dalvik_system_VMRuntime.cc b/src/native/dalvik_system_VMRuntime.cc
index caac283..fbc2a01 100644
--- a/src/native/dalvik_system_VMRuntime.cc
+++ b/src/native/dalvik_system_VMRuntime.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <limits.h>
+
 #include "class_linker.h"
 #include "debugger.h"
 #include "jni_internal.h"
@@ -24,12 +26,8 @@
 #include "space.h"
 #include "thread.h"
 #include "thread_list.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 #include "toStringArray.h"
 
-#include <limits.h>
-
 namespace art {
 
 static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
@@ -187,7 +185,7 @@
 };
 
 void register_dalvik_system_VMRuntime(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "dalvik/system/VMRuntime", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("dalvik/system/VMRuntime");
 }
 
 }  // namespace art
diff --git a/src/native/dalvik_system_VMStack.cc b/src/native/dalvik_system_VMStack.cc
index e0862c3..ab82694 100644
--- a/src/native/dalvik_system_VMStack.cc
+++ b/src/native/dalvik_system_VMStack.cc
@@ -14,16 +14,14 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_loader.h"
+#include "jni_internal.h"
 #include "nth_caller_visitor.h"
 #include "object.h"
 #include "scoped_heap_lock.h"
 #include "scoped_thread_list_lock.h"
 #include "thread_list.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jobject GetThreadStack(JNIEnv* env, jobject javaThread) {
@@ -99,7 +97,7 @@
 };
 
 void register_dalvik_system_VMStack(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "dalvik/system/VMStack", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("dalvik/system/VMStack");
 }
 
 }  // namespace art
diff --git a/src/native/dalvik_system_Zygote.cc b/src/native/dalvik_system_Zygote.cc
index b4f69fb..65fadf2 100644
--- a/src/native/dalvik_system_Zygote.cc
+++ b/src/native/dalvik_system_Zygote.cc
@@ -25,7 +25,6 @@
 #include "cutils/sched_policy.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "JniConstants.h"
 #include "JNIHelp.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
@@ -375,7 +374,7 @@
 };
 
 void register_dalvik_system_Zygote(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "dalvik/system/Zygote", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("dalvik/system/Zygote");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_Class.cc b/src/native/java_lang_Class.cc
index 2cd7090..66c83c7 100644
--- a/src/native/java_lang_Class.cc
+++ b/src/native/java_lang_Class.cc
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_linker.h"
 #include "class_loader.h"
+#include "jni_internal.h"
 #include "nth_caller_visitor.h"
 #include "object.h"
 #include "object_utils.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -62,9 +61,9 @@
   if (c == NULL) {
     ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
     env->ExceptionClear();
-    static jclass ClassNotFoundException_class = CacheClass(env, "java/lang/ClassNotFoundException");
-    static jmethodID ctor = env->GetMethodID(ClassNotFoundException_class, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
-    jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(ClassNotFoundException_class, ctor, javaName, cause.get()));
+    jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
+                                                                  WellKnownClasses::java_lang_ClassNotFoundException_init,
+                                                                  javaName, cause.get()));
     env->Throw(cnfe);
     return NULL;
   }
@@ -89,8 +88,8 @@
 
 template<typename T>
 static jobjectArray ToArray(JNIEnv* env, const char* array_class_name, const std::vector<T*>& objects) {
-  jclass array_class = env->FindClass(array_class_name);
-  jobjectArray result = env->NewObjectArray(objects.size(), array_class, NULL);
+  ScopedLocalRef<jclass> array_class(env, env->FindClass(array_class_name));
+  jobjectArray result = env->NewObjectArray(objects.size(), array_class.get(), NULL);
   for (size_t i = 0; i < objects.size(); ++i) {
     ScopedLocalRef<jobject> object(env, AddLocalReference<jobject>(env, objects[i]));
     env->SetObjectArrayElement(result, i, object.get());
@@ -472,7 +471,7 @@
 };
 
 void register_java_lang_Class(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/Class", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/Class");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_Object.cc b/src/native/java_lang_Object.cc
index 7c79fc1..51e4581 100644
--- a/src/native/java_lang_Object.cc
+++ b/src/native/java_lang_Object.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "object.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jobject Object_internalClone(JNIEnv* env, jobject javaThis) {
@@ -50,7 +48,7 @@
 };
 
 void register_java_lang_Object(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/Object", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/Object");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_Runtime.cc b/src/native/java_lang_Runtime.cc
index 1b5520b..b7e81af 100644
--- a/src/native/java_lang_Runtime.cc
+++ b/src/native/java_lang_Runtime.cc
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
 #include <limits.h>
+#include <unistd.h>
 
 #include "heap.h"
 #include "jni_internal.h"
 #include "object.h"
 #include "runtime.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 #include "ScopedUtfChars.h"
 
 namespace art {
@@ -77,16 +75,16 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(Runtime, freeMemory, "()J"),
-    NATIVE_METHOD(Runtime, gc, "()V"),
-    NATIVE_METHOD(Runtime, maxMemory, "()J"),
-    NATIVE_METHOD(Runtime, nativeExit, "(IZ)V"),
-    NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;"),
-    NATIVE_METHOD(Runtime, totalMemory, "()J"),
+  NATIVE_METHOD(Runtime, freeMemory, "()J"),
+  NATIVE_METHOD(Runtime, gc, "()V"),
+  NATIVE_METHOD(Runtime, maxMemory, "()J"),
+  NATIVE_METHOD(Runtime, nativeExit, "(IZ)V"),
+  NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;"),
+  NATIVE_METHOD(Runtime, totalMemory, "()J"),
 };
 
 void register_java_lang_Runtime(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/lang/Runtime", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/Runtime");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_String.cc b/src/native/java_lang_String.cc
index 49bf234..f8fb4a7 100644
--- a/src/native/java_lang_String.cc
+++ b/src/native/java_lang_String.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "object.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 #ifdef HAVE__MEMCMP16
 // "count" is in 16-bit units.
 extern "C" uint32_t __memcmp16(const uint16_t* s0, const uint16_t* s1, size_t count);
@@ -108,7 +106,7 @@
 };
 
 void register_java_lang_String(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/String", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/String");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_System.cc b/src/native/java_lang_System.cc
index 741b319..b0d1eec 100644
--- a/src/native/java_lang_System.cc
+++ b/src/native/java_lang_System.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "object.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 /*
  * We make guarantees about the atomicity of accesses to primitive
  * variables.  These guarantees also apply to elements of arrays.
@@ -253,7 +251,7 @@
 };
 
 void register_java_lang_System(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/System");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index 197c1b9..e009157 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -22,8 +22,6 @@
 #include "thread.h"
 #include "thread_list.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jobject Thread_currentThread(JNIEnv* env, jclass) {
@@ -145,7 +143,7 @@
 };
 
 void register_java_lang_Thread(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/Thread", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/Thread");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_Throwable.cc b/src/native/java_lang_Throwable.cc
index 1d73027..625a34b 100644
--- a/src/native/java_lang_Throwable.cc
+++ b/src/native/java_lang_Throwable.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "thread.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) {
@@ -39,7 +37,7 @@
 };
 
 void register_java_lang_Throwable(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/Throwable", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/Throwable");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_VMClassLoader.cc b/src/native/java_lang_VMClassLoader.cc
index 3d96c47..a976933 100644
--- a/src/native/java_lang_VMClassLoader.cc
+++ b/src/native/java_lang_VMClassLoader.cc
@@ -19,8 +19,6 @@
 #include "ScopedUtfChars.h"
 #include "zip_archive.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader, jstring javaName) {
@@ -91,7 +89,7 @@
 };
 
 void register_java_lang_VMClassLoader(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/VMClassLoader", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/VMClassLoader");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_reflect_Array.cc b/src/native/java_lang_reflect_Array.cc
index 1c86aac..ea635d3 100644
--- a/src/native/java_lang_reflect_Array.cc
+++ b/src/native/java_lang_reflect_Array.cc
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_linker.h"
+#include "jni_internal.h"
 #include "object.h"
 #include "object_utils.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 // Recursively create an array with multiple dimensions.  Elements may be
@@ -150,7 +148,7 @@
 };
 
 void register_java_lang_reflect_Array(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/reflect/Array", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Array");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_reflect_Constructor.cc b/src/native/java_lang_reflect_Constructor.cc
index 5d0434d..1094d06 100644
--- a/src/native/java_lang_reflect_Constructor.cc
+++ b/src/native/java_lang_reflect_Constructor.cc
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_linker.h"
+#include "jni_internal.h"
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 /*
@@ -63,7 +61,7 @@
 };
 
 void register_java_lang_reflect_Constructor(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/reflect/Constructor", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Constructor");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_reflect_Field.cc b/src/native/java_lang_reflect_Field.cc
index 3e0c9d7..bd33c0e 100644
--- a/src/native/java_lang_reflect_Field.cc
+++ b/src/native/java_lang_reflect_Field.cc
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_linker.h"
+#include "jni_internal.h"
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
@@ -79,7 +77,7 @@
 
   o = Decode<Object*>(env, javaObj);
   Class* declaringClass = f->GetDeclaringClass();
-  if (!VerifyObjectInClass(env, o, declaringClass)) {
+  if (!VerifyObjectInClass(o, declaringClass)) {
     return false;
   }
   return true;
@@ -323,7 +321,7 @@
 };
 
 void register_java_lang_reflect_Field(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/reflect/Field", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Field");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_reflect_Method.cc b/src/native/java_lang_reflect_Method.cc
index a5a705b..bf5c850 100644
--- a/src/native/java_lang_reflect_Method.cc
+++ b/src/native/java_lang_reflect_Method.cc
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
 #include "class_linker.h"
+#include "jni_internal.h"
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
@@ -60,7 +58,7 @@
 };
 
 void register_java_lang_reflect_Method(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/reflect/Method", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Method");
 }
 
 }  // namespace art
diff --git a/src/native/java_lang_reflect_Proxy.cc b/src/native/java_lang_reflect_Proxy.cc
index bac20b0..eca6c32 100644
--- a/src/native/java_lang_reflect_Proxy.cc
+++ b/src/native/java_lang_reflect_Proxy.cc
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
+#include "class_linker.h"
 #include "jni_internal.h"
 #include "object.h"
-#include "class_linker.h"
-
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 
 namespace art {
 
@@ -40,7 +38,7 @@
 };
 
 void register_java_lang_reflect_Proxy(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/lang/reflect/Proxy", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Proxy");
 }
 
 }  // namespace art
diff --git a/src/native/java_util_concurrent_atomic_AtomicLong.cc b/src/native/java_util_concurrent_atomic_AtomicLong.cc
index 118b9e4..7caa23f 100644
--- a/src/native/java_util_concurrent_atomic_AtomicLong.cc
+++ b/src/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "object.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jboolean AtomicLong_VMSupportsCS8(JNIEnv*, jclass) {
@@ -30,7 +28,7 @@
 };
 
 void register_java_util_concurrent_atomic_AtomicLong(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/util/concurrent/atomic/AtomicLong", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("java/util/concurrent/atomic/AtomicLong");
 }
 
 }  // namespace art
diff --git a/src/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/src/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index ed36590..e3c31b0 100644
--- a/src/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/src/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -16,9 +16,7 @@
 
 #include "debugger.h"
 #include "logging.h"
-
-#include "JniConstants.h"  // Last to avoid problems with LOG redefinition.
-#include "ScopedPrimitiveArray.h"  // Last to avoid problems with LOG redefinition.
+#include "ScopedPrimitiveArray.h"
 
 namespace art {
 
@@ -34,7 +32,7 @@
 };
 
 void register_org_apache_harmony_dalvik_ddmc_DdmServer(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/ddmc/DdmServer", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmServer");
 }
 
 }  // namespace art
diff --git a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 88416af..3766546 100644
--- a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -15,15 +15,14 @@
  */
 
 #include "debugger.h"
+#include "jni_internal.h"
 #include "logging.h"
 #include "scoped_heap_lock.h"
 #include "scoped_thread_list_lock.h"
+#include "ScopedPrimitiveArray.h"
 #include "stack.h"
 #include "thread_list.h"
 
-#include "JniConstants.h"  // Last to avoid problems with LOG redefinition.
-#include "ScopedPrimitiveArray.h"  // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) {
@@ -162,7 +161,7 @@
 };
 
 void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/ddmc/DdmVmInternal", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal");
 }
 
 }  // namespace art
diff --git a/src/native/sun_misc_Unsafe.cc b/src/native/sun_misc_Unsafe.cc
index 8cc549a..360f241 100644
--- a/src/native/sun_misc_Unsafe.cc
+++ b/src/native/sun_misc_Unsafe.cc
@@ -17,8 +17,6 @@
 #include "jni_internal.h"
 #include "object.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 static jlong Unsafe_objectFieldOffset0(JNIEnv* env, jclass, jobject javaField) {
@@ -187,7 +185,7 @@
 };
 
 void register_sun_misc_Unsafe(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "sun/misc/Unsafe", gMethods, NELEM(gMethods));
+  REGISTER_NATIVE_METHODS("sun/misc/Unsafe");
 }
 
 }  // namespace art
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 66d0e2c..26f61cf 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -19,6 +19,7 @@
 #include "reflection.h"
 #include "runtime_support.h"
 #include "thread.h"
+#include "well_known_classes.h"
 
 #include "ScopedLocalRef.h"
 
@@ -161,19 +162,10 @@
     param_index++;
   }
   // Get the InvocationHandler method and the field that holds it within the Proxy object
-  static jmethodID inv_hand_invoke_mid = NULL;
-  static jfieldID proxy_inv_hand_fid = NULL;
-  if (proxy_inv_hand_fid == NULL) {
-    ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
-    proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
-    ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
-    inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
-        "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
-  }
-  DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
-  jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
+  DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
+  jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
   // Call InvocationHandler.invoke
-  jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
+  jobject result = env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke, args_jobj);
   // Place result in stack args
   if (!self->IsExceptionPending()) {
     Object* result_ref = self->DecodeJObject(result);
diff --git a/src/oatexec.cc b/src/oatexec.cc
index d080560..e8e2050 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -21,12 +21,13 @@
 #include <cstring>
 #include <string>
 
-#include "ScopedLocalRef.h"
-#include "UniquePtr.h"
 #include "jni.h"
 #include "logging.h"
-#include "toStringArray.h"
 #include "object.h"
+#include "ScopedLocalRef.h"
+#include "toStringArray.h"
+#include "UniquePtr.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -39,17 +40,12 @@
   }
   // We now have a Method instance.  We need to call its
   // getModifiers() method.
-  ScopedLocalRef<jclass> method(env, env->FindClass("java/lang/reflect/Method"));
-  if (method.get() == NULL) {
-    fprintf(stderr, "Failed to find class Method\n");
+  jmethodID mid = env->GetMethodID(WellKnownClasses::java_lang_reflect_Method, "getModifiers", "()I");
+  if (mid == NULL) {
+    fprintf(stderr, "Failed to find java.lang.reflect.Method.getModifiers\n");
     return false;
   }
-  jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
-  if (get_modifiers == NULL) {
-    fprintf(stderr, "Failed to find reflect.Method.getModifiers\n");
-    return false;
-  }
-  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
+  int modifiers = env->CallIntMethod(reflected.get(), mid);
   if ((modifiers & kAccPublic) == 0) {
     return false;
   }
diff --git a/src/reflection.cc b/src/reflection.cc
index 010211e..2b72944 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -21,8 +21,6 @@
 #include "object.h"
 #include "object_utils.h"
 
-#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
-
 namespace art {
 
 Method* gBoolean_valueOf;
@@ -62,7 +60,7 @@
   if (!m->IsStatic()) {
     // Check that the receiver is non-null and an instance of the field's declaring class.
     receiver = Decode<Object*>(env, javaReceiver);
-    if (!VerifyObjectInClass(env, receiver, declaring_class)) {
+    if (!VerifyObjectInClass(receiver, declaring_class)) {
       return NULL;
     }
 
@@ -117,18 +115,18 @@
   return AddLocalReference<jobject>(env, value.GetL());
 }
 
-bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) {
+bool VerifyObjectInClass(Object* o, Class* c) {
   const char* exception = NULL;
   if (o == NULL) {
-    exception = "java/lang/NullPointerException";
+    exception = "Ljava/lang/NullPointerException;";
   } else if (!o->InstanceOf(c)) {
-    exception = "java/lang/IllegalArgumentException";
+    exception = "Ljava/lang/IllegalArgumentException;";
   }
   if (exception != NULL) {
     std::string expected_class_name(PrettyDescriptor(c));
     std::string actual_class_name(PrettyTypeOf(o));
-    jniThrowExceptionFmt(env, exception, "expected receiver of type %s, but got %s",
-                         expected_class_name.c_str(), actual_class_name.c_str());
+    Thread::Current()->ThrowNewExceptionF(exception, "expected receiver of type %s, but got %s",
+                                          expected_class_name.c_str(), actual_class_name.c_str());
     return false;
   }
   return true;
diff --git a/src/reflection.h b/src/reflection.h
index 50c36d7..6b47440 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -38,7 +38,7 @@
 
 jobject InvokeMethod(JNIEnv* env, jobject method, jobject receiver, jobject args);
 
-bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c);
+bool VerifyObjectInClass(Object* o, Class* c);
 
 }  // namespace art
 
diff --git a/src/runtime.cc b/src/runtime.cc
index e033059..226334e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -43,9 +43,9 @@
 #include "trace.h"
 #include "UniquePtr.h"
 #include "verifier/method_verifier.h"
+#include "well_known_classes.h"
 
-// TODO: this drags in cutil/log.h, which conflicts with our logging.h.
-#include "JniConstants.h"
+#include "JniConstants.h" // Last to avoid LOG redefinition in ics-mr1-plus-art.
 
 namespace art {
 
@@ -516,21 +516,17 @@
   CHECK_EQ(self->GetState(), kNative);
 
   JNIEnv* env = self->GetJniEnv();
-  ScopedLocalRef<jclass> ClassLoader_class(env, env->FindClass("java/lang/ClassLoader"));
-  CHECK(ClassLoader_class.get() != NULL);
-  jmethodID getSystemClassLoader = env->GetStaticMethodID(ClassLoader_class.get(),
+  jmethodID getSystemClassLoader = env->GetStaticMethodID(WellKnownClasses::java_lang_ClassLoader,
                                                           "getSystemClassLoader",
                                                           "()Ljava/lang/ClassLoader;");
   CHECK(getSystemClassLoader != NULL);
-  ScopedLocalRef<jobject> class_loader(env, env->CallStaticObjectMethod(ClassLoader_class.get(),
+  ScopedLocalRef<jobject> class_loader(env, env->CallStaticObjectMethod(WellKnownClasses::java_lang_ClassLoader,
                                                                         getSystemClassLoader));
   CHECK(class_loader.get() != NULL);
 
   Thread::Current()->SetClassLoaderOverride(Decode<ClassLoader*>(env, class_loader.get()));
 
-  ScopedLocalRef<jclass> Thread_class(env, env->FindClass("java/lang/Thread"));
-  CHECK(Thread_class.get() != NULL);
-  jfieldID contextClassLoader = env->GetFieldID(Thread_class.get(),
+  jfieldID contextClassLoader = env->GetFieldID(WellKnownClasses::java_lang_Thread,
                                                 "contextClassLoader",
                                                 "Ljava/lang/ClassLoader;");
   CHECK(contextClassLoader != NULL);
@@ -595,11 +591,7 @@
   CHECK_EQ(self->GetState(), kNative);
 
   JNIEnv* env = self->GetJniEnv();
-  ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Daemons"));
-  CHECK(c.get() != NULL);
-  jmethodID mid = env->GetStaticMethodID(c.get(), "start", "()V");
-  CHECK(mid != NULL);
-  env->CallStaticVoidMethod(c.get(), mid);
+  env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons, WellKnownClasses::java_lang_Daemons_start);
   CHECK(!env->ExceptionCheck());
 
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
@@ -708,6 +700,7 @@
   // First set up JniConstants, which is used by both the runtime's built-in native
   // methods and libcore.
   JniConstants::init(env);
+  WellKnownClasses::Init(env);
 
   // Then set up the native methods provided by the runtime itself.
   RegisterRuntimeNativeMethods(env);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index f8b40a2..8d649a6 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -17,6 +17,7 @@
 #include "runtime_support.h"
 
 #include "ScopedLocalRef.h"
+#include "well_known_classes.h"
 
 double art_l2d(int64_t l) {
   return (double) l;
@@ -609,21 +610,15 @@
 }
 
 void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
-  ScopedLocalRef<jclass> jlr_UTE_class(env,
-      env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
-  if (jlr_UTE_class.get() == NULL) {
+  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\"";
-  } else {
-    jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>",
-                                                      "(Ljava/lang/Throwable;)V");
-    jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
-    ScopedLocalRef<jthrowable> jlr_UTE(env,
-        reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), 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());
 }
diff --git a/src/thread.cc b/src/thread.cc
index 01e0771..a986ed5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -50,6 +50,7 @@
 #include "thread_list.h"
 #include "utils.h"
 #include "verifier/gc_map.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -339,15 +340,16 @@
   jint thread_priority = GetNativePriority();
   jboolean thread_is_daemon = as_daemon;
 
-  ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Thread"));
-  ScopedLocalRef<jobject> peer(env, env->AllocObject(c.get()));
+  ScopedLocalRef<jobject> peer(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
   peer_ = DecodeJObject(peer.get());
   if (peer_ == NULL) {
     CHECK(IsExceptionPending());
     return;
   }
-  jmethodID mid = env->GetMethodID(c.get(), "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
-  env->CallNonvirtualVoidMethod(peer.get(), c.get(), mid, java_thread_group.get(), thread_name.get(), thread_priority, thread_is_daemon);
+  env->CallNonvirtualVoidMethod(peer.get(),
+                                WellKnownClasses::java_lang_Thread,
+                                WellKnownClasses::java_lang_Thread_init,
+                                java_thread_group.get(), thread_name.get(), thread_priority, thread_is_daemon);
   CHECK(!IsExceptionPending()) << " " << PrettyTypeOf(GetException());
   SetVmData(peer_, Thread::Current());
 
@@ -524,11 +526,10 @@
   os << "  | schedstat=( " << scheduler_stats << " )"
      << " utm=" << utime
      << " stm=" << stime
-     << " core=" << task_cpu
-     << " HZ=" << sysconf(_SC_CLK_TCK) << "\n";
-
-  os << "  | stackSize=" << PrettySize(stack_size_)
-     << " stack=" << reinterpret_cast<void*>(stack_begin_) << "-" << reinterpret_cast<void*>(stack_end_) << "\n";
+     << " core=" << task_cpu;
+  os << " HZ=" << sysconf(_SC_CLK_TCK) << "\n"
+     << "  | stack=" << reinterpret_cast<void*>(stack_begin_) << "-" << reinterpret_cast<void*>(stack_end_)
+     << " stackSize=" << PrettySize(stack_size_) << "\n";
 }
 
 #if !defined(ART_USE_LLVM_COMPILER)
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
new file mode 100644
index 0000000..7e21a66
--- /dev/null
+++ b/src/well_known_classes.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "well_known_classes.h"
+
+#include <stdlib.h>
+
+#include "logging.h"
+#include "ScopedLocalRef.h"
+
+namespace art {
+
+jclass WellKnownClasses::com_android_dex_Dex;
+jclass WellKnownClasses::java_lang_ClassLoader;
+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_Thread;
+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_Daemons_requestHeapTrim;
+jmethodID WellKnownClasses::java_lang_Daemons_start;
+jmethodID WellKnownClasses::java_lang_reflect_InvocationHandler_invoke;
+jmethodID WellKnownClasses::java_lang_Thread_init;
+jmethodID WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_init;
+jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
+jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
+
+jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
+jfieldID WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_capacity;
+jfieldID WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress;
+jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data;
+jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length;
+jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset;
+jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type;
+
+static jclass CacheClass(JNIEnv* env, const char* jni_class_name) {
+  ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
+  if (c.get() == NULL) {
+    LOG(FATAL) << "Couldn't find class: " << jni_class_name;
+  }
+  return reinterpret_cast<jclass>(env->NewGlobalRef(c.get()));
+}
+
+static jfieldID CacheField(JNIEnv* env, jclass c, const char* name, const char* signature) {
+  jfieldID fid = env->GetFieldID(c, name, signature);
+  if (fid == NULL) {
+    LOG(FATAL) << "Couldn't find field \"" << name << "\" with signature \"" << signature << "\"";
+  }
+  return fid;
+}
+
+static jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static, const char* name, const char* signature) {
+  jmethodID mid = is_static ? env->GetStaticMethodID(c, name, signature) : env->GetMethodID(c, name, signature);
+  if (mid == NULL) {
+    LOG(FATAL) << "Couldn't find method \"" << name << "\" with signature \"" << signature << "\"";
+  }
+  return mid;
+}
+
+void WellKnownClasses::Init(JNIEnv* env) {
+  com_android_dex_Dex = CacheClass(env, "com/android/dex/Dex");
+  java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
+  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_Thread = CacheClass(env, "java/lang/Thread");
+  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_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
+  java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()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_nio_ReadWriteDirectByteBuffer_init = CacheMethod(env, java_nio_ReadWriteDirectByteBuffer, false, "<init>", "(II)V");
+  org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V");
+  org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
+
+  java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, "h", "Ljava/lang/reflect/InvocationHandler;");
+  java_nio_ReadWriteDirectByteBuffer_capacity = CacheField(env, java_nio_ReadWriteDirectByteBuffer, "capacity", "I");
+  java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_ReadWriteDirectByteBuffer, "effectiveDirectAddress", "I");
+  org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, "data", "[B");
+  org_apache_harmony_dalvik_ddmc_Chunk_length = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, "length", "I");
+  org_apache_harmony_dalvik_ddmc_Chunk_offset = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, "offset", "I");
+  org_apache_harmony_dalvik_ddmc_Chunk_type = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, "type", "I");
+}
+
+}  // namespace art
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
new file mode 100644
index 0000000..5d45938
--- /dev/null
+++ b/src/well_known_classes.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_WELL_KNOWN_CLASSES_H_
+#define ART_SRC_WELL_KNOWN_CLASSES_H_
+
+#include "jni.h"
+
+namespace art {
+
+// Various classes used in JNI. We cache them so we don't have to keep looking
+// them up. Similar to libcore's JniConstants (except there's no overlap, so
+// we keep them separate).
+
+struct WellKnownClasses {
+  static void Init(JNIEnv* env);
+
+  static jclass com_android_dex_Dex;
+  static jclass java_lang_ClassLoader;
+  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_Thread;
+  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_ClassNotFoundException_init;
+  static jmethodID java_lang_Daemons_requestHeapTrim;
+  static jmethodID java_lang_Daemons_start;
+  static jmethodID java_lang_reflect_InvocationHandler_invoke;
+  static jmethodID java_lang_Thread_init;
+  static jmethodID java_nio_ReadWriteDirectByteBuffer_init;
+  static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_broadcast;
+  static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_dispatch;
+
+  static jfieldID java_lang_reflect_Proxy_h;
+  static jfieldID java_nio_ReadWriteDirectByteBuffer_capacity;
+  static jfieldID java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress;
+  static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data;
+  static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
+  static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
+  static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_type;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_WELL_KNOWN_CLASSES_H_