Initialize ClassLinker from image

Change-Id: Ibaf47b4181f7c6603a8b37e2eba8fa6509c927ed
diff --git a/src/calling_convention.cc b/src/calling_convention.cc
index d14857b..32e3ee2 100644
--- a/src/calling_convention.cc
+++ b/src/calling_convention.cc
@@ -24,7 +24,7 @@
 
 void ManagedRuntimeCallingConvention::Next() {
   CHECK(HasNext());
-  if (IsCurrentUserArg() && 
+  if (IsCurrentUserArg() &&
       GetMethod()->IsParamALongOrDouble(itr_args_)) {
     itr_longs_and_doubles_++;
     itr_slots_++;
diff --git a/src/casts.h b/src/casts.h
index a5e31c4..461df21 100644
--- a/src/casts.h
+++ b/src/casts.h
@@ -59,7 +59,7 @@
     implicit_cast<From*, To>(0);
   }
 
-  // 
+  //
   // assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
   return static_cast<To>(f);
 }
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 55aaff4..2e4aa9e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -14,25 +14,59 @@
 #include "object.h"
 #include "dex_file.h"
 #include "scoped_ptr.h"
+#include "space.h"
 #include "thread.h"
 #include "utils.h"
 
 namespace art {
 
-ClassLinker* ClassLinker::Create(const std::vector<DexFile*>& boot_class_path) {
+const char* ClassLinker::class_roots_descriptors_[kClassRootsMax] = {
+  "Ljava/lang/Class;",
+  "Ljava/lang/Object;",
+  "[Ljava/lang/Object;",
+  "Ljava/lang/String;",
+  "Ljava/lang/reflect/Field;",
+  "Ljava/lang/reflect/Method;",
+  "Ljava/lang/ClassLoader;",
+  "Ldalvik/system/BaseDexClassLoader;",
+  "Ldalvik/system/PathClassLoader;",
+  "Z",
+  "B",
+  "C",
+  "D",
+  "F",
+  "I",
+  "J",
+  "S",
+  "V",
+  "[Z",
+  "[B",
+  "[C",
+  "[D",
+  "[F",
+  "[I",
+  "[J",
+  "[S",
+};
+
+ClassLinker* ClassLinker::Create(const std::vector<DexFile*>& boot_class_path, Space* space) {
   scoped_ptr<ClassLinker> class_linker(new ClassLinker);
-  class_linker->Init(boot_class_path);
+  if (space == NULL) {
+    class_linker->Init(boot_class_path);
+  } else {
+    class_linker->Init(boot_class_path, space);
+  }
   // TODO: check for failure during initialization
   return class_linker.release();
 }
 
+
 void ClassLinker::Init(const std::vector<DexFile*>& boot_class_path) {
   CHECK(!init_done_);
 
   // java_lang_Class comes first, its needed for AllocClass
   Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(Class)));
   CHECK(java_lang_Class != NULL);
-  // java_lang_Class->descriptor_ = "Ljava/lang/Class;";  // XXX bdc can these be created later?
   java_lang_Class->object_size_ = sizeof(Class);
   java_lang_Class->klass_ = java_lang_Class;
   // AllocClass(Class*) can now be used
@@ -40,7 +74,6 @@
   // java_lang_Object comes next so that object_array_class can be created
   Class* java_lang_Object = AllocClass(java_lang_Class);
   CHECK(java_lang_Object != NULL);
-  // java_lang_Object->descriptor_ = "Ljava/lang/Object;";  // XXX bdc can these be created later?
   // backfill Object as the super class of Class
   java_lang_Class->super_class_ = java_lang_Object;
   // mark as non-primitive for object_array_class
@@ -49,19 +82,16 @@
   // object_array_class is for root_classes to provide the storage for these classes
   Class* object_array_class = AllocClass(java_lang_Class);
   CHECK(object_array_class != NULL);
-  // object_array_class->descriptor_ = "[Ljava/lang/Object;";  // XXX bdc can these be created later?
   object_array_class->component_type_ = java_lang_Object;
 
   // String and char[] are necessary so that FindClass can assign names to members
   Class* java_lang_String = AllocClass(java_lang_Class);
   CHECK(java_lang_String != NULL);
-  // java_lang_String->descriptor_ = "Ljava/lang/String;";  // XXX can these be created later?
   CHECK_LT(java_lang_String->object_size_, sizeof(String));
   java_lang_String->object_size_ = sizeof(String);
-  String::InitClass(java_lang_String);
+  String::SetClass(java_lang_String);
   Class* char_array_class = AllocClass(java_lang_Class);
   CHECK(char_array_class != NULL);
-  // char_array_class->descriptor_ = "[C";  // XXX can these be created later?
   CharArray::SetArrayClass(char_array_class);
   // Now String::Alloc* can be used
 
@@ -96,15 +126,15 @@
 
   // create storage for root classes, save away our work so far
   class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
-  class_roots_->Set(kJavaLangClass, java_lang_Class);
-  class_roots_->Set(kJavaLangObject, java_lang_Object);
-  class_roots_->Set(kObjectArrayClass, object_array_class);
-  class_roots_->Set(kJavaLangString, java_lang_String);
-  class_roots_->Set(kCharArrayClass, char_array_class);
-  class_roots_->Set(kIntArrayClass, int_array_class);
-  class_roots_->Set(kLongArrayClass, long_array_class);
-  class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
-  class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
+  SetClassRoot(kJavaLangClass, java_lang_Class);
+  SetClassRoot(kJavaLangObject, java_lang_Object);
+  SetClassRoot(kObjectArrayClass, object_array_class);
+  SetClassRoot(kJavaLangString, java_lang_String);
+  SetClassRoot(kCharArrayClass, char_array_class);
+  SetClassRoot(kIntArrayClass, int_array_class);
+  SetClassRoot(kLongArrayClass, long_array_class);
+  SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
+  SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
   // setup boot_class_path_ now that we can use AllocObjectArray to
@@ -143,15 +173,15 @@
   CHECK(java_lang_ClassLoader != NULL);
   CHECK_LT(java_lang_ClassLoader->object_size_, sizeof(ClassLoader));
   java_lang_ClassLoader->object_size_ = sizeof(ClassLoader);
-  class_roots_->Set(kJavaLangClassLoader, java_lang_ClassLoader);
+  SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
   Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
   CHECK(dalvik_system_BaseDexClassLoader != NULL);
   CHECK_EQ(dalvik_system_BaseDexClassLoader->object_size_, sizeof(BaseDexClassLoader));
-  class_roots_->Set(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
+  SetClassRoot(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
   Class* dalvik_system_PathClassLoader = FindSystemClass("Ldalvik/system/PathClassLoader;");
   CHECK(dalvik_system_PathClassLoader != NULL);
   CHECK_EQ(dalvik_system_PathClassLoader->object_size_, sizeof(PathClassLoader));
-  class_roots_->Set(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
+  SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
 
   // Setup a single, global copy of "interfaces" and "iftable" for
   // reuse across array classes
@@ -181,15 +211,15 @@
   CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
 
   // Setup the primitive type classes.
-  class_roots_->Set(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
-  class_roots_->Set(kPrimitiveByte, CreatePrimitiveClass("B"));
-  class_roots_->Set(kPrimitiveChar, CreatePrimitiveClass("C"));
-  class_roots_->Set(kPrimitiveDouble, CreatePrimitiveClass("D"));
-  class_roots_->Set(kPrimitiveFloat, CreatePrimitiveClass("F"));
-  class_roots_->Set(kPrimitiveInt, CreatePrimitiveClass("I"));
-  class_roots_->Set(kPrimitiveLong, CreatePrimitiveClass("J"));
-  class_roots_->Set(kPrimitiveShort, CreatePrimitiveClass("S"));
-  class_roots_->Set(kPrimitiveVoid, CreatePrimitiveClass("V"));
+  SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
+  SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B"));
+  SetClassRoot(kPrimitiveChar, CreatePrimitiveClass("C"));
+  SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D"));
+  SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F"));
+  SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I"));
+  SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J"));
+  SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S"));
+  SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V"));
   // now we can use FindSystemClass for anything, including for "[C"
 
   // run char[], int[] and long[] through FindClass to complete initialization
@@ -202,20 +232,29 @@
 
   // Initialize all the other primitive array types for PrimitiveArray::Alloc.
   // These are easy because everything we need has already been set up.
-  class_roots_->Set(kBooleanArrayClass, FindSystemClass("[Z"));
-  class_roots_->Set(kByteArrayClass, FindSystemClass("[B"));
-  class_roots_->Set(kDoubleArrayClass, FindSystemClass("[D"));
-  class_roots_->Set(kFloatArrayClass, FindSystemClass("[F"));
-  class_roots_->Set(kShortArrayClass, FindSystemClass("[S"));
+  SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z"));
+  SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
+  SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
+  SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
+  SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
   BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
   ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
   DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
   FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
 
-  // ensure all class_roots_ were initialized
+  FinishInit();
+}
+
+void ClassLinker::FinishInit() {
+  // ensure all class_roots_ are initialized
   for (size_t i = 0; i < kClassRootsMax; i++) {
-    CHECK(GetClassRoot(static_cast<ClassRoot>(i)));
+    ClassRoot class_root = static_cast<ClassRoot>(i);
+    Class* klass = GetClassRoot(class_root);
+    CHECK(klass != NULL);
+    DCHECK(klass->IsArray() || klass->IsPrimitive() || klass->dex_cache_ != NULL);
+    // note SetClassRoot does additional validation.
+    // if possible add new checks there to catch errors early
   }
 
   // disable the slow paths in FindClass and CreatePrimitiveClass now
@@ -223,7 +262,125 @@
   init_done_ = true;
 }
 
-void ClassLinker::VisitRoots(Heap::RootVistor* root_visitor, void* arg) {
+struct ClassLinker::InitCallbackState {
+  ClassLinker* class_linker;
+
+  Class* class_roots[kClassRootsMax];
+
+  typedef std::tr1::unordered_map<std::string, ClassRoot> Table;
+  Table descriptor_to_class_root;
+
+  struct DexCacheHash {
+    size_t operator()(art::DexCache* const& obj) const {
+     return reinterpret_cast<size_t>(&obj);
+    }
+  };
+  typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
+  Set dex_caches;
+};
+
+void ClassLinker::Init(const std::vector<DexFile*>& boot_class_path, Space* space) {
+  CHECK(!init_done_);
+
+  HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+  DCHECK(heap_bitmap != NULL);
+
+  InitCallbackState state;
+  state.class_linker = this;
+  for (size_t i = 0; i < kClassRootsMax; i++) {
+    ClassRoot class_root = static_cast<ClassRoot>(i);
+    state.descriptor_to_class_root[GetClassRootDescriptor(class_root)] = class_root;
+  }
+
+  // reinit clases_ table
+  heap_bitmap->Walk(InitCallback, &state);
+
+  // reinit class_roots_
+  Class* object_array_class = state.class_roots[kObjectArrayClass];
+  class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
+  for (size_t i = 0; i < kClassRootsMax; i++) {
+    ClassRoot class_root = static_cast<ClassRoot>(i);
+    SetClassRoot(class_root, state.class_roots[class_root]);
+  }
+
+  // reinit intern_table_
+  ObjectArray<Object>* interned_array = space->GetImageHeader().GetInternedArray();
+  for (int32_t i = 0; i < interned_array->GetLength(); i++) {
+    String* string = interned_array->Get(i)->AsString();
+    intern_table_.Register(string);
+  }
+
+  // reinit array_interfaces_ from any array class instance, they should all be ==
+  array_interfaces_ = GetClassRoot(kObjectArrayClass)->interfaces_;
+  DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->interfaces_);
+
+  // build a map from location to DexCache to match up with DexFile::GetLocation
+  std::tr1::unordered_map<std::string, DexCache*> location_to_dex_cache;
+  typedef InitCallbackState::Set::const_iterator It; // TODO: C++0x auto
+  for (It it = state.dex_caches.begin(), end = state.dex_caches.end(); it != end; ++it) {
+    DexCache* dex_cache = *it;
+    std::string location = dex_cache->GetLocation()->ToModifiedUtf8();
+    location_to_dex_cache[location] = dex_cache;
+  }
+
+  // reinit boot_class_path with DexFile arguments and found DexCaches
+  for (size_t i = 0; i != boot_class_path.size(); ++i) {
+    DexFile* dex_file = boot_class_path[i];
+    DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+    AppendToBootClassPath(dex_file, dex_cache);
+  }
+
+  String::SetClass(GetClassRoot(kJavaLangString));
+  BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+  ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+  CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
+  DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+  FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+  IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
+  LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
+  ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+
+  FinishInit();
+}
+
+void ClassLinker::InitCallback(Object *obj, void *arg) {
+  DCHECK(obj != NULL);
+  DCHECK(arg != NULL);
+  InitCallbackState* state = reinterpret_cast<InitCallbackState*>(arg);
+
+  if (!obj->IsClass()) {
+    return;
+  }
+  Class* klass = obj->AsClass();
+  CHECK(klass->class_loader_ == NULL);
+
+  std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+
+  // restore class to ClassLinker::classes_ table
+  state->class_linker->InsertClass(descriptor, klass);
+
+  // note DexCache to match with DexFile later
+  DexCache* dex_cache = klass->GetDexCache();
+  if (dex_cache != NULL) {
+    state->dex_caches.insert(dex_cache);
+  } else {
+    DCHECK(klass->IsArray() || klass->IsPrimitive());
+  }
+
+  // check if this is a root, if so, register it
+  typedef InitCallbackState::Table::const_iterator It; // TODO: C++0x auto
+  It it = state->descriptor_to_class_root.find(descriptor);
+  if (it != state->descriptor_to_class_root.end()) {
+    ClassRoot class_root = it->second;
+    state->class_roots[class_root] = klass;
+  }
+}
+
+// Keep in sync with InitCallback. Anything we visit, we need to
+// reinit references to when reinitializing a ClassLinker from a
+// mapped image.
+void ClassLinker::VisitRoots(Heap::RootVistor* root_visitor, void* arg) const {
+
   root_visitor(class_roots_, arg);
 
   for (size_t i = 0; i < dex_caches_.size(); i++) {
@@ -243,8 +400,14 @@
   root_visitor(array_interfaces_, arg);
 }
 
-DexCache* ClassLinker::AllocDexCache() {
-  return down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::kMax));
+DexCache* ClassLinker::AllocDexCache(const DexFile* dex_file) {
+  DexCache* dex_cache = down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::kMax));
+  dex_cache->Init(String::AllocFromModifiedUtf8(dex_file->GetLocation().c_str()),
+                  AllocObjectArray<String>(dex_file->NumStringIds()),
+                  AllocObjectArray<Class>(dex_file->NumTypeIds()),
+                  AllocObjectArray<Method>(dex_file->NumMethodIds()),
+                  AllocObjectArray<Field>(dex_file->NumFieldIds()));
+  return dex_cache;
 }
 
 Class* ClassLinker::AllocClass(Class* java_lang_Class) {
@@ -537,21 +700,27 @@
   }
 }
 
-void ClassLinker::AppendToBootClassPath(DexFile* dex_file) {
+void ClassLinker::AppendToBootClassPath(const DexFile* dex_file) {
   CHECK(dex_file != NULL);
+  AppendToBootClassPath(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::AppendToBootClassPath(const DexFile* dex_file, DexCache* dex_cache) {
+  CHECK(dex_file != NULL);
+  CHECK(dex_cache != NULL);
   boot_class_path_.push_back(dex_file);
-  RegisterDexFile(dex_file);
+  RegisterDexFile(dex_file, dex_cache);
 }
 
 void ClassLinker::RegisterDexFile(const DexFile* dex_file) {
   CHECK(dex_file != NULL);
-  dex_files_.push_back(dex_file);
-  DexCache* dex_cache = AllocDexCache();
+  RegisterDexFile(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::RegisterDexFile(const DexFile* dex_file, DexCache* dex_cache) {
+  CHECK(dex_file != NULL);
   CHECK(dex_cache != NULL);
-  dex_cache->Init(AllocObjectArray<String>(dex_file->NumStringIds()),
-                  AllocObjectArray<Class>(dex_file->NumTypeIds()),
-                  AllocObjectArray<Method>(dex_file->NumMethodIds()),
-                  AllocObjectArray<Field>(dex_file->NumFieldIds()));
+  dex_files_.push_back(dex_file);
   dex_caches_.push_back(dex_cache);
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index bc7a780..ad29383 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -14,6 +14,7 @@
 #include "object.h"
 #include "thread.h"
 #include "unordered_map.h"
+#include "unordered_set.h"
 
 #include "gtest/gtest.h"
 
@@ -21,11 +22,20 @@
 
 class ClassLinker {
  public:
-  // Initializes the class linker.
-  static ClassLinker* Create(const std::vector<DexFile*>& boot_class_path);
+  // Initializes the class linker using DexFile and an optional boot Space.
+  static ClassLinker* Create(const std::vector<DexFile*>& boot_class_path, Space* boot_space);
 
   ~ClassLinker() {
     delete classes_lock_;
+    String::ResetClass();
+    BooleanArray::ResetArrayClass();
+    ByteArray::ResetArrayClass();
+    CharArray::ResetArrayClass();
+    DoubleArray::ResetArrayClass();
+    FloatArray::ResetArrayClass();
+    IntArray::ResetArrayClass();
+    LongArray::ResetArrayClass();
+    ShortArray::ResetArrayClass();
   }
 
   // Finds a class by its descriptor name.
@@ -43,17 +53,31 @@
   bool EnsureInitialized(Class* c);
 
   void RegisterDexFile(const DexFile* dex_file);
+  void RegisterDexFile(const DexFile* dex_file, DexCache* dex_cache);
 
-  void VisitRoots(Heap::RootVistor* root_visitor, void* arg);
+  const InternTable& GetInternTable() {
+    return intern_table_;
+  }
+
+  void VisitRoots(Heap::RootVistor* root_visitor, void* arg) const;
 
  private:
   ClassLinker()
       : classes_lock_(Mutex::Create("ClassLinker::Lock")),
+        class_roots_(NULL),
         init_done_(false) {
   }
 
+  // Initialize class linker from DexFile instances.
   void Init(const std::vector<DexFile*>& boot_class_path_);
 
+  // Initialize class linker from pre-initialized space.
+  void Init(const std::vector<DexFile*>& boot_class_path_, Space* space);
+  static void InitCallback(Object *obj, void *arg);
+  struct InitCallbackState;
+
+  void FinishInit();
+
   bool InitializeClass(Class* klass);
 
   // For early bootstrapping by Init
@@ -63,12 +87,12 @@
   // values that are known to the ClassLinker such as
   // kObjectArrayClass and kJavaLangString etc.
   Class* AllocClass();
-  DexCache* AllocDexCache();
+  DexCache* AllocDexCache(const DexFile* dex_file);
   Field* AllocField();
   Method* AllocMethod();
   template <class T>
   ObjectArray<T>* AllocObjectArray(size_t length) {
-    return ObjectArray<T>::Alloc(class_roots_->Get(kObjectArrayClass), length);
+    return ObjectArray<T>::Alloc(GetClassRoot(kObjectArrayClass), length);
   }
   PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
 
@@ -81,7 +105,8 @@
 
   DexCache* FindDexCache(const DexFile* dex_file) const;
 
-  void AppendToBootClassPath(DexFile* dex_file);
+  void AppendToBootClassPath(const DexFile* dex_file);
+  void AppendToBootClassPath(const DexFile* dex_file, DexCache* dex_cache);
 
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
@@ -165,7 +190,8 @@
 
   InternTable intern_table_;
 
-  // indexes into class_roots_
+  // indexes into class_roots_.
+  // needs to be kept in sync with class_roots_descriptors_.
   enum ClassRoot {
     kJavaLangClass,
     kJavaLangObject,
@@ -198,11 +224,33 @@
   ObjectArray<Class>* class_roots_;
 
   Class* GetClassRoot(ClassRoot class_root) {
+    DCHECK(class_roots_ != NULL);
     Class* klass = class_roots_->Get(class_root);
     DCHECK(klass != NULL);
     return klass;
   }
 
+  void SetClassRoot(ClassRoot class_root, Class* klass) {
+    DCHECK(!init_done_);
+
+    DCHECK(klass != NULL);
+    DCHECK(klass->class_loader_ == NULL);
+    DCHECK(klass->descriptor_ != NULL);
+    DCHECK(klass->descriptor_->Equals(GetClassRootDescriptor(class_root)));
+
+    DCHECK(class_roots_ != NULL);
+    DCHECK(class_roots_->Get(class_root) == NULL);
+    class_roots_->Set(class_root, klass);
+  }
+
+  static const char* class_roots_descriptors_[kClassRootsMax];
+
+  const char* GetClassRootDescriptor(ClassRoot class_root) {
+    const char* descriptor = class_roots_descriptors_[class_root];
+    CHECK(descriptor != NULL);
+    return descriptor;
+  }
+
   ObjectArray<Class>* array_interfaces_;
   InterfaceEntry* array_iftable_;
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 42a773c..88ddd07 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -134,11 +134,15 @@
       Method* method = klass->GetDirectMethod(i);
       EXPECT_TRUE(method != NULL);
       EXPECT_EQ(klass, method->GetDeclaringClass());
+      EXPECT_TRUE(method->GetName() != NULL);
+      EXPECT_TRUE(method->GetSignature() != NULL);
     }
 
     for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
       Method* method = klass->GetVirtualMethod(i);
       EXPECT_TRUE(method != NULL);
+      EXPECT_TRUE(method->GetName() != NULL);
+      EXPECT_TRUE(method->GetSignature() != NULL);
     }
 
     for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
@@ -146,6 +150,8 @@
       EXPECT_TRUE(field != NULL);
       EXPECT_FALSE(field->IsStatic());
       EXPECT_EQ(klass, field->GetDeclaringClass());
+      EXPECT_TRUE(field->GetName() != NULL);
+      EXPECT_TRUE(field->GetDescriptor() != NULL);
     }
 
     for (size_t i = 0; i < klass->NumStaticFields(); i++) {
@@ -153,22 +159,20 @@
       EXPECT_TRUE(field != NULL);
       EXPECT_TRUE(field->IsStatic());
       EXPECT_EQ(klass, field->GetDeclaringClass());
-    }
+      EXPECT_TRUE(field->GetName() != NULL);
+      EXPECT_TRUE(field->GetDescriptor() != NULL);
+   }
 
     // Confirm that all instances fields are packed together at the start
     EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
     for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
       Field* field = klass->GetInstanceField(i);
-      ASSERT_TRUE(field != NULL);
-      ASSERT_TRUE(field->GetDescriptor() != NULL);
       Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
       ASSERT_TRUE(field_type != NULL);
       EXPECT_FALSE(field_type->IsPrimitive());
     }
     for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
       Field* field = klass->GetInstanceField(i);
-      ASSERT_TRUE(field != NULL);
-      ASSERT_TRUE(field->GetDescriptor() != NULL);
       Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
       ASSERT_TRUE(field_type != NULL);
       EXPECT_TRUE(field_type->IsPrimitive());
@@ -207,7 +211,7 @@
 }
 
 TEST_F(ClassLinkerTest, FindClassNested) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex, "kNestedDex"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
 
   Class* outer = class_linker_->FindClass("LNested;", class_loader);
@@ -262,7 +266,7 @@
   EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
 
 
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex, "kMyClassDex"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   EXPECT_TRUE(linker->FindSystemClass("LMyClass;") == NULL);
   Class* MyClass = linker->FindClass("LMyClass;", class_loader);
@@ -378,8 +382,8 @@
 }
 
 TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
-  scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex));
-  scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex));
+  scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex, "kMyClassDex"));
+  scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex, "kMyClassDex"));
   PathClassLoader* class_loader_1 = AllocPathClassLoader(dex_1.get());
   PathClassLoader* class_loader_2 = AllocPathClassLoader(dex_2.get());
   Class* MyClass_1 = class_linker_->FindClass("LMyClass;", class_loader_1);
