Interning image strings

Change-Id: I7e93b3975fe43d91d00b8185b65e8e0fd67ff6f4
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 570d797..a2e05c5 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -58,13 +58,13 @@
 
 ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_path,
                                  const std::vector<const DexFile*>& class_path,
-                                 InternTable* intern_table, Space* space) {
+                                 InternTable* intern_table, bool image) {
   CHECK_NE(boot_class_path.size(), 0U);
   UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
-  if (space == NULL) {
-    class_linker->Init(boot_class_path, class_path);
+  if (image) {
+    class_linker->InitFromImage(boot_class_path, class_path);
   } else {
-    class_linker->Init(boot_class_path, class_path, space);
+    class_linker->Init(boot_class_path, class_path);
   }
   // TODO: check for failure during initialization
   return class_linker.release();
@@ -115,16 +115,11 @@
   java_lang_String->SetStatus(Class::kStatusResolved);
 
   // Backfill Class descriptors missing until this point
-  // TODO: intern these strings
-  java_lang_Class->SetDescriptor(
-      String::AllocFromModifiedUtf8("Ljava/lang/Class;"));
-  java_lang_Object->SetDescriptor(
-      String::AllocFromModifiedUtf8("Ljava/lang/Object;"));
-  object_array_class->SetDescriptor(
-      String::AllocFromModifiedUtf8("[Ljava/lang/Object;"));
-  java_lang_String->SetDescriptor(
-      String::AllocFromModifiedUtf8("Ljava/lang/String;"));
-  char_array_class->SetDescriptor(String::AllocFromModifiedUtf8("[C"));
+  java_lang_Class->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Class;"));
+  java_lang_Object->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Object;"));
+  object_array_class->SetDescriptor(intern_table_->InternStrong("[Ljava/lang/Object;"));
+  java_lang_String->SetDescriptor(intern_table_->InternStrong("Ljava/lang/String;"));
+  char_array_class->SetDescriptor(intern_table_->InternStrong("[C"));
 
   // Create storage for root classes, save away our work so far (requires
   // descriptors)
@@ -156,7 +151,7 @@
   // Create int array type for AllocDexCache (done in AppendToBootClassPath)
   Class* int_array_class = AllocClass(java_lang_Class, sizeof(Class));
   int_array_class->SetArrayRank(1);
-  int_array_class->SetDescriptor(String::AllocFromModifiedUtf8("[I"));
+  int_array_class->SetDescriptor(intern_table_->InternStrong("[I"));
   int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
   IntArray::SetArrayClass(int_array_class);
   SetClassRoot(kIntArrayClass, int_array_class);
@@ -179,14 +174,15 @@
   // Field and Method are necessary so that FindClass can link members
   Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
   CHECK(java_lang_reflect_Field != NULL);
-  java_lang_reflect_Field->SetDescriptor(String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;"));
+  java_lang_reflect_Field->SetDescriptor(intern_table_->InternStrong("Ljava/lang/reflect/Field;"));
   java_lang_reflect_Field->SetObjectSize(sizeof(Field));
   SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
   java_lang_reflect_Field->SetStatus(Class::kStatusResolved);
   Field::SetClass(java_lang_reflect_Field);
 
   Class* java_lang_reflect_Method = AllocClass(java_lang_Class, sizeof(MethodClass));
-  java_lang_reflect_Method->SetDescriptor(String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;"));
+  java_lang_reflect_Method->SetDescriptor(
+      intern_table_->InternStrong("Ljava/lang/reflect/Method;"));
   CHECK(java_lang_reflect_Method != NULL);
   java_lang_reflect_Method->SetObjectSize(sizeof(Method));
   SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
@@ -358,7 +354,7 @@
   init_done_ = true;
 }
 
-struct ClassLinker::InitCallbackState {
+struct ClassLinker::InitFromImageCallbackState {
   ClassLinker* class_linker;
 
   Class* class_roots[kClassRootsMax];
@@ -370,15 +366,14 @@
   Set dex_caches;
 };
 
-void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
-                       const std::vector<const DexFile*>& class_path,
-                       Space* space) {
+void ClassLinker::InitFromImage(const std::vector<const DexFile*>& boot_class_path,
+                                const std::vector<const DexFile*>& class_path) {
   CHECK(!init_done_);
 
   HeapBitmap* heap_bitmap = Heap::GetLiveBits();
   DCHECK(heap_bitmap != NULL);
 
-  InitCallbackState state;
+  InitFromImageCallbackState state;
   state.class_linker = this;
   for (size_t i = 0; i < kClassRootsMax; i++) {
     ClassRoot class_root = static_cast<ClassRoot>(i);
@@ -386,7 +381,7 @@
   }
 
   // reinit clases_ table
-  heap_bitmap->Walk(InitCallback, &state);
+  heap_bitmap->Walk(InitFromImageCallback, &state);
 
   // reinit class_roots_
   Class* object_array_class = state.class_roots[kObjectArrayClass];
@@ -396,21 +391,13 @@
     SetClassRoot(class_root, state.class_roots[class_root]);
   }
 
-  // reinit intern table
-  // TODO: remove interned_array, make all strings in image interned (and remove space argument)
-  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_->RegisterStrong(string);
-  }
-
   // reinit array_interfaces_ from any array class instance, they should all be ==
   array_interfaces_ = GetClassRoot(kObjectArrayClass)->GetInterfaces();
   DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->GetInterfaces());
 
   // 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
+  typedef InitFromImageCallbackState::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();
@@ -454,11 +441,15 @@
   FinishInit();
 }
 
-void ClassLinker::InitCallback(Object* obj, void *arg) {
+void ClassLinker::InitFromImageCallback(Object* obj, void *arg) {
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
-  InitCallbackState* state = reinterpret_cast<InitCallbackState*>(arg);
+  InitFromImageCallbackState* state = reinterpret_cast<InitFromImageCallbackState*>(arg);
 
+  if (obj->IsString()) {
+    state->class_linker->intern_table_->RegisterStrong(obj->AsString());
+    return;
+  }
   if (!obj->IsClass()) {
     return;
   }
@@ -484,7 +475,7 @@
   }
 
   // check if this is a root, if so, register it
-  typedef InitCallbackState::Table::const_iterator It;  // TODO: C++0x auto
+  typedef InitFromImageCallbackState::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;
@@ -531,7 +522,7 @@
 
 DexCache* ClassLinker::AllocDexCache(const DexFile& dex_file) {
   DexCache* dex_cache = down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::LengthAsArray()));
-  dex_cache->Init(String::AllocFromModifiedUtf8(dex_file.GetLocation().c_str()),
+  dex_cache->Init(intern_table_->InternStrong(dex_file.GetLocation().c_str()),
                   AllocObjectArray<String>(dex_file.NumStringIds()),
                   AllocObjectArray<Class>(dex_file.NumTypeIds()),
                   AllocObjectArray<Method>(dex_file.NumMethodIds()),
@@ -760,7 +751,7 @@
   if (klass->GetDescriptor() != NULL) {
     DCHECK(klass->GetDescriptor()->Equals(descriptor));
   } else {
-    klass->SetDescriptor(String::AllocFromModifiedUtf8(descriptor));
+    klass->SetDescriptor(intern_table_->InternStrong(descriptor));
   }
   uint32_t access_flags = dex_class_def.access_flags_;
   // Make sure there aren't any "bonus" flags set, since we use them for runtime
@@ -778,7 +769,7 @@
   size_t num_direct_methods = header.direct_methods_size_;
   size_t num_virtual_methods = header.virtual_methods_size_;
 
-  klass->SetSourceFile(String::AllocFromModifiedUtf8(dex_file.dexGetSourceFile(dex_class_def)));
+  klass->SetSourceFile(intern_table_->InternStrong(dex_file.dexGetSourceFile(dex_class_def)));
 
   // Load class interfaces.
   LoadInterfaces(dex_file, dex_class_def, klass);
@@ -885,12 +876,12 @@
   {
     int32_t utf16_length;
     std::string utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_, &utf16_length));
-    dst->SetSignature(String::AllocFromModifiedUtf8(utf16_length, utf8.c_str()));
+    dst->SetSignature(intern_table_->InternStrong(utf16_length, utf8.c_str()));
   }
   dst->SetProtoIdx(method_id.proto_idx_);
   dst->SetCodeItemOffset(src.code_off_);
   const char* shorty = dex_file.GetShorty(method_id.proto_idx_);
-  dst->SetShorty(String::AllocFromModifiedUtf8(shorty));
+  dst->SetShorty(intern_table_->InternStrong(shorty));
   dst->SetAccessFlags(src.access_flags_);
   dst->SetReturnTypeIdx(dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_);
 
@@ -965,7 +956,7 @@
   Class* klass = AllocClass(sizeof(Class));
   CHECK(klass != NULL);
   klass->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
-  klass->SetDescriptor(String::AllocFromModifiedUtf8(descriptor));
+  klass->SetDescriptor(intern_table_->InternStrong(descriptor));
   klass->SetPrimitiveType(type);
   klass->SetStatus(Class::kStatusInitialized);
   bool success = InsertClass(descriptor, klass);
@@ -1078,7 +1069,7 @@
   if (new_class->GetDescriptor() != NULL) {
     DCHECK(new_class->GetDescriptor()->Equals(descriptor));
   } else {
-    new_class->SetDescriptor(String::AllocFromModifiedUtf8(descriptor.ToString().c_str()));
+    new_class->SetDescriptor(intern_table_->InternStrong(descriptor.ToString().c_str()));
   }
   Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
diff --git a/src/class_linker.h b/src/class_linker.h
index fa0c789..b250593 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -24,10 +24,10 @@
 
 class ClassLinker {
  public:
-  // Initializes the class linker using DexFile and an optional boot Space.
+  // Initializes the class linker using DexFiles and an optional an image.
   static ClassLinker* Create(const std::vector<const DexFile*>& boot_class_path,
                              const std::vector<const DexFile*>& class_path,
-                             InternTable* intern_table, Space* boot_space);
+                             InternTable* intern_table, bool image);
 
   ~ClassLinker();
 
@@ -153,12 +153,11 @@
   void Init(const std::vector<const DexFile*>& boot_class_path_,
             const std::vector<const DexFile*>& class_path_);
 
-  // Initialize class linker from pre-initialized space.
-  void Init(const std::vector<const DexFile*>& boot_class_path_,
-            const std::vector<const DexFile*>& class_path_,
-            Space* space);
-  static void InitCallback(Object* obj, void *arg);
-  struct InitCallbackState;
+  // Initialize class linker from pre-initialized image.
+  void InitFromImage(const std::vector<const DexFile*>& boot_class_path_,
+                     const std::vector<const DexFile*>& class_path_);
+  static void InitFromImageCallback(Object* obj, void *arg);
+  struct InitFromImageCallbackState;
 
   void FinishInit();
 
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index aaec17b..2161949 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -106,7 +106,7 @@
             // Skip past "this"
             sReg++;
         }
