Convert Class::descriptor_ from StringPiece to String (as part of image loading)

Change-Id: Iab5ffa353661a7c06ee79af1f40d399a53777174
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 448a542..55aaff4 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -32,7 +32,7 @@
   // 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;";
+  // 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 +40,7 @@
   // 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;";
+  // 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,38 +49,47 @@
   // 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;";
+  // 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;";
+  // 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);
   Class* char_array_class = AllocClass(java_lang_Class);
   CHECK(char_array_class != NULL);
-  char_array_class->descriptor_ = "[C";
+  // char_array_class->descriptor_ = "[C";  // XXX can these be created later?
   CharArray::SetArrayClass(char_array_class);
+  // Now String::Alloc* can be used
+
+  // backfill Class descriptors missing until this point
+  java_lang_Class->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Class;");
+  java_lang_Object->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Object;");
+  object_array_class->descriptor_ = String::AllocFromModifiedUtf8("[Ljava/lang/Object;");
+  java_lang_String->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/String;");
+  char_array_class->descriptor_ = String::AllocFromModifiedUtf8("[C");
 
   // int[] and long[] are used for static field storage
   Class* int_array_class = AllocClass(java_lang_Class);
   CHECK(int_array_class != NULL);
-  int_array_class->descriptor_ = "[I";
+  int_array_class->descriptor_ = String::AllocFromModifiedUtf8("[I");
   IntArray::SetArrayClass(int_array_class);
   Class* long_array_class = AllocClass(java_lang_Class);
   CHECK(long_array_class != NULL);
-  long_array_class->descriptor_ = "[J";
+  long_array_class->descriptor_ = String::AllocFromModifiedUtf8("[J");
   LongArray::SetArrayClass(long_array_class);
 
   // Field and Method are necessary so that FindClass can link members
   Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
   CHECK(java_lang_reflect_Field != NULL);
-  java_lang_reflect_Field->descriptor_ = "Ljava/lang/reflect/Field;";
+  java_lang_reflect_Field->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;");
   CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
   java_lang_reflect_Field->object_size_ = sizeof(Field);
   Class* java_lang_reflect_Method = AllocClass(java_lang_Class);
-  java_lang_reflect_Method->descriptor_ = "Ljava/lang/reflect/Method;";
+  java_lang_reflect_Method->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;");
   CHECK(java_lang_reflect_Method != NULL);
   CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
   java_lang_reflect_Method->object_size_ = sizeof(Method);
@@ -98,9 +107,6 @@
   class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
-  String::InitClasses(java_lang_String);
-  // Now AllocString* can be used
-
   // setup boot_class_path_ now that we can use AllocObjectArray to
   // create DexCache instances
   for (size_t i = 0; i != boot_class_path.size(); ++i) {
@@ -111,24 +117,24 @@
   // run Class, Field, and Method through FindSystemClass.
   // this initializes their dex_cache_ fields and register them in classes_.
   // we also override their object_size_ values to accommodate the extra C++ fields.
-  Class* Class_class = FindSystemClass(java_lang_Class->GetDescriptor());
+  Class* Class_class = FindSystemClass("Ljava/lang/Class;");
   CHECK_EQ(java_lang_Class, Class_class);
   CHECK_LT(java_lang_Class->object_size_, sizeof(Class));
   java_lang_Class->object_size_ = sizeof(Class);
-  Class* Field_class = FindSystemClass(java_lang_reflect_Field->GetDescriptor());
+  Class* Field_class = FindSystemClass("Ljava/lang/reflect/Field;");
   CHECK_EQ(java_lang_reflect_Field, Field_class);
   CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
   java_lang_reflect_Field->object_size_ = sizeof(Field);
-  Class* Method_class = FindSystemClass(java_lang_reflect_Method->GetDescriptor());
+  Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;");
   CHECK_EQ(java_lang_reflect_Method, Method_class);
   CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
   java_lang_reflect_Method->object_size_ = sizeof(Method);
 
   // Object and String just need more minimal setup, since they do not have extra C++ fields.
-  Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
+  Class* Object_class = FindSystemClass("Ljava/lang/Object;");
   CHECK_EQ(java_lang_Object, Object_class);
   CHECK_EQ(java_lang_Object->object_size_, sizeof(Object));
-  Class* String_class = FindSystemClass(java_lang_String->GetDescriptor());
+  Class* String_class = FindSystemClass("Ljava/lang/String;");
   CHECK_EQ(java_lang_String, String_class);
   CHECK_EQ(java_lang_String->object_size_, sizeof(String));
 
@@ -323,7 +329,7 @@
       ObjectLock lock(klass);
       klass->clinit_thread_id_ = self->GetId();
       // Add the newly loaded class to the loaded classes table.
-      bool success = InsertClass(klass);  // TODO: just return collision
+      bool success = InsertClass(descriptor, klass);  // TODO: just return collision
       if (!success) {
         // We may fail to insert if we raced with another thread.
         klass->clinit_thread_id_ = 0;
@@ -387,8 +393,7 @@
   CHECK(descriptor != NULL);
 
   klass->klass_ = GetClassRoot(kJavaLangClass);
-  klass->descriptor_.set(descriptor);
-  klass->descriptor_alloc_ = NULL;
+  klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
   klass->access_flags_ = dex_class_def.access_flags_;
   klass->class_loader_ = class_loader;
   klass->primitive_type_ = Class::kPrimNot;
@@ -508,7 +513,7 @@
     int32_t utf16_length;
     scoped_array<char> utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_,
                                                           &utf16_length));