@@ -391,7 +395,7 @@
 
 TEST_F(ClassLinkerTest, StaticFields) {
   // TODO: uncomment expectations of initial values when InitializeClass works
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics, "kStatics"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* statics = class_linker_->FindClass("LStatics;", class_loader);
   // class_linker_->InitializeClass(statics);  // TODO: uncomment this
@@ -441,7 +445,7 @@
 
   Field* s8 = statics->GetStaticField(8);
   EXPECT_EQ('L', s8->GetType());
-//  EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("android"));  // TODO: uncomment this
+//  EXPECT_TRUE(s8->GetObject()->AsString()->Equals("android"));  // TODO: uncomment this
   s8->SetObject(String::AllocFromModifiedUtf8("robot"));
 
   Field* s9 = statics->GetStaticField(9);
@@ -457,7 +461,7 @@
   EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong());
   EXPECT_EQ(0.75,                 s6->GetFloat());
   EXPECT_EQ(16777219,             s7->GetDouble());
-  EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("robot"));
+  EXPECT_TRUE(s8->GetObject()->AsString()->Equals("robot"));
 }
 
 }  // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 14a68a2..685e627 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -277,12 +277,12 @@
   "AAwAAADgAAAABQAAAA4AAABwAQAABgAAAAEAAADgAQAAASAAAA0AAAAAAgAAARAAAAsAAAA4AwAA"
   "AiAAABYAAACuAwAAAyAAAA0AAABXBAAAACAAAAEAAAC3BAAAABAAAAEAAAD0BAAA";
 