-        String* shorty = cUnit->method->GetShorty();
+        const String* shorty = cUnit->method->GetShorty();
         for (int i = 1; i < shorty->GetLength(); i++) {
             char arg = shorty->CharAt(i);
             // Is it wide?
diff --git a/src/image.h b/src/image.h
index 00f72ba..02d15de 100644
--- a/src/image.h
+++ b/src/image.h
@@ -15,8 +15,7 @@
  public:
   ImageHeader() {}
 
-  ImageHeader(uint32_t base_addr, uint32_t intern_addr)
-      : base_addr_(base_addr), intern_addr_(intern_addr) {
+  ImageHeader(uint32_t base_addr) : base_addr_(base_addr) {
     memcpy(magic_, kImageMagic, sizeof(kImageMagic));
     memcpy(version_, kImageVersion, sizeof(kImageVersion));
   }
@@ -35,10 +34,6 @@
     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];
@@ -48,10 +43,6 @@
 
   // required base address for mapping the image.
   uint32_t base_addr_;
-
-  // absolute address of an Object[] of Strings to InternTable::RegisterStrong.
-  // TODO: remove after interning all Strings in image
-  uint32_t intern_addr_;
 };
 
 }  // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 859da86..c265838 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -57,41 +57,6 @@
   return true;
 }
 