-    dst->descriptor_ = String::AllocFromModifiedUtf8(utf16_length, utf8.get());
+    dst->signature_ = String::AllocFromModifiedUtf8(utf16_length, utf8.get());
   }
   dst->proto_idx_ = method_id.proto_idx_;
   dst->code_off_ = src.code_off_;
@@ -570,15 +575,14 @@
   return NULL;
 }
 
-Class* ClassLinker::CreatePrimitiveClass(const StringPiece& descriptor) {
+Class* ClassLinker::CreatePrimitiveClass(const char* descriptor) {
   Class* klass = AllocClass();
   CHECK(klass != NULL);
   klass->super_class_ = NULL;
   klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
-  klass->descriptor_ = descriptor;
-  klass->descriptor_alloc_ = NULL;
+  klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
   klass->status_ = Class::kStatusInitialized;
-  bool success = InsertClass(klass);
+  bool success = InsertClass(descriptor, klass);
   CHECK(success) << "CreatePrimitiveClass(" << descriptor << ") failed";
   return klass;
 }
@@ -683,10 +687,7 @@
       return NULL;
     }
   }
-  new_class->descriptor_alloc_ = new std::string(descriptor.data(),
-                                                 descriptor.size());
-  new_class->descriptor_.set(new_class->descriptor_alloc_->data(),
-                             new_class->descriptor_alloc_->size());
+  new_class->descriptor_ = String::AllocFromModifiedUtf8(descriptor.ToString().c_str());
   Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->super_class_ = java_lang_Object;
   new_class->vtable_ = java_lang_Object->vtable_;
@@ -696,6 +697,7 @@
   new_class->array_rank_ = array_rank;
   new_class->status_ = Class::kStatusInitialized;
   // don't need to set new_class->object_size_
+  // because Object::SizeOf delegates to Array::SizeOf
 
 
   // All arrays have java/lang/Cloneable and java/io/Serializable as
@@ -726,7 +728,7 @@
   new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
                                ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
 
-  if (InsertClass(new_class)) {
+  if (InsertClass(descriptor, new_class)) {
     return new_class;
   }
   // Another thread must have loaded the class after we
@@ -770,19 +772,20 @@
   return NULL;  // Not reachable.
 }
 
-bool ClassLinker::InsertClass(Class* klass) {
+bool ClassLinker::InsertClass(const StringPiece& descriptor, Class* klass) {
+  size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(classes_lock_);
-  const StringPiece& key = klass->GetDescriptor();
-  Table::iterator it = classes_.insert(std::make_pair(key, klass));
+  Table::iterator it = classes_.insert(std::make_pair(hash, klass));
   return ((*it).second == klass);
 }
 
 Class* ClassLinker::LookupClass(const StringPiece& descriptor, ClassLoader* class_loader) {
+  size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(classes_lock_);
   typedef Table::const_iterator It; // TODO: C++0x auto
-  for (It it = classes_.find(descriptor), end = classes_.end(); it != end; ++it) {
+  for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
     Class* klass = it->second;
-    if (klass->descriptor_ == descriptor && klass->class_loader_ == class_loader) {
+    if (klass->descriptor_->Equals(descriptor) && klass->class_loader_ == class_loader) {
       return klass;
     }
   }
@@ -974,7 +977,6 @@
   CHECK(descriptor != NULL);
   CHECK(klass1 != NULL);
   CHECK(klass2 != NULL);
-#if 0
   Class* found1 = FindClass(descriptor, klass1->GetClassLoader());
   // TODO: found1 == NULL
   Class* found2 = FindClass(descriptor, klass2->GetClassLoader());
@@ -988,7 +990,6 @@
       return false;
     }
   }
-#endif
   return true;
 }
 