-static inline DexFile* OpenDexFileBase64(const char* base64) {
+static inline DexFile* OpenDexFileBase64(const char* base64, const std::string& location) {
   CHECK(base64 != NULL);
   size_t length;
   byte* dex_bytes = DecodeBase64(base64, &length);
   CHECK(dex_bytes != NULL);
-  DexFile* dex_file = DexFile::OpenPtr(dex_bytes, length);
+  DexFile* dex_file = DexFile::OpenPtr(dex_bytes, length, location);
   CHECK(dex_file != NULL);
   return dex_file;
 }
diff --git a/src/dex_cache.cc b/src/dex_cache.cc
index 8ab4130..3bd04eb 100644
--- a/src/dex_cache.cc
+++ b/src/dex_cache.cc
@@ -8,14 +8,16 @@
 
 namespace art {
 
-void DexCache::Init(ObjectArray<String>* strings,
+void DexCache::Init(String* location,
+                    ObjectArray<String>* strings,
                     ObjectArray<Class>* classes,
                     ObjectArray<Method>* methods,
                     ObjectArray<Field>* fields) {
-  Set(kStrings, strings);
-  Set(kClasses, classes);
-  Set(kMethods, methods);
-  Set(kFields,  fields);
+  Set(kLocation, location);
+  Set(kStrings,  strings);
+  Set(kClasses,  classes);
+  Set(kMethods,  methods);
+  Set(kFields,   fields);
 }
 
 }  // namespace art
diff --git a/src/dex_cache.h b/src/dex_cache.h
index 5f3c54f..534a29b 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -19,18 +19,24 @@
  public:
 
   enum ArrayIndexes {
-    kStrings = 0,
-    kClasses = 1,
-    kMethods = 2,
-    kFields  = 3,
-    kMax     = 4,
+    kLocation = 0,
+    kStrings  = 1,
+    kClasses  = 2,
+    kMethods  = 3,
+    kFields   = 4,
+    kMax      = 5,
   };
 
-  void Init(ObjectArray<String>* strings,
+  void Init(String* location,
+            ObjectArray<String>* strings,
             ObjectArray<Class>* classes,
             ObjectArray<Method>* methods,
             ObjectArray<Field>* fields);
 
+  String* GetLocation() const {
+    return Get(kLocation)->AsString();
+  }
+
   size_t NumStrings() const {
     return GetStrings()->GetLength();
   }
@@ -81,16 +87,16 @@
 
  private:
   ObjectArray<String>* GetStrings() const {
-      return static_cast<ObjectArray<String>*>(Get(kStrings));
+    return static_cast<ObjectArray<String>*>(Get(kStrings));
   }
   ObjectArray<Class>* GetClasses() const {
-      return static_cast<ObjectArray<Class>*>(Get(kClasses));
+    return static_cast<ObjectArray<Class>*>(Get(kClasses));
   }
   ObjectArray<Method>* GetMethods() const {
-      return static_cast<ObjectArray<Method>*>(Get(kMethods));
+    return static_cast<ObjectArray<Method>*>(Get(kMethods));
   }
   ObjectArray<Field>* GetFields() const {
-      return static_cast<ObjectArray<Field>*>(Get(kFields));
+    return static_cast<ObjectArray<Field>*>(Get(kFields));
   }
   DexCache();
 };
diff --git a/src/dex_cache_test.cc b/src/dex_cache_test.cc
index cb682a0..674ec0f 100644
--- a/src/dex_cache_test.cc
+++ b/src/dex_cache_test.cc
@@ -16,16 +16,12 @@
 
 TEST_F(DexCacheTest, Open) {
 
-  DexCache* dex_cache = class_linker_->AllocDexCache();
+  DexCache* dex_cache = class_linker_->AllocDexCache(java_lang_dex_file_.get());
   ASSERT_TRUE(dex_cache != NULL);
-  dex_cache->Init(class_linker_->AllocObjectArray<String>(1),
-                  class_linker_->AllocObjectArray<Class>(2),
-                  class_linker_->AllocObjectArray<Method>(3),
-                  class_linker_->AllocObjectArray<Field>(4));
-  EXPECT_EQ(1U, dex_cache->NumStrings());
-  EXPECT_EQ(2U, dex_cache->NumClasses());
-  EXPECT_EQ(3U, dex_cache->NumMethods());
-  EXPECT_EQ(4U, dex_cache->NumFields());
+  EXPECT_EQ(java_lang_dex_file_->NumStringIds(), dex_cache->NumStrings());
+  EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),   dex_cache->NumClasses());
+  EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumMethods());
+  EXPECT_EQ(java_lang_dex_file_->NumFieldIds(),  dex_cache->NumFields());
 }
 
 }  // namespace art
