Assorted fixes

- Match ClassLinker::oat_files_ against cached oat file locations
- Have DexFile_isDexOptNeeded do checksum comparsion of oat to dex
- Complete TODO in Heap::Lock to use TryLock before switching to kVmWait
- Fix ThrowNew to use Throwable constructor without String when no msg is available

Change-Id: Ie9d7bfef9e80b77e5f7625a4d7c9c4a23c7b30b5
diff --git a/src/class_linker.cc b/src/class_linker.cc
index eda60ca..6dc44d1 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -585,7 +585,7 @@
   return FindOatFile(OatFile::DexFileToOatFilename(dex_file));
 }
 
-const OatFile* ClassLinker::FindOatFile(const std::string& location) {
+const OatFile* ClassLinker::FindOpenedOatFile(const std::string& location) {
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
@@ -593,23 +593,37 @@
       return oat_file;
     }
   }
+  return NULL;
+}
 
-  const OatFile* oat_file = OatFile::Open(location, "", NULL);
+const OatFile* ClassLinker::FindOatFile(const std::string& location) {
+  const OatFile* oat_file = FindOpenedOatFile(location);
+  if (oat_file != NULL) {
+    return oat_file;
+  }
+
+  oat_file = OatFile::Open(location, "", NULL);
   if (oat_file == NULL) {
     if (location.empty() || location[0] != '/') {
       LOG(ERROR) << "Failed to open oat file from " << location;
       return NULL;
     }
+
     // not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
     std::string cache_location = GetArtCacheOatFilenameOrDie(location);
+    oat_file = FindOpenedOatFile(cache_location);
+    if (oat_file != NULL) {
+      return oat_file;
+    }
     oat_file = OatFile::Open(cache_location, "", NULL);
     if (oat_file  == NULL) {
       LOG(ERROR) << "Failed to open oat file from " << location << " or " << cache_location << ".";
       return NULL;
     }
-
-
   }
+
+  CHECK(oat_file != NULL) << location;
+  oat_files_.push_back(oat_file);
   return oat_file;
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index 91d6259..2a3e74d 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -346,6 +346,8 @@
     return dex_caches_;
   }
 
+  const OatFile* FindOpenedOatFile(const std::string& location);
+
   Method* CreateProxyConstructor(Class* klass);
   Method* CreateProxyMethod(Class* klass, Method* prototype, ObjectArray<Class>* throws);
 
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index e6d45e3..9b29d25 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -184,11 +184,17 @@
     return JNI_TRUE;
   }
 
-  UniquePtr<const OatFile> oat_file(class_linker->FindOatFile(*dex_file.get()));
-  if (oat_file.get() == NULL) {
+  const OatFile* oat_file = class_linker->FindOatFile(*dex_file.get());
+  if (oat_file == NULL) {
     return JNI_TRUE;
   }
-
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation());
+  if (oat_dex_file == NULL) {
+    return JNI_TRUE;
+  }
+  if (oat_dex_file->GetDexFileChecksum() != dex_file->GetHeader().checksum_) {
+    return JNI_TRUE;
+  }
   return JNI_FALSE;
 }
 
diff --git a/src/heap.cc b/src/heap.cc
index d7c9584..73b6640 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -585,9 +585,15 @@
 }
 
 void Heap::Lock() {
-  // TODO: grab the lock, but put ourselves into Thread::kVmWait if it looks like
-  // we're going to have to wait on the mutex.
-  lock_->Lock();
+  // Grab the lock, but put ourselves into Thread::kVmWait if it looks
+  // like we're going to have to wait on the mutex. This prevents
+  // deadlock if another thread is calling CollectGarbageInternal,
+  // since they will have the heap lock and be waiting for mutators to
+  // suspend.
+  if (!lock_->TryLock()) {
+    ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
+    lock_->Lock();
+  }
 }
 
 void Heap::Unlock() {
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 7ce29d4..1d46526 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -696,7 +696,9 @@
   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 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V");
+    jmethodID mid = ((msg != NULL)
+                     ? env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V")
+                     : env->GetMethodID(c, "<init>", "()V"));
     if (mid == NULL) {
       return JNI_ERR;
     }