@@ -1033,7 +1034,7 @@
   if (dex_cache == NULL) {
     return;
   }
-  const StringPiece& descriptor = klass->GetDescriptor();
+  const std::string descriptor(klass->GetDescriptor()->ToModifiedUtf8());
   const DexFile& dex_file = FindDexFile(dex_cache);
   const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
   CHECK(dex_class_def != NULL);
@@ -1140,7 +1141,7 @@
 bool ClassLinker::LinkSuperClass(Class* klass) {
   CHECK(!klass->IsPrimitive());
   const Class* super = klass->GetSuperClass();
-  if (klass->GetDescriptor() == "Ljava/lang/Object;") {
+  if (klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
     if (super != NULL) {
       LG << "Superclass must not be defined";  // TODO: ClassFormatError
       return false;
@@ -1154,15 +1155,15 @@
   }
   // Verify
   if (super->IsFinal()) {
-    LG << "Superclass " << super->descriptor_ << " is declared final";  // TODO: IncompatibleClassChangeError
+    LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is declared final";  // TODO: IncompatibleClassChangeError
     return false;
   }
   if (super->IsInterface()) {
-    LG << "Superclass " << super->descriptor_ << " is an interface";  // TODO: IncompatibleClassChangeError
+    LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is an interface";  // TODO: IncompatibleClassChangeError
     return false;
   }
   if (!klass->CanAccess(super)) {
-    LG << "Superclass " << super->descriptor_ << " is  inaccessible";  // TODO: IllegalAccessError
+    LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is  inaccessible";  // TODO: IllegalAccessError
     return false;
   }
   return true;
@@ -1234,9 +1235,8 @@
       klass->vtable_ = klass->vtable_->CopyOf(actual_count);
     }
   } else {
-    CHECK(klass->GetDescriptor() == "Ljava/lang/Object;");
+    CHECK(klass->GetDescriptor()->Equals("Ljava/lang/Object;"));
     uint32_t num_virtual_methods = klass->NumVirtualMethods();
-    CHECK(klass->GetDescriptor() == "Ljava/lang/Object;");
     if (!IsUint(16, num_virtual_methods)) {
       LG << "Too many methods";  // TODO: VirtualMachineError
       return false;
diff --git a/src/class_linker.h b/src/class_linker.h
index e83c850..bc7a780 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -72,7 +72,7 @@
   }
   PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
 
-  Class* CreatePrimitiveClass(const StringPiece& descriptor);
+  Class* CreatePrimitiveClass(const char* descriptor);
 
   Class* CreateArrayClass(const StringPiece& descriptor,
                           ClassLoader* class_loader);
@@ -114,7 +114,7 @@
 
   // Inserts a class into the class table.  Returns true if the class
   // was inserted.
-  bool InsertClass(Class* klass);
+  bool InsertClass(const StringPiece& descriptor, Class* klass);
 
   bool InitializeSuperClass(Class* klass);
 
@@ -156,10 +156,10 @@
 
   std::vector<DexCache*> dex_caches_;
 
-  // multimap from String::descriptor_ to Class* instances. Results
-  // should be compared for a matching Class::descriptor_ and
-  // Class::class_loader_.
-  typedef std::tr1::unordered_multimap<StringPiece, Class*> Table;
+  // multimap from a StringPiece hash code of a class descriptor to
+  // Class* instances. Results should be compared for a matching
+  // Class::descriptor_ and Class::class_loader_.
+  typedef std::tr1::unordered_multimap<size_t, Class*> Table;
   Table classes_;
   Mutex* classes_lock_;
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index fd7fecf..42a773c 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -21,7 +21,7 @@
     ASSERT_TRUE(primitive->GetClass() != NULL);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
     EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
-    ASSERT_EQ(descriptor, primitive->GetDescriptor());
+    ASSERT_TRUE(primitive->GetDescriptor()->Equals(descriptor));
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == NULL);
@@ -53,14 +53,14 @@
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
     EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
-    ASSERT_EQ(array_descriptor, array->GetDescriptor());
+    ASSERT_TRUE(array->GetDescriptor()->Equals(array_descriptor));
     EXPECT_TRUE(array->GetSuperClass() != NULL);
     EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
     EXPECT_EQ(class_loader, array->GetClassLoader());
     ASSERT_TRUE(array->GetComponentType() != NULL);
     ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
-    EXPECT_EQ(component_type, array->GetComponentType()->GetDescriptor());
+    EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
     EXPECT_TRUE(array->GetStatus() == Class::kStatusInitialized);
     EXPECT_FALSE(array->IsErroneous());
     EXPECT_TRUE(array->IsVerified());
@@ -83,8 +83,8 @@
     ASSERT_TRUE(descriptor != NULL);
     Class* klass = class_linker_->FindSystemClass(descriptor);
     ASSERT_TRUE(klass != NULL);
-    EXPECT_EQ(descriptor, klass->GetDescriptor());
-    if (klass->descriptor_ == "Ljava/lang/Object;") {
+    EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
+    if (klass->descriptor_->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
       EXPECT_FALSE(klass->HasSuperClass());
     } else {
       EXPECT_TRUE(klass->HasSuperClass());
@@ -240,7 +240,7 @@
   ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
   ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
-  ASSERT_TRUE(JavaLangObject->GetDescriptor() == "Ljava/lang/Object;");
+  ASSERT_TRUE(JavaLangObject->GetDescriptor()->Equals("Ljava/lang/Object;"));
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
   EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
@@ -270,7 +270,7 @@
   ASSERT_TRUE(MyClass->GetClass() != NULL);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
-  ASSERT_TRUE(MyClass->GetDescriptor() == "LMyClass;");
+  ASSERT_TRUE(MyClass->GetDescriptor()->Equals("LMyClass;"));
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader, MyClass->GetClassLoader());
@@ -399,7 +399,7 @@
   EXPECT_EQ(10U, statics->NumStaticFields());
 
   Field* s0 = statics->GetStaticField(0);
-  EXPECT_EQ("Ljava/lang/reflect/Field;", s0->GetClass()->descriptor_);
+  EXPECT_TRUE(s0->GetClass()->descriptor_->Equals("Ljava/lang/reflect/Field;"));
   EXPECT_EQ('Z', s0->GetType());
 //  EXPECT_EQ(true, s0->GetBoolean());  // TODO: uncomment this
   s0->SetBoolean(false);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 63f6e8c..f55b20e 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -16,14 +16,14 @@
   for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
     Method* method = klass->GetDirectMethod(i);
     if (!VerifyMethod(method)) {
-        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor();
+        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
       return false;
     }
   }
   for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
     Method* method = klass->GetVirtualMethod(i);
     if (!VerifyMethod(method)) {
-        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor();
+        LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
       return false;
     }
   }