diff --git a/src/dex_file.cc b/src/dex_file.cc
index b9ae7e3..14c62f1 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -77,7 +77,7 @@
   close(fd);
   byte* dex_file = reinterpret_cast<byte*>(addr);
   Closer* closer = new MmapCloser(addr, length);
-  return Open(dex_file, length, closer);
+  return Open(dex_file, length, filename, closer);
 }
 
 static const char* kClassesDex = "classes.dex";
@@ -294,15 +294,15 @@
   // NOTREACHED
 }
 
-DexFile* DexFile::OpenPtr(byte* ptr, size_t length) {
+DexFile* DexFile::OpenPtr(byte* ptr, size_t length, const std::string& location) {
   CHECK(ptr != NULL);
   DexFile::Closer* closer = new PtrCloser(ptr);
-  return Open(ptr, length, closer);
+  return Open(ptr, length, location, closer);
 }
 
 DexFile* DexFile::Open(const byte* dex_bytes, size_t length,
-                       Closer* closer) {
-  scoped_ptr<DexFile> dex_file(new DexFile(dex_bytes, length, closer));
+                       const std::string& location, Closer* closer) {
+  scoped_ptr<DexFile> dex_file(new DexFile(dex_bytes, length, location, closer));
   if (!dex_file->Init()) {
     return NULL;
   } else {
diff --git a/src/dex_file.h b/src/dex_file.h
index 2de46f8..b3f9bdd 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -288,13 +288,21 @@
   // Opens a .jar, .zip, or .apk file from the file system.
   static DexFile* OpenZip(const std::string& filename);
 
-  // Opens a .dex file from a new allocated pointer
-  static DexFile* OpenPtr(byte* ptr, size_t length);
+  // Opens a .dex file from a new allocated pointer.  location is used
+  // to identify the source, for example "/system/framework/core.jar"
+  // or "contrived-test-42". When initializing a ClassLinker from an
+  // image, the location is used to match DexCaches the image to their
+  // corresponding DexFiles.N
+  static DexFile* OpenPtr(byte* ptr, size_t length, const std::string& location);
 
   // Closes a .dex file.
   virtual ~DexFile();
 
-  const Header& GetHeader() {
+  const std::string& GetLocation() const {
+    return location_;
+  }
+
+  const Header& GetHeader() const {
     CHECK(header_ != NULL);
     return *header_;
   }
@@ -640,11 +648,12 @@
   };
 
   // Opens a .dex file at a the given address.
-  static DexFile* Open(const byte* dex_file, size_t length, Closer* closer);
+  static DexFile* Open(const byte* dex_file, size_t length, const std::string& location, Closer* closer);
 
-  DexFile(const byte* addr, size_t length, Closer* closer)
+  DexFile(const byte* addr, size_t length, const std::string& location, Closer* closer)
       : base_(addr),
         length_(length),
+        location_(location),
         closer_(closer),
         header_(0),
         string_ids_(0),
@@ -652,7 +661,11 @@
         field_ids_(0),
         method_ids_(0),
         proto_ids_(0),
-        class_defs_(0) {}
+        class_defs_(0) {
+    CHECK(addr != NULL);
+    CHECK_GT(length, 0U);
+    CHECK(closer != NULL);
+  }
 
   // Top-level initializer that calls other Init methods.
   bool Init();
@@ -679,6 +692,12 @@
   // The size of the underlying memory allocation in bytes.
   size_t length_;
 
+  // Typically the dex file name when availble, alternatively some identifying string.
+  //
+  // The ClassLinker will use this to match DexFiles the boot class
+  // path to DexCache::GetLocation when loading from an image.
+  const std::string location_;
+
   // Helper object to free the underlying allocation.
   scoped_ptr<Closer> closer_;
 
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 616e1c4..9eb5f73 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -10,12 +10,12 @@
 namespace art {
 
 TEST(DexFileTest, Open) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+  scoped_ptr<const DexFile> dex(OpenDexFileBase64(kNestedDex, "kNestedDex"));
   ASSERT_TRUE(dex != NULL);
 }
 
 TEST(DexFileTest, Header) {
-  scoped_ptr<DexFile> raw(OpenDexFileBase64(kNestedDex));
+  scoped_ptr<const DexFile> raw(OpenDexFileBase64(kNestedDex, "kNestedDex"));
   ASSERT_TRUE(raw != NULL);
 
   const DexFile::Header& header = raw->GetHeader();
@@ -43,7 +43,7 @@
 }
 
 TEST(DexFileTest, ClassDefs) {
-  scoped_ptr<DexFile> raw(OpenDexFileBase64(kNestedDex));
+  scoped_ptr<const DexFile> raw(OpenDexFileBase64(kNestedDex, "kNestedDex"));
   ASSERT_TRUE(raw != NULL);
   EXPECT_EQ(2U, raw->NumClassDefs());
 
@@ -55,7 +55,7 @@
 }
 
 TEST(DexFileTest, CreateMethodDescriptor) {
-  scoped_ptr<DexFile> raw(OpenDexFileBase64(kCreateMethodDescriptorDex));
+  scoped_ptr<const DexFile> raw(OpenDexFileBase64(kCreateMethodDescriptorDex, "kCreateMethodDescriptorDex"));
   ASSERT_TRUE(raw != NULL);
   EXPECT_EQ(1U, raw->NumClassDefs());
 
diff --git a/src/exception_test.cc b/src/exception_test.cc
index e2f97c0..a9673ef 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -64,7 +64,7 @@
 };
 
 TEST_F(ExceptionTest, MyClass_F_G) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassExceptionHandleDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassExceptionHandleDex, "kMyClassExceptionHandleDex"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* klass = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader);
   ASSERT_TRUE(klass != NULL);
diff --git a/src/heap.cc b/src/heap.cc
index 643d056..7369804 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -15,6 +15,8 @@
 
 std::vector<Space*> Heap::spaces_;
 
+Space* Heap::boot_space_ = NULL;
+
 Space* Heap::alloc_space_ = NULL;
 
 size_t Heap::maximum_size_ = 0;
@@ -79,6 +81,7 @@
 
   // Make objects in boot_space live (after live_bitmap_ is set)
   if (boot_image_file_name != NULL) {
+    boot_space_ = boot_space;
     RecordImageAllocations(boot_space);
   }
 
diff --git a/src/heap.h b/src/heap.h
index 0cf0b57..4d45366 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -47,6 +47,10 @@
     return spaces_;
   }
 
+  static Space* GetBootSpace() {
+    return boot_space_;
+  }
+
   static HeapBitmap* GetLiveBits() {
     return live_bitmap_;
   }
@@ -72,6 +76,9 @@
 
   static std::vector<Space*> spaces_;
 
+  // Space loaded from an image
+  static Space* boot_space_;
+
   // default Space for allocations
   static Space* alloc_space_;
 
diff --git a/src/image.h b/src/image.h
index c4123e8..c567880 100644
--- a/src/image.h
+++ b/src/image.h
@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include "globals.h"
+#include "object.h"
 
 namespace art {
 
@@ -14,7 +15,8 @@
  public:
   ImageHeader() {}
 
-  ImageHeader(uint32_t base_addr) : base_addr_(base_addr) {
+  ImageHeader(uint32_t base_addr, uint32_t intern_addr)
+      : base_addr_(base_addr), intern_addr_(intern_addr) {
     memcpy(magic_, kImageMagic, sizeof(kImageMagic));
     memcpy(version_, kImageVersion, sizeof(kImageVersion));
   }
@@ -33,13 +35,22 @@
     return reinterpret_cast<byte*>(base_addr_);
   }
 
+  ObjectArray<Object>* GetInternedArray() const {
+    return reinterpret_cast<ObjectArray<Object>*>(intern_addr_);
+  }
+
  private:
   static const byte kImageMagic[4];
   static const byte kImageVersion[4];
 
   byte magic_[4];
   byte version_[4];
+
+  // required base address for mapping the image.
   uint32_t base_addr_;
+
+  // absolute address of an Object[] of Strings to InternTable::Register
+  uint32_t intern_addr_;
 };
 
 }  // namespace art