-namespace {
-
-struct InternTableVisitorState {
-  int index;
-  ObjectArray<const Object>* interned_array;
-};
-
-void InternTableVisitor(const Object* obj, void* arg) {
-  InternTableVisitorState* state = reinterpret_cast<InternTableVisitorState*>(arg);
-  state->interned_array->Set(state->index++, obj);
-}
-
-ObjectArray<const Object>* CreateInternedArray() {
-  // build a Object[] of the interned strings for reinit
-  // TODO: avoid creating this future garbage
-  Runtime* runtime = Runtime::Current();
-  ClassLinker* class_linker = runtime->GetClassLinker();
-  const InternTable& intern_table = *runtime->GetInternTable();
-  size_t size = intern_table.Size();
-  CHECK_NE(0U, size);
-
-  Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
-  ObjectArray<const Object>* interned_array = ObjectArray<const 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);
@@ -99,9 +64,28 @@
   if (!image_writer->InSourceSpace(obj)) {
     return;
   }
-  image_writer->SetImageOffset(obj, image_writer->image_top_);
-  image_writer->image_top_ += RoundUp(obj->SizeOf(), 8);  // 64-bit alignment
-  DCHECK_LT(image_writer->image_top_, image_writer->image_->GetLength());
+
+  // if it is a string, we want to intern it if its not interned.
+  if (obj->IsString()) {
+    // we must be an interned string that was forward referenced and already assigned
+    if (IsImageOffsetAssigned(obj)) {
+      DCHECK_EQ(obj, obj->AsString()->Intern());
+      return;
+    }
+    String* interned = obj->AsString()->Intern();
+    if (obj != interned) {
+      if (!IsImageOffsetAssigned(interned)) {
+        // interned obj is after us, allocate its location early
+        image_writer->AssignImageOffset(interned);
+      }
+      // point those looking for this object to the interned version.
+      SetImageOffset(obj, GetImageOffset(interned));
+      return;
+    }
+    // else (obj == interned), nothing to do but fall through to the normal case
+  }
+
+  image_writer->AssignImageOffset(obj);
 
   // sniff out the DexCaches on this pass for use on the next pass
   if (obj->IsClass()) {
@@ -116,22 +100,18 @@
 }
 
 void ImageWriter::CalculateNewObjectOffsets() {
-  ObjectArray<const Object>* interned_array = CreateInternedArray();
-
   HeapBitmap* heap_bitmap = Heap::GetLiveBits();
   DCHECK(heap_bitmap != NULL);
   DCHECK_EQ(0U, image_top_);
 
-  // leave space for the header, but do not write it yet, we need to
-  // know where interned_array is going to end up
+  // leave space for the header, but do not write it yet
   image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
 
   heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);  // TODO: add Space-limited Walk
   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)));