diff --git a/src/heap.cc b/src/heap.cc
index de801ce..643d056 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4,6 +4,7 @@
 
 #include <vector>
 
+#include "image.h"
 #include "mark_sweep.h"
 #include "object.h"
 #include "space.h"
@@ -76,6 +77,11 @@
 
   // TODO: allocate the card table
 
+  // Make objects in boot_space live (after live_bitmap_ is set)
+  if (boot_image_file_name != NULL) {
+    RecordImageAllocations(boot_space);
+  }
+
   return true;
 }
 
@@ -92,7 +98,7 @@
 }
 
 Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
-  DCHECK((klass == NULL && num_bytes == sizeof(Class))
+  DCHECK(klass == NULL
          || klass->descriptor_ == NULL
          || (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
   Object* obj = Allocate(num_bytes);
@@ -124,6 +130,18 @@
   }
 }
 
+void Heap::RecordImageAllocations(Space* space) {
+  CHECK(space != NULL);
+  CHECK(live_bitmap_ != NULL);
+  byte* current = space->GetBase() + RoundUp(sizeof(ImageHeader), 8);
+  while (current < space->GetLimit()) {
+    DCHECK(IsAligned(current, 8));
+    const Object* obj = reinterpret_cast<const Object*>(current);
+    live_bitmap_->Set(obj);
+    current += RoundUp(obj->SizeOf(), 8);
+  }
+}
+
 Object* Heap::Allocate(size_t size) {
   DCHECK(alloc_space_ != NULL);
   Space* space = alloc_space_;
diff --git a/src/heap.h b/src/heap.h
index 99f6554..0cf0b57 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -62,6 +62,7 @@
 
   static void RecordAllocation(Space* space, const Object* object);
   static void RecordFree(Space* space, const Object* object);
+  static void RecordImageAllocations(Space* space);
 
   static void CollectGarbageInternal();
 
diff --git a/src/image_test.cc b/src/image_test.cc
index 6cfa62d..c68b600 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -13,11 +13,25 @@
 
 class ImageTest : public CommonTest {};
 
-TEST_F(ImageTest, WriteRead) {
-  scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
-  EXPECT_TRUE(libcore_dex_file.get() != NULL);
+std::string ReadFileToString(const char* file_name) {
+  scoped_ptr<File> file(OS::OpenFile(file_name, false));
+  CHECK(file != NULL);
 
-  // TODO: garbage collect before writing
+  std::string contents;
+  char buf[8 * KB];
+  while (true) {
+    int64_t n = file->Read(buf, sizeof(buf));
+    CHECK_NE(-1, n);
+    if (n == 0) {
+        break;
+    }
+    contents.append(buf, n);
+  }
+  return contents;
+}
+
+TEST_F(ImageTest, WriteRead) {
+  // 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());
@@ -25,7 +39,7 @@
 
   ImageWriter writer;
   ScratchFile tmp;
-  const int image_base = 0x5000000;
+  const int image_base = 0x50000000;
   bool success = writer.Write(space, tmp.GetFilename(), reinterpret_cast<byte*>(image_base));
   ASSERT_TRUE(success);
 
@@ -40,10 +54,16 @@
 
   // tear down old runtime and make a new one
   delete runtime_.release();
-  java_lang_dex_file_.reset(GetLibCoreDex());
+
+  // don't reuse java_lang_dex_file_ so we make sure we don't get
+  // lucky by pointers that happen to work referencing the earlier
+  // dex.
+  delete java_lang_dex_file_.release();
+  scoped_ptr<DexFile> dex(GetLibCoreDex());
+  ASSERT_TRUE(dex != NULL);
 
   std::vector<const DexFile*> boot_class_path;
-  boot_class_path.push_back(java_lang_dex_file_.get());
+  boot_class_path.push_back(dex.get());
 
   Runtime::Options options;
   options.push_back(std::make_pair("bootclasspath", &boot_class_path));
@@ -54,6 +74,28 @@
   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();
+  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);
+  }
 }
 
 }  // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