diff --git a/src/image_test.cc b/src/image_test.cc
index c68b600..8c00e89 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -31,7 +31,16 @@
 }
 
 TEST_F(ImageTest, WriteRead) {
+
+  // TODO: move the touching of classes and GC to the ImageWriter proper
+  for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) {
+    const DexFile::ClassDef class_def = java_lang_dex_file_->GetClassDef(i);
+    const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def);
+    Class* klass = class_linker_->FindSystemClass(descriptor);
+    ASSERT_TRUE(klass != NULL) << descriptor;
+  }
   // TODO: Heap::CollectGarbage before writing
+
   const std::vector<Space*>& spaces = Heap::GetSpaces();
   // can't currently deal with writing a space that might have pointers between spaces
   ASSERT_EQ(1U, spaces.size());
@@ -52,7 +61,7 @@
     ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
   }
 
-  // tear down old runtime and make a new one
+  // tear down old runtime before making a new one, clearing out misc state
   delete runtime_.release();
 
   // don't reuse java_lang_dex_file_ so we make sure we don't get
@@ -74,27 +83,27 @@
   runtime_.reset(Runtime::Create(options, false));
   ASSERT_TRUE(runtime_ != NULL);
   class_linker_ = runtime_->GetClassLinker();
-  
-  if (true) {
-    const char* maps_file = "/proc/self/maps";
-    std::string contents = ReadFileToString(maps_file);
-    LG << maps_file << ":\n" << contents;
-  }
 
   ASSERT_EQ(2U, Heap::GetSpaces().size());
   Space* boot_space = Heap::GetSpaces()[0];
   ASSERT_TRUE(boot_space != NULL);
 