+  // return to write header at start of image
+  ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_));
   memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
 
   // Note that top_ is left at end of used space
diff --git a/src/image_writer.h b/src/image_writer.h
index 9dac31a..a5d3d6a73 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -29,12 +29,25 @@
   bool Init();
 
   // we use the lock word to store the offset of the object in the image
-  static void SetImageOffset(Object* object, size_t offset) {
+  void AssignImageOffset(Object* object) {
     DCHECK(object != NULL);
     DCHECK(object->GetMonitor() == NULL);  // should be no lock
+    SetImageOffset(object, image_top_);
+    image_top_ += RoundUp(object->SizeOf(), 8);  // 64-bit alignment
+    DCHECK_LT(image_top_, image_->GetLength());
+  }
+  static void SetImageOffset(Object* object, size_t offset) {
+    DCHECK(object != NULL);
+    // should be no lock (but it might be forward referenced interned string)
+    DCHECK(object->GetMonitor() == NULL || object->IsString());
     DCHECK_NE(0U, offset);
     object->SetMonitor(reinterpret_cast<Monitor*>(offset));
   }
+  static size_t IsImageOffsetAssigned(const Object* object) {
+    DCHECK(object != NULL);
+    size_t offset = reinterpret_cast<size_t>(object->GetMonitor());
+    return offset != 0U;
+  }
   static size_t GetImageOffset(const Object* object) {
     DCHECK(object != NULL);
     size_t offset = reinterpret_cast<size_t>(object->GetMonitor());
diff --git a/src/intern_table.cc b/src/intern_table.cc
index 41c1b2a..aa27ace 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -24,11 +24,11 @@
   // Note: we deliberately don't visit the weak_interns_ table.
 }
 
-const String* InternTable::Lookup(Table& table, const String* s, uint32_t hash_code) {
+String* InternTable::Lookup(Table& table, String* s, uint32_t hash_code) {
   intern_table_lock_.AssertHeld();
   typedef Table::const_iterator It; // TODO: C++0x auto
   for (It it = table.find(hash_code), end = table.end(); it != end; ++it) {
-    const String* existing_string = it->second;
+    String* existing_string = it->second;
     if (existing_string->Equals(s)) {
       return existing_string;
     }
@@ -36,13 +36,13 @@
   return NULL;
 }
 
-const String* InternTable::Insert(Table& table, const String* s, uint32_t hash_code) {
+String* InternTable::Insert(Table& table, String* s, uint32_t hash_code) {
   intern_table_lock_.AssertHeld();
   table.insert(std::make_pair(hash_code, s));
   return s;
 }
 
-void InternTable::RegisterStrong(const String* s) {
+void InternTable::RegisterStrong(String* s) {
   MutexLock mu(intern_table_lock_);
   Insert(strong_interns_, s, s->GetHashCode());
 }
@@ -58,7 +58,7 @@
   }
 }
 
-const String* InternTable::Insert(const String* s, bool is_strong) {
+String* InternTable::Insert(String* s, bool is_strong) {
   MutexLock mu(intern_table_lock_);
 
   DCHECK(s != NULL);
@@ -66,13 +66,13 @@
 
   if (is_strong) {
     // Check the strong table for a match.
-    const String* strong = Lookup(strong_interns_, s, hash_code);
+    String* strong = Lookup(strong_interns_, s, hash_code);
     if (strong != NULL) {
       return strong;
     }
 
     // There is no match in the strong table, check the weak table.
-    const String* weak = Lookup(weak_interns_, s, hash_code);
+    String* weak = Lookup(weak_interns_, s, hash_code);
     if (weak != NULL) {
       // A match was found in the weak table. Promote to the strong table.
       Remove(weak_interns_, weak, hash_code);
@@ -84,12 +84,12 @@
   }
 
   // Check the strong table for a match.
-  const String* strong = Lookup(strong_interns_, s, hash_code);
+  String* strong = Lookup(strong_interns_, s, hash_code);
   if (strong != NULL) {
     return strong;
   }
   // Check the weak table for a match.
-  const String* weak = Lookup(weak_interns_, s, hash_code);
+  String* weak = Lookup(weak_interns_, s, hash_code);
   if (weak != NULL) {
     return weak;
   }
@@ -97,15 +97,23 @@
   return Insert(weak_interns_, s, hash_code);
 }
 
-const String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
+String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
   return Insert(String::AllocFromModifiedUtf8(utf16_length, utf8_data), true);
 }
 
-const String* InternTable::InternWeak(const String* s) {
+String* InternTable::InternStrong(const char* utf8_data) {
+  return Insert(String::AllocFromModifiedUtf8(utf8_data), true);
+}
+
+String* InternTable::InternStrong(String* s) {
+  return Insert(s, true);
+}
+
+String* InternTable::InternWeak(String* s) {
   return Insert(s, false);
 }
 
-bool InternTable::ContainsWeak(const String* s) {
+bool InternTable::ContainsWeak(String* s) {
   MutexLock mu(intern_table_lock_);
   const String* found = Lookup(weak_interns_, s, s->GetHashCode());
   return found == s;
diff --git a/src/intern_table.h b/src/intern_table.h
index fe84347..c814a1b 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -26,14 +26,20 @@
   InternTable();
 
   // Interns a potentially new string in the 'strong' table. (See above.)
-  const String* InternStrong(int32_t utf16_length, const char* utf8_data);
+  String* InternStrong(int32_t utf16_length, const char* utf8_data);
+
+  // Interns a potentially new string in the 'strong' table. (See above.)
+  String* InternStrong(const char* utf8_data);
+
+  // Interns a potentially new string in the 'strong' table. (See above.)
+  String* InternStrong(String* s);
 
   // Interns a potentially new string in the 'weak' table. (See above.)
-  const String* InternWeak(const String* s);
+  String* InternWeak(String* s);
 
   // Register a String trusting that it is safe to intern.
   // Used when reinitializing InternTable from an image.
-  void RegisterStrong(const String* s);
+  void RegisterStrong(String* s);
 
   // Removes all weak interns for which the predicate functor 'p' returns true.
   // (We use an explicit Predicate type rather than a template to keep implementation
@@ -44,19 +50,19 @@
   };
   void RemoveWeakIf(const Predicate& p);
 
-  bool ContainsWeak(const String* s);
+  bool ContainsWeak(String* s);
 
   size_t Size() const;
 
   void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
 
  private:
-  typedef std::tr1::unordered_multimap<int32_t, const String*> Table;
+  typedef std::tr1::unordered_multimap<int32_t, String*> Table;
 
-  const String* Insert(const String* s, bool is_strong);
+  String* Insert(String* s, bool is_strong);
 
-  const String* Lookup(Table& table, const String* s, uint32_t hash_code);
-  const String* Insert(Table& table, const String* s, uint32_t hash_code);
+  String* Lookup(Table& table, String* s, uint32_t hash_code);
+  String* Insert(Table& table, String* s, uint32_t hash_code);
   void Remove(Table& table, const String* s, uint32_t hash_code);
 
   mutable Mutex intern_table_lock_;
diff --git a/src/intern_table_test.cc b/src/intern_table_test.cc
index 0362b05..3f9fab0 100644
--- a/src/intern_table_test.cc
+++ b/src/intern_table_test.cc
@@ -90,9 +90,9 @@
   {
     // Strongs are never weak.
     InternTable t;
-    const String* foo_1 = t.InternStrong(3, "foo");
+    String* foo_1 = t.InternStrong(3, "foo");
     EXPECT_FALSE(t.ContainsWeak(foo_1));
-    const String* foo_2 = t.InternStrong(3, "foo");
+    String* foo_2 = t.InternStrong(3, "foo");
     EXPECT_FALSE(t.ContainsWeak(foo_2));
     EXPECT_EQ(foo_1, foo_2);
   }
@@ -100,9 +100,9 @@
   {
     // Weaks are always weak.
     InternTable t;
-    const String* foo_1 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
+    String* foo_1 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
     EXPECT_TRUE(t.ContainsWeak(foo_1));
-    const String* foo_2 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
+    String* foo_2 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
     EXPECT_TRUE(t.ContainsWeak(foo_2));
     EXPECT_EQ(foo_1, foo_2);
   }
@@ -110,9 +110,9 @@
   {
     // A weak can be promoted to a strong.
     InternTable t;
-    const String* foo_1 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
+    String* foo_1 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
     EXPECT_TRUE(t.ContainsWeak(foo_1));
-    const String* foo_2 = t.InternStrong(3, "foo");
+    String* foo_2 = t.InternStrong(3, "foo");
     EXPECT_FALSE(t.ContainsWeak(foo_2));
     EXPECT_EQ(foo_1, foo_2);
   }
@@ -120,9 +120,9 @@
   {
     // Interning a weak after a strong gets you the strong.
     InternTable t;
-    const String* foo_1 = t.InternStrong(3, "foo");
+    String* foo_1 = t.InternStrong(3, "foo");
     EXPECT_FALSE(t.ContainsWeak(foo_1));
-    const String* foo_2 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
+    String* foo_2 = t.InternWeak(String::AllocFromModifiedUtf8("foo"));
     EXPECT_FALSE(t.ContainsWeak(foo_2));
     EXPECT_EQ(foo_1, foo_2);
   }
diff --git a/src/java_lang_String.cc b/src/java_lang_String.cc
index fbabd43..9aa5221 100644
--- a/src/java_lang_String.cc
+++ b/src/java_lang_String.cc
@@ -148,8 +148,8 @@
 }
 
 jstring String_intern(JNIEnv* env, jobject javaThis) {
-  const String* s = Decode<String*>(env, javaThis);
-  const String* result = s->Intern();
+  String* s = Decode<String*>(env, javaThis);
+  String* result = s->Intern();
   return AddLocalReference<jstring>(env, result);
 }
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 0f464d2..0129fc5 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -144,7 +144,7 @@
 byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) {
   size_t num_bytes = method->NumArgArrayBytes();
   UniquePtr<byte[]> arg_array(new byte[num_bytes]);
-  String* shorty = method->GetShorty();
+  const String* shorty = method->GetShorty();
   for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) {
     switch (shorty->CharAt(i)) {
       case 'Z':
@@ -181,7 +181,7 @@
 byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, jvalue* args) {
   size_t num_bytes = method->NumArgArrayBytes();
   UniquePtr<byte[]> arg_array(new byte[num_bytes]);
-  String* shorty = method->GetShorty();
+  const String* shorty = method->GetShorty();
   for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) {
     switch (shorty->CharAt(i)) {
       case 'Z':
diff --git a/src/object.cc b/src/object.cc
index 3696374..d78eb24 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -359,7 +359,7 @@
 }
 
 size_t Method::NumArgArrayBytes() const {
-  String* shorty = GetShorty();
+  const String* shorty = GetShorty();
   size_t num_bytes = 0;
   for (int i = 1; i < shorty->GetLength(); ++i) {
     char ch = shorty->CharAt(i);
@@ -385,7 +385,7 @@
 // The number of reference arguments to this method including implicit this
 // pointer
 size_t Method::NumReferenceArgs() const {
-  String* shorty = GetShorty();
+  const String* shorty = GetShorty();
   size_t result = IsStatic() ? 0 : 1;  // The implicit this pointer.
   for (int i = 1; i < shorty->GetLength(); i++) {
     char ch = shorty->CharAt(i);
@@ -398,7 +398,7 @@
 
 // The number of long or double arguments
 size_t Method::NumLongOrDoubleArgs() const {
-  String* shorty = GetShorty();
+  const String* shorty = GetShorty();
   size_t result = 0;
   for (int i = 1; i < shorty->GetLength(); i++) {
     char ch = shorty->CharAt(i);
@@ -981,7 +981,7 @@
   java_lang_String_ = NULL;
 }
 
-const String* String::Intern() const {
+String* String::Intern() {
   return Runtime::Current()->GetInternTable()->InternWeak(this);
 }
 
diff --git a/src/object.h b/src/object.h
index 70a9b33..959abcb 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1940,16 +1940,9 @@
                           klass, false);
   }
 
-  String* GetSourceFile() const {
-    DCHECK(IsLoaded());
-    return GetFieldPtr<String*>(
-        OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
-  }
+  String* GetSourceFile() const;
 
-  void SetSourceFile(String* new_source_file) {
-    SetFieldPtr<String*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_),
-                             new_source_file, false);
-  }
+  void SetSourceFile(String* new_source_file);
 
  private:
   bool Implements(const Class* klass) const;
@@ -2419,7 +2412,7 @@
 
   uint16_t CharAt(int32_t index) const;
 
-  const String* Intern() const;
+  String* Intern();
 
   static String* AllocFromUtf16(int32_t utf16_length,
                                 const uint16_t* utf16_data_in,
@@ -2589,6 +2582,15 @@
                  new_descriptor, false);
 }
 
+inline String* Class::GetSourceFile() const {
+  DCHECK(IsLoaded());
+  return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
+}
+
+inline void Class::SetSourceFile(String* new_source_file) {
+  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), new_source_file, false);
+}
+
 inline uint32_t Method::GetAccessFlags() const {
   DCHECK(GetDeclaringClass()->IsLoaded());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);