index b6625d0..4335a90 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -5,6 +5,7 @@
 #include <sys/mman.h>
 #include <vector>
 
+#include "dex_cache.h"
 #include "file.h"
 #include "globals.h"
 #include "heap.h"
@@ -88,14 +89,34 @@
   DCHECK(orig != NULL);
   DCHECK(copy != NULL);
   copy->klass_ = down_cast<Class*>(GetImageAddress(orig->klass_));
-  // TODO: specical case init of pointers to malloc data (or removal of these pointers)
-  if (orig->IsObjectArray()) {
+  // 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->IsObjectArray()) {
     FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
   } else {
     FixupInstanceFields(orig, copy);
   }
 }
 
+void ImageWriter::FixupClass(Class* orig, Class* copy) {
+  FixupInstanceFields(orig, copy);
+  copy->descriptor_ = down_cast<String*>(GetImageAddress(orig->descriptor_));
+  copy->dex_cache_ = down_cast<DexCache*>(GetImageAddress(orig->dex_cache_));
+  copy->verify_error_class_ = down_cast<Class*>(GetImageAddress(orig->verify_error_class_));
+  copy->component_type_ = down_cast<Class*>(GetImageAddress(orig->component_type_));
+  copy->super_class_ = down_cast<Class*>(GetImageAddress(orig->super_class_));
+  copy->class_loader_ = down_cast<ClassLoader*>(GetImageAddress(orig->class_loader_));
+  copy->interfaces_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->interfaces_));
+  copy->direct_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->direct_methods_));
+  copy->virtual_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->virtual_methods_));
+  copy->vtable_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->vtable_));
+  // TODO: convert iftable_ to heap allocated storage
+  copy->ifields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->ifields_));
+  copy->sfields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->sfields_));
+  copy->static_references_ = down_cast<ObjectArray<Object>*>(GetImageAddress(orig->static_references_));
+}
+
 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 003c4e9..8ae8f7d 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -50,6 +50,7 @@
 
   void CopyAndFixupObjects();
   static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