-  // TODO: need to rebuild ClassLinker::classes_ and ::intern_table_
-  // byte* boot_base = boot_space->GetBase();
-  // byte* boot_limit = boot_space->GetLimit();
+  // enable to display maps to debug boot_base and boot_limit checking problems below
+  if (false) {
+    const char* maps_file = "/proc/self/maps";
+    std::string contents = ReadFileToString(maps_file);
+    LG << maps_file << ":\n" << contents;
+  }
+
+  byte* boot_base = boot_space->GetBase();
+  byte* boot_limit = boot_space->GetLimit();
   for (size_t i = 0; i < dex->NumClassDefs(); i++) {
     const DexFile::ClassDef class_def = dex->GetClassDef(i);
     const char* descriptor = dex->GetClassDescriptor(class_def);
     Class* klass = class_linker_->FindSystemClass(descriptor);
-    EXPECT_TRUE(klass != NULL);
-    // EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass));
-    // EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit);
+    EXPECT_TRUE(klass != NULL) << descriptor;
+    EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass)) << descriptor;
+    EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit) << descriptor;
   }
 }
 
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 4335a90..1c7acff 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -6,10 +6,12 @@
 #include <vector>
 
 #include "dex_cache.h"
+#include "class_linker.h"
 #include "file.h"
 #include "globals.h"
 #include "heap.h"
 #include "image.h"
+#include "intern_table.h"
 #include "logging.h"
 #include "object.h"
 #include "space.h"
@@ -43,6 +45,40 @@
   return true;
 }
 
+namespace {
+
+struct InternTableVisitorState {
+  int index;
+  ObjectArray<Object>* interned_array;
+};
+
+void InternTableVisitor(Object* obj, void* arg) {
+  InternTableVisitorState* state = reinterpret_cast<InternTableVisitorState*>(arg);
+  state->interned_array->Set(state->index++, obj);
+}
+
+ObjectArray<Object>* CreateInternedArray() {
+  // build a Object[] of the interned strings for reinit
+  // TODO: avoid creating this future garbage
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const InternTable& intern_table = class_linker->GetInternTable();
+  size_t size = intern_table.Size();
+  CHECK_NE(0U, size);
+
+  Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
+  ObjectArray<Object>* interned_array = ObjectArray<Object>::Alloc(object_array_class, size);
+
+  InternTableVisitorState state;
+  state.index = 0;
+  state.interned_array = interned_array;
+
+  intern_table.VisitRoots(InternTableVisitor, &state);
+
+  return interned_array;
+}
+
+} // namespace
+
 void ImageWriter::CalculateNewObjectOffsetsCallback(Object *obj, void *arg) {
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
@@ -53,14 +89,24 @@
 }
 
 void ImageWriter::CalculateNewObjectOffsets() {
+  ObjectArray<Object>* interned_array = CreateInternedArray();
+
   HeapBitmap* heap_bitmap = Heap::GetLiveBits();
   DCHECK(heap_bitmap != NULL);
   DCHECK_EQ(0U, image_top_);
-  ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_));
-  memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
-  image_top_ += RoundUp(sizeof(image_header), 8); // 64-bit-alignment
+
+  // leave space for the header, but do not write it yet, we need to
+  // know where interned_array is going to end up
+  image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
+
   heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);
   DCHECK_LT(image_top_, image_->GetLength());
+
+  // return to write header at start of image with future location of interned_array
+  ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_),
+                           reinterpret_cast<uint32_t>(GetImageAddress(interned_array)));
+  memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
+
   // Note that top_ is left at end of used space
 }
 
@@ -92,6 +138,10 @@
   // TODO: special case init of pointers to malloc data (or removal of these pointers)
   if (orig->IsClass()) {
     FixupClass(orig->AsClass(), down_cast<Class*>(copy));
+  } else if (orig->IsMethod()) {
+    FixupMethod(orig->AsMethod(), down_cast<Method*>(copy));
+  } else if (orig->IsField()) {
+    FixupField(orig->AsField(), down_cast<Field*>(copy));
   } else if (orig->IsObjectArray()) {
     FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
   } else {
@@ -117,6 +167,20 @@
   copy->static_references_ = down_cast<ObjectArray<Object>*>(GetImageAddress(orig->static_references_));
 }
 
