Add the -Xcheck:jni option.

And make sure the boolean is available in every JNIEnv, so we
don't have to look it up via Runtime and JavaVM every time we
need to use it.

Change-Id: I2d4b5d04ded196e7c7602406d854bb35227d767a
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index e23b162..1be9d76 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2037,9 +2037,10 @@
 static const size_t kMonitorTableInitialSize = 32; // Arbitrary.
 static const size_t kMonitorTableMaxSize = 4096; // Arbitrary sanity check.
 
-JNIEnvExt::JNIEnvExt(Thread* self)
+JNIEnvExt::JNIEnvExt(Thread* self, bool check_jni)
     : fns(&gNativeInterface),
       self(self),
+      check_jni(check_jni),
       critical(false),
       monitor_table("monitor table", kMonitorTableInitialSize, kMonitorTableMaxSize) {
   // TODO: kill these.
@@ -2179,9 +2180,10 @@
 static const size_t kPinTableInitialSize = 16;
 static const size_t kPinTableMaxSize = 1024;
 
-JavaVMExt::JavaVMExt(Runtime* runtime)
+JavaVMExt::JavaVMExt(Runtime* runtime, bool check_jni)
     : fns(&gInvokeInterface),
       runtime(runtime),
+      check_jni(check_jni),
       pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize) {
 }
 
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 03dbfa0..2935c73 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -15,25 +15,29 @@
 class Thread;
 
 struct JavaVMExt {
-  JavaVMExt(Runtime* runtime);
+  JavaVMExt(Runtime* runtime, bool check_jni);
 
   // Must be first to correspond with JNIEnv.
   const struct JNIInvokeInterface* fns;
 
   Runtime* runtime;
 
+  bool check_jni;
+
   // Used to hold references to pinned primitive arrays.
   ReferenceTable pin_table;
 };
 
 struct JNIEnvExt {
-  JNIEnvExt(Thread* self);
+  JNIEnvExt(Thread* self, bool check_jni);
 
   // Must be first to correspond with JavaVM.
   const struct JNINativeInterface* fns;
 
   Thread* self;
 
+  bool check_jni;
+
   // Are we in a "critical" JNI call?
   bool critical;
 
diff --git a/src/runtime.cc b/src/runtime.cc
index b167280c..2476837 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -180,6 +180,13 @@
   scoped_ptr<ParsedOptions> parsed(new ParsedOptions());
   const char* boot_class_path = getenv("BOOTCLASSPATH");
   parsed->boot_image_ = NULL;
+#ifdef NDEBUG
+  // CheckJNI is off by default for regular builds...
+  parsed->check_jni_ = false;
+#else
+  // ...but on by default in debug builds.
+  parsed->check_jni_ = true;
+#endif
   parsed->heap_initial_size_ = Heap::kInitialSize;
   parsed->heap_maximum_size_ = Heap::kMaximumSize;
   parsed->hook_vfprintf_ = vfprintf;
@@ -194,6 +201,8 @@
       parsed->boot_class_path_ = *reinterpret_cast<const std::vector<DexFile*>*>(options[i].second);
     } else if (option.starts_with("-Xbootimage:")) {
       parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
+    } else if (option.starts_with("-Xcheck:jni")) {
+      parsed->check_jni_ = true;
     } else if (option.starts_with("-Xms")) {
       parsed->heap_initial_size_ = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
     } else if (option.starts_with("-Xmx")) {
@@ -262,24 +271,24 @@
   Heap::Init(parsed_options->heap_initial_size_,
              parsed_options->heap_maximum_size_);
 
+  java_vm_.reset(reinterpret_cast<JavaVM*>(new JavaVMExt(this, parsed_options->check_jni_)));
+
   Thread::Init();
-  Thread* current_thread = Thread::Attach();
+  Thread* current_thread = Thread::Attach(this);
   thread_list_->Register(current_thread);
 
   class_linker_ = ClassLinker::Create(parsed_options->boot_class_path_);
 
-  java_vm_.reset(reinterpret_cast<JavaVM*>(new JavaVMExt(this)));
-
   return true;
 }
 
 bool Runtime::AttachCurrentThread(const char* name, JNIEnv** penv) {
-  return Thread::Attach() != NULL;
+  return Thread::Attach(instance_) != NULL;
 }
 
 bool Runtime::AttachCurrentThreadAsDaemon(const char* name, JNIEnv** penv) {
   // TODO: do something different for daemon threads.
-  return Thread::Attach() != NULL;
+  return Thread::Attach(instance_) != NULL;
 }
 
 bool Runtime::DetachCurrentThread() {
diff --git a/src/runtime.h b/src/runtime.h
index da46ee6..828e677 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -33,6 +33,7 @@
 
     std::vector<DexFile*> boot_class_path_;
     const char* boot_image_;
+    bool check_jni_;
     size_t heap_initial_size_;
     size_t heap_maximum_size_;
     jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
@@ -76,7 +77,7 @@
     return class_linker_;
   }
 
-  JavaVM* GetJavaVM() {
+  JavaVM* GetJavaVM() const {
     return java_vm_.get();
   }
 
diff --git a/src/thread.cc b/src/thread.cc
index e3c92d4..baa659c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -85,7 +85,7 @@
   return new_thread;
 }
 
-Thread* Thread::Attach() {
+Thread* Thread::Attach(const Runtime* runtime) {
   Thread* thread = new Thread;
   thread->InitCpu();
   thread->stack_limit_ = reinterpret_cast<byte*>(-1);  // TODO: getrlimit
@@ -103,7 +103,10 @@
       PLOG(FATAL) << "pthread_setspecific failed";
   }
 
-  thread->jni_env_ = reinterpret_cast<JNIEnv*>(new JNIEnvExt(thread));
+  JavaVMExt* vm = reinterpret_cast<JavaVMExt*>(runtime->GetJavaVM());
+  CHECK(vm != NULL);
+  bool check_jni = vm->check_jni;
+  thread->jni_env_ = reinterpret_cast<JNIEnv*>(new JNIEnvExt(thread, check_jni));
 
   return thread;
 }
diff --git a/src/thread.h b/src/thread.h
index 8bde370..de5893e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -118,7 +118,7 @@
   static Thread* Create(size_t stack_size);
 
   // Creates a new thread from the calling thread.
-  static Thread* Attach();
+  static Thread* Attach(const Runtime* runtime);
 
   static Thread* Current() {
     void* thread = pthread_getspecific(Thread::pthread_key_self_);