+  void FixupClass(Class* orig, Class* 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/jni_internal.cc b/src/jni_internal.cc
index 8e8ecd3..a55cdae 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -472,7 +472,7 @@
 
   if (method == NULL || method->IsStatic() != is_static) {
     Thread* self = Thread::Current();
-    std::string class_name(c->GetDescriptor().ToString());
+    std::string class_name(c->GetDescriptor()->ToModifiedUtf8());
     // TODO: try searching for the opposite kind of method from is_static
     // for better diagnostics?
     self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
@@ -505,7 +505,7 @@
 
   if (field == NULL) {
     Thread* self = Thread::Current();
-    std::string class_name(c->GetDescriptor().ToString());
+    std::string class_name(c->GetDescriptor()->ToModifiedUtf8());
     self->ThrowNewException("Ljava/lang/NoSuchFieldError;",
         "no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
         name, class_name.c_str());
@@ -1768,7 +1768,7 @@
     Class* element_class = Decode<Class*>(ts, element_jclass);
     std::string descriptor;
     descriptor += "[";
-    descriptor += element_class->GetDescriptor().ToString();
+    descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
 
     // Find the class.
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -2003,7 +2003,7 @@
       }
       if (method == NULL) {
         Thread* self = Thread::Current();
-        std::string class_name = klass->GetDescriptor().ToString();
+        std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
         // TODO: pretty print method names through a single routine
         self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
             "no method \"%s.%s%s\"",
@@ -2011,7 +2011,7 @@
         return JNI_ERR;
       } else if (!method->IsNative()) {
         Thread* self = Thread::Current();
-        std::string class_name = klass->GetDescriptor().ToString();
+        std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
         // TODO: pretty print method names through a single routine
         self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
             "method \"%s.%s%s\" is not native",
diff --git a/src/object.cc b/src/object.cc
index b9324a6..8765713 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -108,8 +108,11 @@
   return false;
 }
 
-bool Class::IsInSamePackage(const StringPiece& descriptor1,
-                            const StringPiece& descriptor2) {
+bool Class::IsInSamePackage(const String* descriptor_string_1,
+                            const String* descriptor_string_2) {
+  const std::string descriptor1(descriptor_string_1->ToModifiedUtf8());
+  const std::string descriptor2(descriptor_string_2->ToModifiedUtf8());
+
   size_t i = 0;
   while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) {
     ++i;
@@ -393,15 +396,15 @@
 
 bool Method::HasSameNameAndDescriptor(const Method* that) const {
   return (this->GetName()->Equals(that->GetName()) &&
-          this->GetDescriptor()->Equals(that->GetDescriptor()));
+          this->GetSignature()->Equals(that->GetSignature()));
 }
 
 Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
-                                        const StringPiece& descriptor) {
+                                        const StringPiece& signature) {
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     Method* method = GetDirectMethod(i);
     if (method->GetName()->Equals(name) &&
-        method->GetDescriptor()->Equals(descriptor)) {
+        method->GetSignature()->Equals(signature)) {
       return method;
     }
   }
@@ -409,9 +412,9 @@
 }
 
 Method* Class::FindDirectMethod(const StringPiece& name,
-                                const StringPiece& descriptor) {
+                                const StringPiece& signature) {
   for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
-    Method* method = klass->FindDeclaredDirectMethod(name, descriptor);
+    Method* method = klass->FindDeclaredDirectMethod(name, signature);
     if (method != NULL) {
       return method;
     }
@@ -420,11 +423,11 @@
 }
 
 Method* Class::FindDeclaredVirtualMethod(const StringPiece& name,
-                                         const StringPiece& descriptor) {
+                                         const StringPiece& signature) {
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     Method* method = GetVirtualMethod(i);
     if (method->GetName()->Equals(name) &&
-        method->GetDescriptor()->Equals(descriptor)) {
+        method->GetSignature()->Equals(signature)) {
       return method;
     }
   }
@@ -519,7 +522,7 @@
 // TODO: get global references for these
 Class* String::java_lang_String_ = NULL;
 
-void String::InitClasses(Class* java_lang_String) {
+void String::InitClass(Class* java_lang_String) {
   java_lang_String_ = java_lang_String;
 }
 
diff --git a/src/object.h b/src/object.h
index 2b5a054..8efa059 100644
--- a/src/object.h
+++ b/src/object.h
@@ -367,8 +367,8 @@
     return name_;
   }
 
-  const String* GetDescriptor() const {
-    return descriptor_;
+  const String* GetSignature() const {
+    return signature_;
   }
 
   Class* GetDeclaringClass() const {
@@ -573,7 +573,7 @@
   // the method descriptor would be
   //
   //   (IDLjava/lang/Thread;)Ljava/lang/Object;
-  String* descriptor_;
+  String* signature_;
 
   // Method prototype descriptor string (return and argument types).
   uint32_t proto_idx_;
@@ -599,16 +599,16 @@
 
 class Array : public Object {
  public:
-  static size_t Size(size_t component_count,
-                     size_t component_size) {
+  static size_t SizeOf(size_t component_count,
+                       size_t component_size) {
     return sizeof(Array) + component_count * component_size;
   }
 
   static Array* Alloc(Class* array_class,
                       size_t component_count,
                       size_t component_size) {
-    size_t size = Size(component_count, component_size);
-    Array* array = Heap::AllocObject(array_class, size)->AsArray();
+    size_t size = SizeOf(component_count, component_size);
+    Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
     if (array != NULL) {
       array->SetLength(component_count);
     }
@@ -816,30 +816,15 @@
     return component_type_;
   }
 
-  static size_t GetTypeSize(const StringPiece& descriptor) {
-    switch (descriptor[0]) {
-    case 'B': return 1;  // byte
-    case 'C': return 2;  // char
-    case 'D': return 8;  // double
-    case 'F': return 4;  // float
-    case 'I': return 4;  // int
-    case 'J': return 8;  // long
-    case 'S': return 2;  // short
-    case 'Z': return 1;  // boolean
-    case 'L': return sizeof(Object*);
-    case '[': return sizeof(Array*);
-    default:
-      LOG(ERROR) << "Unknown type " << descriptor;
-      return 0;
-    }
-  }
+  static size_t GetTypeSize(String* descriptor);
 
   size_t GetComponentSize() const {
     return GetTypeSize(component_type_->descriptor_);
   }
 
-  const StringPiece& GetDescriptor() const {
-    DCHECK_NE(0, descriptor_.size());
+  const String* GetDescriptor() const {
+    DCHECK(descriptor_ != NULL);
+    // DCHECK_NE(0, descriptor_->GetLength());  // TODO: keep?
     return descriptor_;
   }
 
@@ -880,13 +865,11 @@
   // Returns true if this class is in the same packages as that class.
   bool IsInSamePackage(const Class* that) const;
 
-  static bool IsInSamePackage(const StringPiece& descriptor1,
-                              const StringPiece& descriptor2);
+  static bool IsInSamePackage(const String* descriptor1,
+                              const String* descriptor2);
 
   // Returns true if this class represents an array class.
-  bool IsArray() const {
-    return GetDescriptor()[0] == '[';  // TODO: avoid parsing the descriptor
-  }
+  bool IsArray() const;
 
   // Returns true if the class is an interface.
   bool IsInterface() const {
@@ -1052,20 +1035,11 @@
   bool IsSubClass(const Class* klass) const;
 
  public:  // TODO: private
-  // leave space for instance data; we could access fields directly if
-  // we freeze the definition of java/lang/Class
-#define CLASS_FIELD_SLOTS 1
-  // Class.#0 name
-  uint32_t instance_data_[CLASS_FIELD_SLOTS];
-#undef CLASS_FIELD_SLOTS
+  // descriptor for the class such as "java.lang.Class" or "[C"
+  String* name_;  // TODO initialize
 
-  // UTF-8 descriptor for the class from constant pool
-  // ("Ljava/lang/Class;"), or on heap if generated ("[C")
-  StringPiece descriptor_;
-
-  // Proxy classes have their descriptor allocated on the native heap.
-  // When this field is non-NULL it must be explicitly freed.
-  std::string* descriptor_alloc_;
+  // descriptor for the class such as "Ljava/lang/Class;" or "[C"
+  String* descriptor_;
 
   // access flags; low 16 bits are defined by VM spec
   uint32_t access_flags_;  // TODO: make an instance field?
@@ -1218,7 +1192,7 @@
 }
 
 inline size_t Array::SizeOf() const {
-  return Size(GetLength(), klass_->GetComponentSize());
+  return SizeOf(GetLength(), klass_->GetComponentSize());
 }
 
 class DataObject : public Object {
@@ -1329,14 +1303,18 @@
     return string;
   }
 
-  static void InitClasses(Class* java_lang_String);
+  static void InitClass(Class* java_lang_String);
 
   static String* Alloc(Class* java_lang_String,
                        int32_t utf16_length) {
+    return Alloc(java_lang_String, CharArray::Alloc(utf16_length));
+  }
+
+  static String* Alloc(Class* java_lang_String,
+                       CharArray* array) {
     String* string = down_cast<String*>(java_lang_String->NewInstance());
-    CharArray* array = CharArray::Alloc(utf16_length);
     string->array_ = array;
-    string->count_ = utf16_length;
+    string->count_ = array->GetLength();
     return string;
   }
 
@@ -1464,6 +1442,29 @@
     return true;
   }
 
+  // Create a modified UTF-8 encoded std::string from a java/lang/String object.
+  std::string ToModifiedUtf8() const {
+    std::string result;
+    for (uint32_t i = 0; i < GetLength(); i++) {
+      uint16_t ch = CharAt(i);
+      // The most common case is (ch > 0 && ch <= 0x7f).
+      if (ch == 0 || ch > 0x7f) {
+        if (ch > 0x07ff) {
+          result.push_back((ch >> 12) | 0xe0);
+          result.push_back(((ch >> 6) & 0x3f) | 0x80);
+          result.push_back((ch & 0x3f) | 0x80);
+        } else { // (ch > 0x7f || ch == 0)
+          result.push_back((ch >> 6) | 0xc0);
+          result.push_back((ch & 0x3f) | 0x80);
+        }
+      } else {
+        result.push_back(ch);
+      }
+    }
+    return result;
+  }
+
+
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   CharArray* array_;
@@ -1484,6 +1485,28 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(String);
 };
 
+inline size_t Class::GetTypeSize(String* descriptor) {
+  switch (descriptor->CharAt(0)) {
+  case 'B': return 1;  // byte
+  case 'C': return 2;  // char
+  case 'D': return 8;  // double
+  case 'F': return 4;  // float
+  case 'I': return 4;  // int
+  case 'J': return 8;  // long
+  case 'S': return 2;  // short
+  case 'Z': return 1;  // boolean
+  case 'L': return sizeof(Object*);
+  case '[': return sizeof(Array*);
+  default:
+    LOG(ERROR) << "Unknown type " << descriptor;
+    return 0;
+  }
+}
+
+inline bool Class::IsArray() const {
+  return GetDescriptor()->CharAt(0) == '[';  // TODO: avoid parsing the descriptor
+}
+
 class InterfaceEntry {
  public:
   InterfaceEntry() : klass_(NULL), method_index_array_(NULL) {
diff --git a/src/object_test.cc b/src/object_test.cc
index 549544c..c757297 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -41,16 +41,16 @@
 
 TEST_F(ObjectTest, IsInSamePackage) {
   // Matches
-  EXPECT_TRUE(Class::IsInSamePackage("Ljava/lang/Object;",
-                                     "Ljava/lang/Class"));
-  EXPECT_TRUE(Class::IsInSamePackage("LFoo;",
-                                     "LBar;"));
+  EXPECT_TRUE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+                                     String::AllocFromModifiedUtf8("Ljava/lang/Class")));
+  EXPECT_TRUE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("LFoo;"),
+                                     String::AllocFromModifiedUtf8("LBar;")));
 
   // Mismatches
-  EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;",
-                                      "Ljava/io/File;"));
-  EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;",
-                                      "Ljava/lang/reflect/Method;"));
+  EXPECT_FALSE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+                                      String::AllocFromModifiedUtf8("Ljava/io/File;")));
+  EXPECT_FALSE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+                                      String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;")));
 }
 
 TEST_F(ObjectTest, AllocObjectArray) {
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index 6fc14b8..75c003b 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -69,7 +69,6 @@
   void* test_abort = reinterpret_cast<void*>(0xb);
   void* test_exit = reinterpret_cast<void*>(0xc);
   void* null = reinterpret_cast<void*>(NULL);
-  scoped_ptr<const DexFile> java_lang_dex_file(GetLibCoreDex());
   std::vector<const DexFile*> boot_class_path;
   boot_class_path.push_back(java_lang_dex_file_.get());
 
diff --git a/src/thread.cc b/src/thread.cc
index 44f0946..15382b9 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -176,7 +176,7 @@
 
   // TODO: need to *call* the constructor!
   UNIMPLEMENTED(WARNING) << "can't call "
-                         << exception_class->GetDescriptor() << ".<init> "
+                         << exception_class->GetDescriptor()->ToModifiedUtf8() << ".<init> "
                          << "\"" << msg << "\"";
 
   thread->SetException(exception);
diff --git a/src/unordered_map.h b/src/unordered_map.h
index 44e5417..caa859d 100644
--- a/src/unordered_map.h
+++ b/src/unordered_map.h
@@ -35,4 +35,10 @@
 #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/utils.cc b/src/utils.cc
index 419eb1c..058ca83 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -61,9 +61,9 @@
   if (obj->GetClass() == NULL) {
     return "(raw)";
   }
-  std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+  std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()->ToModifiedUtf8()));
   if (obj->IsClass()) {
-    result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()) + ">";
+    result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()->ToModifiedUtf8()) + ">";
   }
   return result;
 }