Don't scan image space when starting runtime.

Bug 10432288.
Find Classes and Strings from dex caches lazily rather than when the image is
loaded.
Make class status changes do notifies when there can be waiters.
For Class lookup there's a pathology if we always search dex caches and
so after 1000 failures move all classes into the class table.
Be consistent in using "const char*" for class linker descriptors as this
most easily agrees with the type in the dex file.
Improve the intern run-test so that it has a case of a literal contained in the
image.
Modify image_test to allow any valid lock word rather than expecting 0, ideally
we wouldn't see inflated monitors but we do due to NotifyAll (see bug 6961405).

Change-Id: Ia9bfa748eeccb9b4498784b97c6823141b1f6db8
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index d7398ca..e3a75cf 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -16,6 +16,10 @@
 
 #include "intern_table.h"
 
+#include "gc/space/image_space.h"
+#include "mirror/dex_cache.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/object-inl.h"
 #include "mirror/string.h"
 #include "thread.h"
 #include "UniquePtr.h"
@@ -23,8 +27,8 @@
 
 namespace art {
 
-InternTable::InternTable() : intern_table_lock_("InternTable lock"), is_dirty_(false) {
-}
+InternTable::InternTable()
+    : intern_table_lock_("InternTable lock"), is_dirty_(false) {}
 
 size_t InternTable::Size() const {
   MutexLock mu(Thread::Current(), intern_table_lock_);
@@ -34,11 +38,11 @@
 void InternTable::DumpForSigQuit(std::ostream& os) const {
   MutexLock mu(Thread::Current(), intern_table_lock_);
   os << "Intern table: " << strong_interns_.size() << " strong; "
-     << weak_interns_.size() << " weak; "
-     << image_strong_interns_.size() << " image strong\n";
+     << weak_interns_.size() << " weak\n";
 }
 
-void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
+void InternTable::VisitRoots(RootVisitor* visitor, void* arg,
+                             bool clean_dirty) {
   MutexLock mu(Thread::Current(), intern_table_lock_);
   for (const auto& strong_intern : strong_interns_) {
     visitor(strong_intern.second, arg);
@@ -46,10 +50,12 @@
   if (clean_dirty) {
     is_dirty_ = false;
   }
-  // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots.
+  // Note: we deliberately don't visit the weak_interns_ table and the immutable
+  // image roots.
 }
 
-mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) {
+mirror::String* InternTable::Lookup(Table& table, mirror::String* s,
+                                    uint32_t hash_code) {
   intern_table_lock_.AssertHeld(Thread::Current());
   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
     mirror::String* existing_string = it->second;
@@ -60,18 +66,15 @@
   return NULL;
 }
 
-mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) {
+mirror::String* InternTable::Insert(Table& table, mirror::String* s,
+                                    uint32_t hash_code) {
   intern_table_lock_.AssertHeld(Thread::Current());
   table.insert(std::make_pair(hash_code, s));
   return s;
 }
 
-void InternTable::RegisterStrong(mirror::String* s) {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
-  Insert(image_strong_interns_, s, s->GetHashCode());
-}
-
-void InternTable::Remove(Table& table, const mirror::String* s, uint32_t hash_code) {
+void InternTable::Remove(Table& table, const mirror::String* s,
+                         uint32_t hash_code) {
   intern_table_lock_.AssertHeld(Thread::Current());
   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
     if (it->second == s) {
@@ -81,6 +84,31 @@
   }
 }
 
+static mirror::String* LookupStringFromImage(mirror::String* s)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
+  if (image == NULL) {
+    return NULL;  // No image present.
+  }
+  mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
+  mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>();
+  const std::string utf8 = s->ToModifiedUtf8();
+  for (int32_t i = 0; i < dex_caches->GetLength(); ++i) {
+    mirror::DexCache* dex_cache = dex_caches->Get(i);
+    const DexFile* dex_file = dex_cache->GetDexFile();
+    // Binary search the dex file for the string index.
+    const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str());
+    if (string_id != NULL) {
+      uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
+      mirror::String* image = dex_cache->GetResolvedString(string_idx);
+      if (image != NULL) {
+        return image;
+      }
+    }
+  }
+  return NULL;
+}
+
 mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
   MutexLock mu(Thread::Current(), intern_table_lock_);
 
@@ -93,15 +121,16 @@
     if (strong != NULL) {
       return strong;
     }
-    // Check the image table for a match.
-    mirror::String* image = Lookup(image_strong_interns_, s, hash_code);
-    if (image != NULL) {
-      return image;
-    }
 
     // Mark as dirty so that we rescan the roots.
     Dirty();
 
+    // Check the image for a match.
+    mirror::String* image = LookupStringFromImage(s);
+    if (image != NULL) {
+      return Insert(strong_interns_, image, hash_code);
+    }
+
     // There is no match in the strong table, check the weak table.
     mirror::String* weak = Lookup(weak_interns_, s, hash_code);
     if (weak != NULL) {
@@ -110,7 +139,8 @@
       return Insert(strong_interns_, weak, hash_code);
     }
 
-    // No match in the strong table or the weak table. Insert into the strong table.
+    // No match in the strong table or the weak table. Insert into the strong
+    // table.
     return Insert(strong_interns_, s, hash_code);
   }
 
@@ -119,10 +149,10 @@
   if (strong != NULL) {
     return strong;
   }
-  // Check the image table for a match.
-  mirror::String* image = Lookup(image_strong_interns_, s, hash_code);
+  // Check the image for a match.
+  mirror::String* image = LookupStringFromImage(s);
   if (image != NULL) {
-    return image;
+    return Insert(weak_interns_, image, hash_code);
   }
   // Check the weak table for a match.
   mirror::String* weak = Lookup(weak_interns_, s, hash_code);
@@ -133,12 +163,15 @@
   return Insert(weak_interns_, s, hash_code);
 }
 
-mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
-  return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf16_length, utf8_data));
+mirror::String* InternTable::InternStrong(int32_t utf16_length,
+                                          const char* utf8_data) {
+  return InternStrong(mirror::String::AllocFromModifiedUtf8(
+      Thread::Current(), utf16_length, utf8_data));
 }
 
 mirror::String* InternTable::InternStrong(const char* utf8_data) {
-  return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data));
+  return InternStrong(
+      mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data));
 }
 
 mirror::String* InternTable::InternStrong(mirror::String* s) {