+// TODO: remove this slow path
+void ImageWriter::FixupMethod(Method* orig, Method* copy) {
+  FixupInstanceFields(orig, copy);
+  // TODO: remove need for this by adding "signature" to java.lang.reflect.Method
+  copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_));
+  DCHECK(copy->signature_ != NULL);
+  // TODO: convert shorty_ to heap allocated storage
+}
+
+void ImageWriter::FixupField(Field* orig, Field* copy) {
+  FixupInstanceFields(orig, copy);
+  // TODO: convert descriptor_ to heap allocated storage
+}
+
 void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
   for (int32_t i = 0; i < orig->GetLength(); ++i) {
     const Object* element = orig->Get(i);
diff --git a/src/image_writer.h b/src/image_writer.h
index 8ae8f7d..8e9ac10 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -51,6 +51,8 @@
   void CopyAndFixupObjects();
   static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
   void FixupClass(Class* orig, Class* copy);
+  void FixupMethod(Method* orig, Method* copy);
+  void FixupField(Field* orig, Field* copy);
   void FixupObject(Object* orig, Object* copy);
   void FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy);
   void FixupInstanceFields(Object* orig, Object* copy);
diff --git a/src/intern_table.cc b/src/intern_table.cc
index 3ef5917..e070573 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -14,11 +14,15 @@
   delete intern_table_lock_;
 }
 
-void InternTable::VisitRoots(Heap::RootVistor* root_visitor, void* arg) {
+size_t InternTable::Size() const {
+  return intern_table_.size();
+}
+
+void InternTable::VisitRoots(Heap::RootVistor* root_visitor, void* arg) const {
   MutexLock mu(intern_table_lock_);
   typedef Table::const_iterator It; // TODO: C++0x auto
   for (It it = intern_table_.begin(), end = intern_table_.end(); it != end; ++it) {
-      root_visitor(it->second, arg);
+    root_visitor(it->second, arg);
   }
 }
 
@@ -36,9 +40,13 @@
       }
     }
     String* new_string = String::AllocFromUtf16(utf16_length, utf16_data_out.get(), hash_code);
-    intern_table_.insert(std::make_pair(hash_code, new_string));
+    Register(new_string);
     return new_string;
   }
 }
 
+void InternTable::Register(String* string) {
+  intern_table_.insert(std::make_pair(string->GetHashCode(), string));
+}
+
 }  // namespace art
diff --git a/src/intern_table.h b/src/intern_table.h
index 0a1554d..46e0e05 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -14,8 +14,16 @@
  public:
   InternTable();
   ~InternTable();
+
+  // intern a potentially new string
   String* Intern(int32_t utf16_length, const char* utf8_data);
-  void VisitRoots(Heap::RootVistor* root_visitor, void* arg);
+
+  // register a String trusting that it is safe to intern.
+  // used when reinitializing InternTable from an image.
+  void Register(String* string);
+
+  size_t Size() const;
+  void VisitRoots(Heap::RootVistor* root_visitor, void* arg) const;
 
  private:
   typedef std::tr1::unordered_multimap<int32_t, String*> Table;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 8a5155f..cb48e76 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -21,7 +21,7 @@
  protected:
   virtual void SetUp() {
     CommonTest::SetUp();
-    dex_.reset(OpenDexFileBase64(kMyClassNativesDex));
+    dex_.reset(OpenDexFileBase64(kMyClassNativesDex, "kMyClassNativesDex"));
     class_loader_ = AllocPathClassLoader(dex_.get());
   }
 
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 6c5d6f2..b9e8f19 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -456,7 +456,7 @@
 
 #if defined(__arm__)
 TEST_F(JniInternalTest, StaticMainMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMainDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kMainDex, "kMainDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -484,7 +484,7 @@
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -511,7 +511,7 @@
 }
 
 TEST_F(JniInternalTest, StaticIdentityByteMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -559,7 +559,7 @@
 }
 
 TEST_F(JniInternalTest, StaticIdentityIntMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -607,7 +607,7 @@
 }
 
 TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -656,7 +656,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -716,7 +716,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -783,7 +783,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -856,7 +856,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -936,7 +936,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -997,7 +997,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -1051,7 +1051,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
@@ -1110,7 +1110,7 @@
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
 
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   ASSERT_TRUE(class_loader != NULL);
diff --git a/src/object.cc b/src/object.cc
index bfa200a..3200e4d 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -526,9 +526,15 @@
 // TODO: get global references for these
 Class* String::java_lang_String_ = NULL;
 
-void String::InitClass(Class* java_lang_String) {
+void String::SetClass(Class* java_lang_String) {
+  CHECK(java_lang_String_ == NULL);
+  CHECK(java_lang_String != NULL);
   java_lang_String_ = java_lang_String;
 }
+void String::ResetClass() {
+  CHECK(java_lang_String_ != NULL);
+  java_lang_String_ = NULL;
+}
 
 static const char* kClassStatusNames[] = {
   "Error",
diff --git a/src/object.h b/src/object.h
index ca09d07..e246dea 100644
--- a/src/object.h
+++ b/src/object.h
@@ -239,6 +239,27 @@
     return down_cast<const Array*>(this);
   }
 
+  bool IsString() const;
+
+  String* AsString() {
+    DCHECK(IsString());
+    return down_cast<String*>(this);
+  }
+
+  bool IsMethod() const;
+
+  Method* AsMethod() {
+    DCHECK(IsMethod());
+    return down_cast<Method*>(this);
+  }
+
+  bool IsField() const;
+
+  Field* AsField() {
+    DCHECK(IsField());
+    return down_cast<Field*>(this);
+  }
+
  public:
   Class* klass_;
 
@@ -285,10 +306,12 @@
 class Field : public AccessibleObject {
  public:
   Class* GetDeclaringClass() const {
+    DCHECK(declaring_class_ != NULL);
     return declaring_class_;
   }
 
   const String* GetName() const {
+    DCHECK(name_ != NULL);
     return name_;
   }
 
@@ -364,14 +387,17 @@
 
   // Returns the method name, e.g. "<init>" or "eatLunch"
   const String* GetName() const {
+    DCHECK(name_ != NULL);
     return name_;
   }
 
   const String* GetSignature() const {
+    DCHECK(signature_ != NULL);
     return signature_;
   }
 
   Class* GetDeclaringClass() const {
+    DCHECK(declaring_class_ != NULL);
     return declaring_class_;
   }
 
@@ -1177,7 +1203,8 @@
 }
 
 inline bool Object::IsClass() const {
-  return klass_ == klass_->klass_;
+  Class* java_lang_Class = klass_->klass_;
+  return klass_ == java_lang_Class;
 }
 
 inline bool Object::IsObjectArray() const {
@@ -1188,6 +1215,18 @@
   return klass_->IsArray();
 }
 
+inline bool Object::IsField() const {
+  Class* java_lang_Class = klass_->klass_;
+  Class* java_lang_reflect_Field = java_lang_Class->GetInstanceField(0)->klass_;
+  return klass_ == java_lang_reflect_Field;
+}
+
+inline bool Object::IsMethod() const {
+  Class* java_lang_Class = klass_->klass_;
+  Class* java_lang_reflect_Method = java_lang_Class->GetDirectMethod(0)->klass_;
+  return klass_ == java_lang_reflect_Method;
+}
+
 inline size_t Object::SizeOf() const {
   if (IsArray()) {
     return AsArray()->SizeOf();
@@ -1236,10 +1275,16 @@
   }
 
   static void SetArrayClass(Class* array_class) {
+    CHECK(array_class_ == NULL);
     CHECK(array_class != NULL);
     array_class_ = array_class;
   }
 
+  static void ResetArrayClass() {
+    CHECK(array_class_ != NULL);
+    array_class_ = NULL;
+  }
+
  private:
   // Location of first element.
   T elements_[0];
@@ -1281,7 +1326,7 @@
   }
 
   static String* AllocFromUtf16(int32_t utf16_length,
-                                uint16_t* utf16_data_in,
+                                const uint16_t* utf16_data_in,
                                 int32_t hash_code) {
     String* string = Alloc(GetJavaLangString(),
                            utf16_length);
@@ -1307,7 +1352,8 @@
     return string;
   }
 
-  static void InitClass(Class* java_lang_String);
+  static void SetClass(Class* java_lang_String);
+  static void ResetClass();
 
   static String* Alloc(Class* java_lang_String,
                        int32_t utf16_length) {
@@ -1489,6 +1535,11 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(String);
 };
 
+inline bool Object::IsString() const {
+  // TODO use "klass_ == String::GetJavaLangString()" instead?
+  return klass_ == klass_->descriptor_->klass_;
+}
+
 inline size_t Class::GetTypeSize(String* descriptor) {
   switch (descriptor->CharAt(0)) {
   case 'B': return 1;  // byte
diff --git a/src/object_test.cc b/src/object_test.cc
index c517459..aa3cf86 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -208,9 +208,9 @@
 TEST_F(ObjectTest, DescriptorCompare) {
   ClassLinker* linker = class_linker_;
 
-  scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
+  scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex, "kProtoCompareDex"));
   PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
-  scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
+  scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex, "kProtoCompare2Dex"));
   PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
 
   Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
@@ -257,7 +257,7 @@
 }
 
 TEST_F(ObjectTest, InstanceOf) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* X = class_linker_->FindClass("LX;", class_loader);
   Class* Y = class_linker_->FindClass("LY;", class_loader);
@@ -284,7 +284,7 @@
 }
 
 TEST_F(ObjectTest, IsAssignableFrom) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* X = class_linker_->FindClass("LX;", class_loader);
   Class* Y = class_linker_->FindClass("LY;", class_loader);
@@ -296,7 +296,7 @@
 }
 
 TEST_F(ObjectTest, IsAssignableFromArray) {
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+  scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* X = class_linker_->FindClass("LX;", class_loader);
   Class* Y = class_linker_->FindClass("LY;", class_loader);
diff --git a/src/runtime.cc b/src/runtime.cc
index 864b257..476297b 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -352,7 +352,7 @@
   Thread* current_thread = Thread::Attach(this);
   thread_list_->Register(current_thread);
 
-  class_linker_ = ClassLinker::Create(options->boot_class_path_);
+  class_linker_ = ClassLinker::Create(options->boot_class_path_, Heap::GetBootSpace());
 
   return true;
 }
diff --git a/src/space.cc b/src/space.cc
index 8048f29..c636e38 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -100,6 +100,9 @@
     return false;
   }
   CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
+  image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
+  DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
+
   Init(map.release());
   return true;
 }
diff --git a/src/space.h b/src/space.h
index 57f676d..24bcefa 100644
--- a/src/space.h
+++ b/src/space.h
@@ -4,6 +4,7 @@
 #define ART_SRC_SPACE_H_
 
 #include "globals.h"
+#include "image.h"
 #include "macros.h"
 #include "mem_map.h"
 #include "scoped_ptr.h"
@@ -47,6 +48,11 @@
     return limit_ - base_;
   }
 
+  const ImageHeader& GetImageHeader() const {
+    CHECK(image_header_ != NULL);
+    return *image_header_;
+  }
+
   size_t AllocationSize(const Object* obj);
 
   bool IsCondemned() const {
@@ -60,7 +66,7 @@
   // create a Space from an existing memory mapping, taking ownership of the address space.
   static Space* Create(MemMap* mem_map);
 
-  Space() : mspace_(NULL), maximum_size_(0), base_(0), limit_(0) {}
+  Space() : mspace_(NULL), maximum_size_(0), image_header_(NULL), base_(0), limit_(0) {}
 
   // Initializes the space and underlying storage.
   bool Init(size_t initial_size, size_t maximum_size, byte* requested_base);
@@ -75,10 +81,13 @@
 
   static void DontNeed(void* start, void* end, void* num_bytes);
 
-  // TODO: have a Space subclass for methods that depend on mspace_ and maximum_size_
+  // TODO: have a Space subclass for non-image Spaces with mspace_ and maximum_size_
   void* mspace_;
   size_t maximum_size_;
 
+  // TODO: have a Space subclass for image Spaces with image_header_
+  ImageHeader* image_header_;
+
   scoped_ptr<MemMap> mem_map_;
 
   byte* base_;
diff --git a/src/stringpiece.h b/src/stringpiece.h
index 249b041..1338ed9 100644
--- a/src/stringpiece.h
+++ b/src/stringpiece.h
@@ -200,6 +200,21 @@
 
 extern std::ostream& operator<<(std::ostream& o, const art::StringPiece& piece);
 
+// BEGIN android-added
+struct StringPieceHash {
+  size_t operator()(const art::StringPiece& string_piece) const {
+    size_t string_size = string_piece.size();
+    const char* string_data = string_piece.data();
+    // this is the java.lang.String hashcode for convenience, not interoperability
+    size_t hash = 0;
+    while (string_size--) {
+      hash = hash * 31 + *string_data++;
+    }
+    return hash;
+  }
+};
+// END android-added
+
 }  // namespace art
 
 #endif  // ART_SRC_STRINGPIECE_H_
diff --git a/src/unordered_map.h b/src/unordered_map.h
index caa859d..4f55d77 100644
--- a/src/unordered_map.h
+++ b/src/unordered_map.h
@@ -11,34 +11,4 @@
 #include <tr1/unordered_map>
 #endif
 
-//TODO: move out to stringpiece.h?
-namespace std {
-#ifndef __ANDROID__
-namespace tr1 {
-#endif
-template<>
-struct hash<art::StringPiece> {
- public:
-  size_t operator()(const art::StringPiece& string_piece) const {
-    size_t string_size = string_piece.size();
-    const char* string_data = string_piece.data();
-    // this is the java.lang.String hashcode for convenience, not interoperability
-    size_t hash = 0;
-    while (string_size--) {
-      hash = hash * 31 + *string_data++;
-    }
-    return hash;
-  }
-};
-#ifndef __ANDROID__
-}  // namespace tr1
-#endif
-}  // namespace std
-
-#ifdef __ANDROID__
-typedef std::hash<art::StringPiece> StringPieceHash;
-#else
-typedef std::tr1::hash<art::StringPiece> StringPieceHash;
-#endif
-
 #endif  // ART_SRC_CLASS_UNORDERED_MAP_H_
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 8001fa3..26cb438 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -119,7 +119,7 @@
   uint16_t num_entries_;
   off_t dir_offset_;
   scoped_ptr<MemMap> dir_map_;
-  typedef std::tr1::unordered_map<StringPiece, const byte*> DirEntries;
+  typedef std::tr1::unordered_map<StringPiece, const byte*, StringPieceHash> DirEntries;
   DirEntries dir_entries_;
 
   friend class ZipEntry;