Reduce meta-data object sizes, introduce meta-data helper classes.

Change-Id: Id14ad218f1c74c659701352fdf1a45bf6444daa3
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 659dcb8..037edfc 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -21,6 +21,7 @@
 
 #include "class_linker.h"
 #include "logging.h"
+#include "object_utils.h"
 #include "scoped_jni_thread_state.h"
 #include "thread.h"
 #include "runtime.h"
@@ -112,7 +113,7 @@
   // such as NewByteArray.
   // If -verbose:third-party-jni is on, we want to log any JNI function calls
   // made by a third-party native method.
-  std::string classNameStr(method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8());
+  std::string classNameStr(MethodHelper(method).GetDeclaringClassDescriptor());
   if (!vm->trace.empty() && classNameStr.find(vm->trace) != std::string::npos) {
     return true;
   }
@@ -180,7 +181,7 @@
     if (f == NULL) {
       return;
     }
-    Class* field_type = f->GetType();
+    Class* field_type = FieldHelper(f).GetType();
     if (!field_type->IsPrimitive()) {
       if (java_object != NULL) {
         Object* obj = Decode<Object*>(ts, java_object);
@@ -237,10 +238,9 @@
     if (f == NULL) {
       return;
     }
-    // check invariant that all jfieldIDs have resolved types
-    DCHECK(f->GetType() != NULL);
     Class* c = o->GetClass();
-    if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f->GetTypeDescriptor()) == NULL) {
+    FieldHelper fh(f);
+    if (c->FindInstanceField(fh.GetName(), fh.GetTypeDescriptor()) == NULL) {
       LOG(ERROR) << "JNI ERROR: jfieldID " << PrettyField(f)
                  << " not valid for an object of class " << PrettyTypeOf(o);
       JniAbort();
@@ -263,11 +263,11 @@
    */
   void CheckSig(jmethodID mid, const char* expectedType, bool isStatic) {
     ScopedJniThreadState ts(env_);
-    const Method* m = CheckMethodID(mid);
+    Method* m = CheckMethodID(mid);
     if (m == NULL) {
       return;
     }
-    if (*expectedType != m->GetShorty()->CharAt(0)) {
+    if (*expectedType != MethodHelper(m).GetShorty()[0]) {
       LOG(ERROR) << "JNI ERROR: the return type of " << function_name_ << " does not match "
                  << PrettyMethod(m);
       JniAbort();
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 9e4a76d..6555070 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -19,6 +19,7 @@
 #include "monitor.h"
 #include "oat_file.h"
 #include "object.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "runtime_support.h"
 #include "ScopedLocalRef.h"
@@ -59,13 +60,14 @@
 
 void ThrowNoSuchMethodError(const char* kind,
     Class* c, const StringPiece& name, const StringPiece& signature) {
-  DexCache* dex_cache = c->GetDexCache();
+  ClassHelper kh(c);
   std::ostringstream msg;
   msg << "no " << kind << " method " << name << "." << signature
-      << " in class " << c->GetDescriptor()->ToModifiedUtf8()
+      << " in class " << kh.GetDescriptor()
       << " or its superclasses";
-  if (dex_cache) {
-    msg << " (defined in " << dex_cache->GetLocation()->ToModifiedUtf8() << ")";
+  std::string location(kh.GetLocation());
+  if (!location.empty()) {
+    msg << " (defined in " << location << ")";
   }
   Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
 }
@@ -81,11 +83,11 @@
 
   if (c->GetVerifyErrorClass() != NULL) {
     // TODO: change the verifier to store an _instance_, with a useful detail message?
-    std::string error_descriptor(c->GetVerifyErrorClass()->GetDescriptor()->ToModifiedUtf8());
-    Thread::Current()->ThrowNewException(error_descriptor.c_str(),
-        PrettyDescriptor(c->GetDescriptor()).c_str());
+    ClassHelper ve_ch(c->GetVerifyErrorClass());
+    std::string error_descriptor(ve_ch.GetDescriptor());
+    Thread::Current()->ThrowNewException(error_descriptor.c_str(), PrettyDescriptor(c).c_str());
   } else {
-    ThrowNoClassDefFoundError("%s", PrettyDescriptor(c->GetDescriptor()).c_str());
+    ThrowNoClassDefFoundError("%s", PrettyDescriptor(c).c_str());
   }
 }
 
@@ -204,7 +206,6 @@
       dex_lock_("ClassLinker dex lock"),
       classes_lock_("ClassLinker classes lock"),
       class_roots_(NULL),
-      array_interfaces_(NULL),
       array_iftable_(NULL),
       init_done_(false),
       intern_table_(intern_table) {
@@ -269,14 +270,6 @@
   java_lang_String->SetObjectSize(sizeof(String));
   java_lang_String->SetStatus(Class::kStatusResolved);
 
-  // Backfill Class descriptors missing until this point
-  java_lang_Class->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Class;"));
-  java_lang_Object->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Object;"));
-  class_array_class->SetDescriptor(intern_table_->InternStrong("[Ljava/lang/Class;"));
-  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)
   class_roots_ = ObjectArray<Class>::Alloc(object_array_class.get(), kClassRootsMax);
@@ -299,12 +292,10 @@
   SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Primitive::kPrimVoid));
 
   // Create array interface entries to populate once we can load system classes
-  array_interfaces_ = AllocClassArray(2);
   array_iftable_ = AllocObjectArray<InterfaceEntry>(2);
 
   // Create int array type for AllocDexCache (done in AppendToBootClassPath)
   SirtRef<Class> int_array_class(AllocClass(java_lang_Class.get(), sizeof(Class)));
-  int_array_class->SetDescriptor(intern_table_->InternStrong("[I"));
   int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
   IntArray::SetArrayClass(int_array_class.get());
   SetClassRoot(kIntArrayClass, int_array_class.get());
@@ -324,7 +315,6 @@
 
   // Constructor, Field, and Method are necessary so that FindClass can link members
   SirtRef<Class> java_lang_reflect_Constructor(AllocClass(java_lang_Class.get(), sizeof(MethodClass)));
-  java_lang_reflect_Constructor->SetDescriptor(intern_table_->InternStrong("Ljava/lang/reflect/Constructor;"));
   CHECK(java_lang_reflect_Constructor.get() != NULL);
   java_lang_reflect_Constructor->SetObjectSize(sizeof(Method));
   SetClassRoot(kJavaLangReflectConstructor, java_lang_reflect_Constructor.get());
@@ -332,14 +322,12 @@
 
   SirtRef<Class> java_lang_reflect_Field(AllocClass(java_lang_Class.get(), sizeof(FieldClass)));
   CHECK(java_lang_reflect_Field.get() != NULL);
-  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.get());
   java_lang_reflect_Field->SetStatus(Class::kStatusResolved);
   Field::SetClass(java_lang_reflect_Field.get());
 
   SirtRef<Class> java_lang_reflect_Method(AllocClass(java_lang_Class.get(), sizeof(MethodClass)));
-  java_lang_reflect_Method->SetDescriptor(intern_table_->InternStrong("Ljava/lang/reflect/Method;"));
   CHECK(java_lang_reflect_Method.get() != NULL);
   java_lang_reflect_Method->SetObjectSize(sizeof(Method));
   SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method.get());
@@ -398,21 +386,19 @@
   CHECK(java_lang_Cloneable != NULL);
   Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;");
   CHECK(java_io_Serializable != NULL);
-  CHECK(array_interfaces_ != NULL);
-  array_interfaces_->Set(0, java_lang_Cloneable);
-  array_interfaces_->Set(1, java_io_Serializable);
   // We assume that Cloneable/Serializable don't have superinterfaces --
   // normally we'd have to crawl up and explicitly list all of the
   // supers as well.
-  array_iftable_->Set(0, AllocInterfaceEntry(array_interfaces_->Get(0)));
-  array_iftable_->Set(1, AllocInterfaceEntry(array_interfaces_->Get(1)));
+  array_iftable_->Set(0, AllocInterfaceEntry(java_lang_Cloneable));
+  array_iftable_->Set(1, AllocInterfaceEntry(java_io_Serializable));
 
   // Sanity check Class[] and Object[]'s interfaces
-  CHECK_EQ(java_lang_Cloneable, class_array_class->GetInterface(0));
-  CHECK_EQ(java_io_Serializable, class_array_class->GetInterface(1));
-  CHECK_EQ(java_lang_Cloneable, object_array_class->GetInterface(0));
-  CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
-
+  ClassHelper kh(class_array_class.get(), this);
+  CHECK_EQ(java_lang_Cloneable, kh.GetInterface(0));
+  CHECK_EQ(java_io_Serializable, kh.GetInterface(1));
+  kh.ChangeClass(object_array_class.get());
+  CHECK_EQ(java_lang_Cloneable, kh.GetInterface(0));
+  CHECK_EQ(java_io_Serializable, kh.GetInterface(1));
   // run Class, Constructor, Field, and Method through FindSystemClass.
   // this initializes their dex_cache_ fields and register them in classes_.
   Class* Class_class = FindSystemClass("Ljava/lang/Class;");
@@ -497,25 +483,37 @@
 
   Heap::SetWellKnownClasses(java_lang_ref_FinalizerReference, java_lang_ref_ReferenceQueue);
 
+  const DexFile& java_lang_dex = FindDexFile(java_lang_ref_Reference->GetDexCache());
+
   Field* pendingNext = java_lang_ref_Reference->GetInstanceField(0);
-  CHECK(pendingNext->GetName()->Equals("pendingNext"));
-  CHECK_EQ(ResolveType(pendingNext->GetTypeIdx(), pendingNext), java_lang_ref_Reference);
+  FieldHelper fh(pendingNext, this);
+  CHECK_STREQ(fh.GetName(), "pendingNext");
+  CHECK_EQ(java_lang_dex.GetFieldId(pendingNext->GetDexFieldIndex()).type_idx_,
+           java_lang_ref_Reference->GetDexTypeIndex());
 
   Field* queue = java_lang_ref_Reference->GetInstanceField(1);
-  CHECK(queue->GetName()->Equals("queue"));
-  CHECK_EQ(ResolveType(queue->GetTypeIdx(), queue), java_lang_ref_ReferenceQueue);
+  fh.ChangeField(queue);
+  CHECK_STREQ(fh.GetName(), "queue");
+  CHECK_EQ(java_lang_dex.GetFieldId(queue->GetDexFieldIndex()).type_idx_,
+           java_lang_ref_ReferenceQueue->GetDexTypeIndex());
 
   Field* queueNext = java_lang_ref_Reference->GetInstanceField(2);
-  CHECK(queueNext->GetName()->Equals("queueNext"));
-  CHECK_EQ(ResolveType(queueNext->GetTypeIdx(), queueNext), java_lang_ref_Reference);
+  fh.ChangeField(queueNext);
+  CHECK_STREQ(fh.GetName(), "queueNext");
+  CHECK_EQ(java_lang_dex.GetFieldId(queueNext->GetDexFieldIndex()).type_idx_,
+           java_lang_ref_Reference->GetDexTypeIndex());
 
   Field* referent = java_lang_ref_Reference->GetInstanceField(3);
-  CHECK(referent->GetName()->Equals("referent"));
-  CHECK_EQ(ResolveType(referent->GetTypeIdx(), referent), GetClassRoot(kJavaLangObject));
+  fh.ChangeField(referent);
+  CHECK_STREQ(fh.GetName(), "referent");
+  CHECK_EQ(java_lang_dex.GetFieldId(referent->GetDexFieldIndex()).type_idx_,
+           GetClassRoot(kJavaLangObject)->GetDexTypeIndex());
 
   Field* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2);
-  CHECK(zombie->GetName()->Equals("zombie"));
-  CHECK_EQ(ResolveType(zombie->GetTypeIdx(), zombie), GetClassRoot(kJavaLangObject));
+  fh.ChangeField(zombie);
+  CHECK_STREQ(fh.GetName(), "zombie");
+  CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_,
+           GetClassRoot(kJavaLangObject)->GetDexTypeIndex());
 
   Heap::SetReferenceOffsets(referent->GetOffset(),
                             queue->GetOffset(),
@@ -534,7 +532,6 @@
   }
 
   CHECK(array_iftable_ != NULL);
-  CHECK(array_interfaces_ != NULL);
 
   // disable the slow paths in FindClass and CreatePrimitiveClass now
   // that Object, Class, and Object[] are setup
@@ -611,7 +608,9 @@
     LOG(INFO) << "ClassLinker::OpenOat entering";
   }
   const ImageHeader& image_header = space->GetImageHeader();
-  String* oat_location = image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString();
+  // Grab location but don't use Object::AsString as we haven't yet initialized the roots to
+  // check the down cast
+  String* oat_location = down_cast<String*>(image_header.GetImageRoot(ImageHeader::kOatLocation));
   std::string oat_filename;
   oat_filename += runtime->GetHostPrefix();
   oat_filename += oat_location->ToModifiedUtf8();
@@ -734,6 +733,14 @@
       Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
       ObjectArray<DexCache>* dex_caches = dex_caches_object->AsObjectArray<DexCache>();
 
+      if (i == 0) {
+        // Special case of setting up the String class early so that we can test arbitrary objects
+        // as being Strings or not
+        Class* java_lang_String = spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)
+            ->AsObjectArray<Class>()->Get(kJavaLangString);
+        String::SetClass(java_lang_String);
+      }
+
       CHECK_EQ(oat_file->GetOatHeader().GetDexFileCount(),
                static_cast<uint32_t>(dex_caches->GetLength()));
       for (int i = 0; i < dex_caches->GetLength(); i++) {
@@ -767,13 +774,10 @@
   Object* class_roots_object = spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots);
   class_roots_ = class_roots_object->AsObjectArray<Class>();
 
-  // reinit array_interfaces_ and array_iftable_ from any array class instance, they should all be ==
-  array_interfaces_ = GetClassRoot(kObjectArrayClass)->GetInterfaces();
-  DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->GetInterfaces());
+  // reinit array_iftable_ from any array class instance, they should be ==
   array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable();
   DCHECK(array_iftable_ == GetClassRoot(kBooleanArrayClass)->GetIfTable());
-
-  String::SetClass(GetClassRoot(kJavaLangString));
+  // String class root was set above
   Field::SetClass(GetClassRoot(kJavaLangReflectField));
   Method::SetClasses(GetClassRoot(kJavaLangReflectConstructor), GetClassRoot(kJavaLangReflectMethod));
   BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
@@ -806,7 +810,7 @@
   if (obj->IsClass()) {
     // restore class to ClassLinker::classes_ table
     Class* klass = obj->AsClass();
-    std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+    std::string descriptor(ClassHelper(klass, class_linker).GetDescriptor());
     bool success = class_linker->InsertClass(descriptor, klass, true);
     DCHECK(success);
     return;
@@ -832,7 +836,6 @@
     // Note. we deliberately ignore the class roots in the image (held in image_classes_)
   }
 
-  visitor(array_interfaces_, arg);
   visitor(array_iftable_, arg);
 }
 
@@ -960,7 +963,7 @@
     // Check for circular dependencies between classes.
     if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
       self->ThrowNewException("Ljava/lang/ClassCircularityError;",
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
+          PrettyDescriptor(klass).c_str());
       return NULL;
     }
     // Wait for the pending initialization to complete.
@@ -985,15 +988,16 @@
   Thread* self = Thread::Current();
   DCHECK(self != NULL);
   CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+  if (descriptor.size() == 1) {
+    // only the descriptors of primitive types should be 1 character long, also avoid class lookup
+    // for primitive classes that aren't backed by dex files.
+    return FindPrimitiveClass(descriptor[0]);
+  }
   // Find the class in the loaded classes table.
   Class* klass = LookupClass(descriptor, class_loader);
   if (klass != NULL) {
     return EnsureResolved(klass);
   }
-  if (descriptor.size() == 1) {
-    // only the descriptors of primitive types should be 1 character long
-    return FindPrimitiveClass(descriptor[0]);
-  }
   // Class is not yet loaded.
   if (descriptor[0] == '[') {
     return CreateArrayClass(descriptor, class_loader);
@@ -1179,14 +1183,6 @@
   CHECK(descriptor != NULL);
 
   klass->SetClass(GetClassRoot(kJavaLangClass));
-  if (klass->GetDescriptor() != NULL) {
-    DCHECK(klass->GetDescriptor()->Equals(descriptor));
-  } else {
-    klass->SetDescriptor(intern_table_->InternStrong(descriptor));
-    if (klass->GetDescriptor() == NULL) {
-      return;
-    }
-  }
   uint32_t access_flags = dex_class_def.access_flags_;
   // Make sure that none of our runtime-only flags are set.
   CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
@@ -1195,21 +1191,7 @@
   DCHECK(klass->GetPrimitiveType() == Primitive::kPrimNot);
   klass->SetStatus(Class::kStatusIdx);
 
-  klass->SetTypeIdx(dex_class_def.class_idx_);
-  klass->SetSuperClassTypeIdx(dex_class_def.superclass_idx_);
-  klass->SetAnnotationsOffset(dex_class_def.annotations_off_);
-
-  const char* source_file = dex_file.GetSourceFile(dex_class_def);
-  if (source_file != NULL) {
-    String* source_file_string = intern_table_->InternStrong(source_file);
-    if (source_file_string == NULL) {
-      return;
-    }
-    klass->SetSourceFile(source_file_string);
-  }
-
-  // Load class interfaces.
-  LoadInterfaces(dex_file, dex_class_def, klass);
+  klass->SetDexTypeIndex(dex_class_def.class_idx_);
 
   // Load fields fields.
   const byte* class_data = dex_file.GetClassData(dex_class_def);
@@ -1279,88 +1261,59 @@
   DCHECK(!it.HasNext());
 }
 
-void ClassLinker::LoadInterfaces(const DexFile& dex_file,
-                                 const DexFile::ClassDef& dex_class_def,
-                                 SirtRef<Class>& klass) {
-  const DexFile::TypeList* list = dex_file.GetInterfacesList(dex_class_def);
-  if (list != NULL) {
-    klass->SetInterfaces(AllocClassArray(list->Size()));
-    IntArray* interfaces_idx = IntArray::Alloc(list->Size());
-    klass->SetInterfacesTypeIdx(interfaces_idx);
-    for (size_t i = 0; i < list->Size(); ++i) {
-      const DexFile::TypeItem& type_item = list->GetTypeItem(i);
-      interfaces_idx->Set(i, type_item.type_idx_);
-    }
-  }
-}
-
 void ClassLinker::LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
                             SirtRef<Class>& klass, SirtRef<Field>& dst) {
-  const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex());
+  uint32_t field_idx = it.GetMemberIndex();
+  dst->SetDexFieldIndex(field_idx);
   dst->SetDeclaringClass(klass.get());
-  dst->SetName(ResolveString(dex_file, field_id.name_idx_, klass->GetDexCache()));
-  dst->SetTypeIdx(field_id.type_idx_);
   dst->SetAccessFlags(it.GetMemberAccessFlags());
-
-  // In order to access primitive types using GetTypeDuringLinking we need to
-  // ensure they are resolved into the dex cache
-  const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
-  if (descriptor[1] == '\0') {
-    // only the descriptors of primitive types should be 1 character long
-    Class* resolved = ResolveType(dex_file, field_id.type_idx_, klass.get());
-    DCHECK(resolved->IsPrimitive());
-  }
 }
 
 void ClassLinker::LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& it,
                              SirtRef<Class>& klass, SirtRef<Method>& dst) {
-  const DexFile::MethodId& method_id = dex_file.GetMethodId(it.GetMemberIndex());
+  uint32_t method_idx = it.GetMemberIndex();
+  dst->SetDexMethodIndex(method_idx);
+  const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
   dst->SetDeclaringClass(klass.get());
 
-  String* method_name = ResolveString(dex_file, method_id.name_idx_, klass->GetDexCache());
-  if (method_name == NULL) {
-    return;
-  }
-  dst->SetName(method_name);
-  if (method_name->Equals("<init>")) {
+
+  StringPiece method_name(dex_file.GetMethodName(method_id));
+  if (method_name == "<init>") {
     dst->SetClass(GetClassRoot(kJavaLangReflectConstructor));
   }
 
-  int32_t utf16_length;
-  std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, &utf16_length));
-  String* signature_string = intern_table_->InternStrong(utf16_length, signature.c_str());
-  if (signature_string == NULL) {
-    return;
-  }
-  dst->SetSignature(signature_string);
-
-  if (method_name->Equals("finalize") && signature == "()V") {
-    /*
-     * The Enum class declares a "final" finalize() method to prevent subclasses from introducing
-     * a finalizer. We don't want to set the finalizable flag for Enum or its subclasses, so we
-     * exclude it here.
-     *
-     * We also want to avoid setting the flag on Object, where we know that finalize() is empty.
-     */
-    if (klass->GetClassLoader() != NULL ||
-        (!klass->GetDescriptor()->Equals("Ljava/lang/Object;") &&
-            !klass->GetDescriptor()->Equals("Ljava/lang/Enum;"))) {
-      klass->SetFinalizable();
+  if (method_name == "finalize") {
+    // Create the prototype for a signature of "()V"
+    const DexFile::StringId* void_string_id = dex_file.FindStringId("V");
+    if (void_string_id != NULL) {
+      const DexFile::TypeId* void_type_id =
+          dex_file.FindTypeId(dex_file.GetIndexForStringId(*void_string_id));
+      if (void_type_id != NULL) {
+        std::vector<uint16_t> no_args;
+        const DexFile::ProtoId* finalizer_proto =
+            dex_file.FindProtoId(dex_file.GetIndexForTypeId(*void_type_id), no_args);
+        if (finalizer_proto != NULL) {
+          // We have the prototype in the dex file
+          if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged
+            klass->SetFinalizable();
+          } else {
+            StringPiece klass_descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
+            // The Enum class declares a "final" finalize() method to prevent subclasses from
+            // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
+            // subclasses, so we exclude it here.
+            // We also want to avoid setting the flag on Object, where we know that finalize() is
+            // empty.
+            if (klass_descriptor != "Ljava/lang/Object;" &&
+                klass_descriptor != "Ljava/lang/Enum;") {
+              klass->SetFinalizable();
+            }
+          }
+        }
+      }
     }
   }
-
-  dst->SetProtoIdx(method_id.proto_idx_);
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
-  const char* shorty = dex_file.GetShorty(method_id.proto_idx_);
-  String* shorty_string = intern_table_->InternStrong(shorty);
-  dst->SetShorty(shorty_string);
-  if (shorty_string == NULL) {
-    return;
-  }
   dst->SetAccessFlags(it.GetMemberAccessFlags());
-  uint32_t return_type_idx = dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_;
-  DCHECK_LT(return_type_idx, dex_file.NumTypeIds());
-  dst->SetReturnTypeIdx(return_type_idx);
 
   dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
@@ -1370,20 +1323,6 @@
   dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
 
   // TODO: check for finalize method
-
-  const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
-  if (code_item != NULL) {
-    dst->SetNumRegisters(code_item->registers_size_);
-    dst->SetNumIns(code_item->ins_size_);
-    dst->SetNumOuts(code_item->outs_size_);
-  } else {
-    uint16_t num_args = Method::NumArgRegisters(shorty);
-    if ((it.GetMemberAccessFlags() & kAccStatic) == 0) {
-      ++num_args;
-    }
-    dst->SetNumRegisters(num_args);
-    // TODO: native methods
-  }
 }
 
 void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) {
@@ -1474,8 +1413,6 @@
   // TODO: deduce one argument from the other
   CHECK(primitive_class != NULL);
   primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
-  primitive_class->SetDescriptor(intern_table_->InternStrong(descriptor));
-  CHECK(primitive_class->GetDescriptor() != NULL);
   primitive_class->SetPrimitiveType(type);
   primitive_class->SetStatus(Class::kStatusInitialized);
   bool success = InsertClass(descriptor, primitive_class, false);
@@ -1561,14 +1498,6 @@
     new_class->SetComponentType(component_type);
   }
   DCHECK(new_class->GetComponentType() != NULL);
-  if (new_class->GetDescriptor() != NULL) {
-    DCHECK(new_class->GetDescriptor()->Equals(descriptor));
-  } else {
-    new_class->SetDescriptor(intern_table_->InternStrong(descriptor.c_str()));
-    if (new_class->GetDescriptor() == NULL) {
-      return NULL;
-    }
-  }
   Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
   new_class->SetVTable(java_lang_Object->GetVTable());
@@ -1591,9 +1520,7 @@
 
   // Use the single, global copies of "interfaces" and "iftable"
   // (remember not to free them for arrays).
-  CHECK(array_interfaces_ != NULL);
   CHECK(array_iftable_ != NULL);
-  new_class->SetInterfaces(array_interfaces_);
   new_class->SetIfTable(array_iftable_);
 
   // Inherit access flags from the component type.  Arrays can't be
@@ -1677,16 +1604,19 @@
   MutexLock mu(classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
+  ClassHelper kh;
   for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
     Class* klass = it->second;
-    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+    kh.ChangeClass(klass);
+    if (kh.GetDescriptor() == descriptor && klass->GetClassLoader() == class_loader) {
       classes_.erase(it);
       return true;
     }
   }
   for (It it = image_classes_.find(hash), end = image_classes_.end(); it != end; ++it) {
     Class* klass = it->second;
-    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+    kh.ChangeClass(klass);
+    if (kh.GetDescriptor() == descriptor && klass->GetClassLoader() == class_loader) {
       image_classes_.erase(it);
       return true;
     }
@@ -1699,15 +1629,18 @@
   MutexLock mu(classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
+  ClassHelper kh(NULL, this);
   for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
     Class* klass = it->second;
-    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+    kh.ChangeClass(klass);
+    if (descriptor == kh.GetDescriptor() && klass->GetClassLoader() == class_loader) {
       return klass;
     }
   }
   for (It it = image_classes_.find(hash), end = image_classes_.end(); it != end; ++it) {
     Class* klass = it->second;
-    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+    kh.ChangeClass(klass);
+    if (descriptor == kh.GetDescriptor() && klass->GetClassLoader() == class_loader) {
       return klass;
     }
   }
@@ -1720,16 +1653,19 @@
   MutexLock mu(classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
+  ClassHelper kh(NULL, this);
   for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
-    Class* c = it->second;
-    if (c->GetDescriptor()->Equals(descriptor)) {
-      classes.push_back(c);
+    Class* klass = it->second;
+    kh.ChangeClass(klass);
+    if (descriptor == kh.GetDescriptor()) {
+      classes.push_back(klass);
     }
   }
   for (It it = image_classes_.find(hash), end = image_classes_.end(); it != end; ++it) {
-    Class* c = it->second;
-    if (c->GetDescriptor()->Equals(descriptor)) {
-      classes.push_back(c);
+    Class* klass = it->second;
+    kh.ChangeClass(klass);
+    if (descriptor == kh.GetDescriptor()) {
+      classes.push_back(klass);
     }
   }
 }
@@ -1749,48 +1685,56 @@
     Thread* self = Thread::Current();
     CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
     self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Verification of %s failed",
-        PrettyDescriptor(klass->GetDescriptor()).c_str());
+        PrettyDescriptor(klass).c_str());
     CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying);
     klass->SetStatus(Class::kStatusError);
   }
 }
 
 Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interfaces,
-    ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws) {
+                                     ClassLoader* loader, ObjectArray<Method>* methods,
+                                     ObjectArray<ObjectArray<Class> >* throws) {
   SirtRef<Class> klass(AllocClass(GetClassRoot(kJavaLangClass), sizeof(ProxyClass)));
   CHECK(klass.get() != NULL);
   klass->SetObjectSize(sizeof(Proxy));
-  const char* descriptor = DotToDescriptor(name->ToModifiedUtf8().c_str()).c_str();;
-  klass->SetDescriptor(intern_table_->InternStrong(descriptor));
-  klass->SetAccessFlags(kAccPublic | kAccFinal);
+  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
   klass->SetClassLoader(loader);
-  klass->SetStatus(Class::kStatusInitialized);  // no loading or initializing necessary
+  klass->SetName(name);
   Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
+  klass->SetDexCache(proxy_class->GetDexCache());
+  klass->SetDexTypeIndex(-1);
   klass->SetSuperClass(proxy_class);  // The super class is java.lang.reflect.Proxy
-  klass->SetInterfaces(interfaces);  // The interfaces are the array of interfaces specified
+  klass->SetStatus(Class::kStatusInitialized);  // no loading or initializing necessary
 
   // Proxies have 1 direct method, the constructor
   klass->SetDirectMethods(AllocObjectArray<Method>(1));
-  klass->SetDirectMethod(0, CreateProxyConstructor(klass));
+  klass->SetDirectMethod(0, CreateProxyConstructor(klass, proxy_class));
 
   // Create virtual method using specified prototypes
   size_t num_virtual_methods = methods->GetLength();
   klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
   for (size_t i = 0; i < num_virtual_methods; ++i) {
     SirtRef<Method> prototype(methods->Get(i));
-    klass->SetVirtualMethod(i, CreateProxyMethod(klass, prototype, throws->Get(i)));
+    klass->SetVirtualMethod(i, CreateProxyMethod(klass, prototype));
   }
   // Link the virtual methods, creating vtable and iftables
-  if (!LinkMethods(klass)) {
+  if (!LinkMethods(klass, interfaces)) {
     DCHECK(Thread::Current()->IsExceptionPending());
     return NULL;
   }
   return klass.get();
 }
 
-Method* ClassLinker::CreateProxyConstructor(SirtRef<Class>& klass) {
+std::string ClassLinker::GetDescriptorForProxy(const Class* proxy_class) {
+  DCHECK(proxy_class->IsProxyClass());
+  String* name = proxy_class->GetName();
+  DCHECK(name != NULL);
+  return DotToDescriptor(name->ToModifiedUtf8().c_str());
+}
+
+
+Method* ClassLinker::CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class) {
   // Create constructor for Proxy that must initialize h
-  Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
   ObjectArray<Method>* proxy_direct_methods = proxy_class->GetDirectMethods();
   CHECK_EQ(proxy_direct_methods->GetLength(), 15);
   Method* proxy_constructor = proxy_direct_methods->Get(2);
@@ -1802,15 +1746,18 @@
   constructor->SetDeclaringClass(klass.get());
   // Sanity checks
   CHECK(constructor->IsConstructor());
-  CHECK(constructor->GetName()->Equals("<init>"));
-  CHECK(constructor->GetSignature()->Equals("(Ljava/lang/reflect/InvocationHandler;)V"));
+  MethodHelper mh(constructor);
+  CHECK_STREQ(mh.GetName(), "<init>");
+  CHECK(mh.GetSignature() == "(Ljava/lang/reflect/InvocationHandler;)V");
   DCHECK(constructor->IsPublic());
   return constructor;
 }
 
-Method* ClassLinker::CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype,
-                                       ObjectArray<Class>* throws) {
-  // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialise
+Method* ClassLinker::CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype) {
+  // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
+  // prototype method
+  prototype->GetDexCacheResolvedMethods()->Set(prototype->GetDexMethodIndex(), prototype.get());
+  // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
   // as necessary
   Method* method = down_cast<Method*>(prototype->Clone());
 
@@ -1818,7 +1765,6 @@
   // the intersection of throw exceptions as defined in Proxy
   method->SetDeclaringClass(klass.get());
   method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
-  method->SetExceptionTypes(throws);
 
   // At runtime the method looks like a reference and argument saving method, clone the code
   // related parameters from this method.
@@ -1829,12 +1775,21 @@
   method->SetCode(reinterpret_cast<void*>(art_proxy_invoke_handler));
 
   // Basic sanity
-  DCHECK(method->GetName()->Equals(prototype->GetName()));
-  DCHECK(method->GetSignature()->Equals(prototype->GetSignature()));
-  DCHECK(method->GetShorty()->Equals(prototype->GetShorty()));
+  CHECK(!prototype->IsFinal());
+  CHECK(method->IsFinal());
+  CHECK(!method->IsAbstract());
+  MethodHelper mh(method);
+  const char* method_name = mh.GetName();
+  const char* method_shorty = mh.GetShorty();
+  Class* method_return = mh.GetReturnType();
+
+  mh.ChangeMethod(prototype.get());
+
+  CHECK_STREQ(mh.GetName(), method_name);
+  CHECK_STREQ(mh.GetShorty(), method_shorty);
 
   // More complex sanity - via dex cache
-  CHECK_EQ(method->GetReturnType(), prototype->GetReturnType());
+  CHECK_EQ(mh.GetReturnType(), method_return);
 
   return method;
 }
@@ -1928,8 +1883,8 @@
       thread_stats->class_init_time_ns += (t1 - t0);
       klass->SetStatus(Class::kStatusInitialized);
       if (verbose_) {
-        LOG(INFO) << "Initialized class " << klass->GetDescriptor()->ToModifiedUtf8()
-                  << " from " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+        ClassHelper kh(klass);
+        LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
       }
     }
     lock.NotifyAll();
@@ -1959,7 +1914,7 @@
       // The caller wants an exception, but it was thrown in a
       // different thread.  Synthesize one here.
       ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
-                                PrettyDescriptor(klass->GetDescriptor()).c_str());
+                                PrettyDescriptor(klass).c_str());
       return false;
     }
     if (klass->IsInitialized()) {
@@ -1984,7 +1939,9 @@
           !HasSameMethodDescriptorClasses(method, super, klass)) {
         klass->DumpClass(std::cerr, Class::kDumpClassFullDetail);
 
-        ThrowLinkageError("Class %s method %s resolves differently in superclass %s", PrettyDescriptor(klass->GetDescriptor()).c_str(), PrettyMethod(method).c_str(), PrettyDescriptor(super->GetDescriptor()).c_str());
+        ThrowLinkageError("Class %s method %s resolves differently in superclass %s",
+                          PrettyDescriptor(klass).c_str(), PrettyMethod(method).c_str(),
+                          PrettyDescriptor(super).c_str());
         return false;
       }
     }
@@ -1999,7 +1956,10 @@
                                             method->GetDeclaringClass())) {
           klass->DumpClass(std::cerr, Class::kDumpClassFullDetail);
 
-          ThrowLinkageError("Class %s method %s resolves differently in interface %s", PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor()).c_str(), PrettyMethod(method).c_str(), PrettyDescriptor(interface->GetDescriptor()).c_str());
+          ThrowLinkageError("Class %s method %s resolves differently in interface %s",
+                            PrettyDescriptor(method->GetDeclaringClass()).c_str(),
+                            PrettyMethod(method).c_str(),
+                            PrettyDescriptor(interface).c_str());
           return false;
         }
       }
@@ -2015,7 +1975,8 @@
     return true;
   }
   const DexFile& dex_file = FindDexFile(method->GetDeclaringClass()->GetDexCache());
-  const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx());
+  const DexFile::ProtoId& proto_id =
+      dex_file.GetMethodPrototype(dex_file.GetMethodId(method->GetDexMethodIndex()));
   for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) {
     const char* descriptor = it.GetDescriptor();
     if (descriptor == NULL) {
@@ -2121,10 +2082,10 @@
   if (dex_cache == NULL) {
     return;
   }
-  const DexFile& dex_file = FindDexFile(dex_cache);
-  const std::string descriptor(klass->GetDescriptor()->ToModifiedUtf8());
-  const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
+  ClassHelper kh(klass);
+  const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
   CHECK(dex_class_def != NULL);
+  const DexFile& dex_file = kh.GetDexFile();
   EncodedStaticFieldValueIterator it(dex_file, dex_cache, this, *dex_class_def);
 
   if (it.HasNext()) {
@@ -2142,7 +2103,7 @@
   if (!LinkSuperClass(klass)) {
     return false;
   }
-  if (!LinkMethods(klass)) {
+  if (!LinkMethods(klass, NULL)) {
     return false;
   }
   if (!LinkInstanceFields(klass)) {
@@ -2160,30 +2121,38 @@
 
 bool ClassLinker::LoadSuperAndInterfaces(SirtRef<Class>& klass, const DexFile& dex_file) {
   CHECK_EQ(Class::kStatusIdx, klass->GetStatus());
-  if (klass->GetSuperClassTypeIdx() != DexFile::kDexNoIndex16) {
-    Class* super_class = ResolveType(dex_file, klass->GetSuperClassTypeIdx(), klass.get());
+  StringPiece descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
+  const DexFile::ClassDef* class_def = dex_file.FindClassDef(descriptor);
+  if (class_def == NULL) {
+    return false;
+  }
+  uint16_t super_class_idx = class_def->superclass_idx_;
+  if (super_class_idx != DexFile::kDexNoIndex16) {
+    Class* super_class = ResolveType(dex_file, super_class_idx, klass.get());
     if (super_class == NULL) {
       DCHECK(Thread::Current()->IsExceptionPending());
       return false;
     }
     klass->SetSuperClass(super_class);
   }
-  for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
-    uint32_t idx = klass->GetInterfacesTypeIdx()->Get(i);
-    Class* interface = ResolveType(dex_file, idx, klass.get());
-    klass->SetInterface(i, interface);
-    if (interface == NULL) {
-      DCHECK(Thread::Current()->IsExceptionPending());
-      return false;
-    }
-    // Verify
-    if (!klass->CanAccess(interface)) {
-      // TODO: the RI seemed to ignore this in my testing.
-      Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
-          "Interface %s implemented by class %s is inaccessible",
-          PrettyDescriptor(interface->GetDescriptor()).c_str(),
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
-      return false;
+  const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(*class_def);
+  if (interfaces != NULL) {
+    for (size_t i = 0; i < interfaces->Size(); i++) {
+      uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
+      Class* interface = ResolveType(dex_file, idx, klass.get());
+      if (interface == NULL) {
+        DCHECK(Thread::Current()->IsExceptionPending());
+        return false;
+      }
+      // Verify
+      if (!klass->CanAccess(interface)) {
+        // TODO: the RI seemed to ignore this in my testing.
+        Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+            "Interface %s implemented by class %s is inaccessible",
+            PrettyDescriptor(interface).c_str(),
+            PrettyDescriptor(klass.get()).c_str());
+        return false;
+      }
     }
   }
   // Mark the class as loaded.
@@ -2194,7 +2163,7 @@
 bool ClassLinker::LinkSuperClass(SirtRef<Class>& klass) {
   CHECK(!klass->IsPrimitive());
   Class* super = klass->GetSuperClass();
-  if (klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
+  if (klass.get() == GetClassRoot(kJavaLangObject)) {
     if (super != NULL) {
       Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassFormatError;",
           "java.lang.Object must not have a superclass");
@@ -2203,24 +2172,23 @@
     return true;
   }
   if (super == NULL) {
-    ThrowLinkageError("No superclass defined for class %s",
-        PrettyDescriptor(klass->GetDescriptor()).c_str());
+    ThrowLinkageError("No superclass defined for class %s", PrettyDescriptor(klass.get()).c_str());
     return false;
   }
   // Verify
   if (super->IsFinal() || super->IsInterface()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
         "Superclass %s of %s is %s",
-        PrettyDescriptor(super->GetDescriptor()).c_str(),
-        PrettyDescriptor(klass->GetDescriptor()).c_str(),
+        PrettyDescriptor(super).c_str(),
+        PrettyDescriptor(klass.get()).c_str(),
         super->IsFinal() ? "declared final" : "an interface");
     return false;
   }
   if (!klass->CanAccess(super)) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
         "Superclass %s is inaccessible by %s",
-        PrettyDescriptor(super->GetDescriptor()).c_str(),
-        PrettyDescriptor(klass->GetDescriptor()).c_str());
+        PrettyDescriptor(super).c_str(),
+        PrettyDescriptor(klass.get()).c_str());
     return false;
   }
 
@@ -2237,7 +2205,7 @@
   // Disallow custom direct subclasses of java.lang.ref.Reference.
   if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
     ThrowLinkageError("Class %s attempts to subclass java.lang.ref.Reference, which is not allowed",
-        PrettyDescriptor(klass->GetDescriptor()).c_str());
+        PrettyDescriptor(klass.get()).c_str());
     return false;
   }
 
@@ -2252,7 +2220,7 @@
 }
 
 // Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(SirtRef<Class>& klass) {
+bool ClassLinker::LinkMethods(SirtRef<Class>& klass, ObjectArray<Class>* interfaces) {
   if (klass->IsInterface()) {
     // No vtable.
     size_t count = klass->NumVirtualMethods();
@@ -2264,10 +2232,10 @@
       klass->GetVirtualMethodDuringLinking(i)->SetMethodIndex(i);
     }
     // Link interface method tables
-    return LinkInterfaceMethods(klass);
+    return LinkInterfaceMethods(klass, interfaces);
   } else {
     // Link virtual and interface method tables
-    return LinkVirtualMethods(klass) && LinkInterfaceMethods(klass);
+    return LinkVirtualMethods(klass) && LinkInterfaceMethods(klass, interfaces);
   }
   return true;
 }
@@ -2280,18 +2248,22 @@
     // TODO: do not assign to the vtable field until it is fully constructed.
     ObjectArray<Method>* vtable = klass->GetSuperClass()->GetVTable()->CopyOf(max_count);
     // See if any of our virtual methods override the superclass.
+    MethodHelper local_mh(NULL, this);
+    MethodHelper super_mh(NULL, this);
     for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
       Method* local_method = klass->GetVirtualMethodDuringLinking(i);
+      local_mh.ChangeMethod(local_method);
       size_t j = 0;
       for (; j < actual_count; ++j) {
         Method* super_method = vtable->Get(j);
-        if (local_method->HasSameNameAndSignature(super_method)) {
+        super_mh.ChangeMethod(super_method);
+        if (local_mh.HasSameNameAndSignature(&super_mh)) {
           // Verify
           if (super_method->IsFinal()) {
+            MethodHelper mh(local_method);
             ThrowLinkageError("Method %s.%s overrides final method in class %s",
-                PrettyDescriptor(klass->GetDescriptor()).c_str(),
-                local_method->GetName()->ToModifiedUtf8().c_str(),
-                PrettyDescriptor(super_method->GetDeclaringClass()->GetDescriptor()).c_str());
+                PrettyDescriptor(klass.get()).c_str(),
+                mh.GetName(), mh.GetDeclaringClassDescriptor());
             return false;
           }
           vtable->Set(j, local_method);
@@ -2317,7 +2289,7 @@
     }
     klass->SetVTable(vtable);
   } else {
-    CHECK(klass->GetDescriptor()->Equals("Ljava/lang/Object;"));
+    CHECK(klass.get() == GetClassRoot(kJavaLangObject));
     uint32_t num_virtual_methods = klass->NumVirtualMethods();
     if (!IsUint(16, num_virtual_methods)) {
       ThrowClassFormatError("Too many methods: %d", num_virtual_methods);
@@ -2334,7 +2306,7 @@
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(SirtRef<Class>& klass) {
+bool ClassLinker::LinkInterfaceMethods(SirtRef<Class>& klass, ObjectArray<Class>* interfaces) {
   size_t super_ifcount;
   if (klass->HasSuperClass()) {
     super_ifcount = klass->GetSuperClass()->GetIfTableCount();
@@ -2342,9 +2314,12 @@
     super_ifcount = 0;
   }
   size_t ifcount = super_ifcount;
-  ifcount += klass->NumInterfaces();
-  for (size_t i = 0; i < klass->NumInterfaces(); i++) {
-    ifcount += klass->GetInterface(i)->GetIfTableCount();
+  ClassHelper kh(klass.get(), this);
+  uint32_t num_interfaces = interfaces == NULL ? kh.NumInterfaces() : interfaces->GetLength();
+  ifcount += num_interfaces;
+  for (size_t i = 0; i < num_interfaces; i++) {
+    Class* interface = interfaces == NULL ? kh.GetInterface(i) : interfaces->Get(i);
+    ifcount += interface->GetIfTableCount();
   }
   if (ifcount == 0) {
     // TODO: enable these asserts with klass status validation
@@ -2361,14 +2336,15 @@
   }
   // Flatten the interface inheritance hierarchy.
   size_t idx = super_ifcount;
-  for (size_t i = 0; i < klass->NumInterfaces(); i++) {
-    Class* interface = klass->GetInterface(i);
+  for (size_t i = 0; i < num_interfaces; i++) {
+    Class* interface = interfaces == NULL ? kh.GetInterface(i) : interfaces->Get(i);
     DCHECK(interface != NULL);
     if (!interface->IsInterface()) {
+      ClassHelper ih(interface);
       Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
           "Class %s implements non-interface class %s",
-          PrettyDescriptor(klass->GetDescriptor()).c_str(),
-          PrettyDescriptor(interface->GetDescriptor()).c_str());
+          PrettyDescriptor(klass.get()).c_str(),
+          PrettyDescriptor(ih.GetDescriptor()).c_str());
       return false;
     }
     // Add this interface.
@@ -2386,6 +2362,8 @@
     return true;
   }
   std::vector<Method*> miranda_list;
+  MethodHelper vtable_mh(NULL, this);
+  MethodHelper interface_mh(NULL, this);
   for (size_t i = 0; i < ifcount; ++i) {
     InterfaceEntry* interface_entry = iftable->Get(i);
     Class* interface = interface_entry->GetInterface();
@@ -2394,6 +2372,7 @@
     ObjectArray<Method>* vtable = klass->GetVTableDuringLinking();
     for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
       Method* interface_method = interface->GetVirtualMethod(j);
+      interface_mh.ChangeMethod(interface_method);
       int32_t k;
       // For each method listed in the interface's method list, find the
       // matching method in our class's method list.  We want to favor the
@@ -2405,7 +2384,8 @@
       // matter which direction we go.  We walk it backward anyway.)
       for (k = vtable->GetLength() - 1; k >= 0; --k) {
         Method* vtable_method = vtable->Get(k);
-        if (interface_method->HasSameNameAndSignature(vtable_method)) {
+        vtable_mh.ChangeMethod(vtable_method);
+        if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
           if (!vtable_method->IsPublic()) {
             Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
                 "Implementation not public: %s", PrettyMethod(vtable_method).c_str());
@@ -2418,7 +2398,9 @@
       if (k < 0) {
         SirtRef<Method> miranda_method(NULL);
         for (size_t mir = 0; mir < miranda_list.size(); mir++) {
-          if (miranda_list[mir]->HasSameNameAndSignature(interface_method)) {
+          Method* mir_method = miranda_list[mir];
+          vtable_mh.ChangeMethod(mir_method);
+          if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
             miranda_method.reset(miranda_list[mir]);
             break;
           }
@@ -2481,10 +2463,13 @@
 }
 
 struct LinkFieldsComparator {
+  LinkFieldsComparator(FieldHelper* fh) : fh_(fh) {}
   bool operator()(const Field* field1, const Field* field2) {
     // First come reference fields, then 64-bit, and finally 32-bit
-    Primitive::Type type1 = field1->GetPrimitiveType();
-    Primitive::Type type2 = field2->GetPrimitiveType();
+    fh_->ChangeField(field1);
+    Primitive::Type type1 = fh_->GetTypeAsPrimitiveType();
+    fh_->ChangeField(field2);
+    Primitive::Type type2 = fh_->GetTypeAsPrimitiveType();
     bool isPrimitive1 = type1 != Primitive::kPrimNot;
     bool isPrimitive2 = type2 != Primitive::kPrimNot;
     bool is64bit1 = isPrimitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble);
@@ -2496,10 +2481,14 @@
     }
 
     // same basic group? then sort by string.
-    std::string name1 = field1->GetName()->ToModifiedUtf8();
-    std::string name2 = field2->GetName()->ToModifiedUtf8();
+    fh_->ChangeField(field1);
+    StringPiece name1(fh_->GetName());
+    fh_->ChangeField(field2);
+    StringPiece name2(fh_->GetName());
     return name1 < name2;
   }
+
+  FieldHelper* fh_;
 };
 
 bool ClassLinker::LinkFields(SirtRef<Class>& klass, bool is_static) {
@@ -2532,16 +2521,18 @@
   for (size_t i = 0; i < num_fields; i++) {
     grouped_and_sorted_fields.push_back(fields->Get(i));
   }
+  FieldHelper fh(NULL, this);
   std::sort(grouped_and_sorted_fields.begin(),
             grouped_and_sorted_fields.end(),
-            LinkFieldsComparator());
+            LinkFieldsComparator(&fh));
 
   // References should be at the front.
   size_t current_field = 0;
   size_t num_reference_fields = 0;
   for (; current_field < num_fields; current_field++) {
     Field* field = grouped_and_sorted_fields.front();
-    Primitive::Type type = field->GetPrimitiveType();
+    fh.ChangeField(field);
+    Primitive::Type type = fh.GetTypeAsPrimitiveType();
     bool isPrimitive = type != Primitive::kPrimNot;
     if (isPrimitive) {
       break; // past last reference, move on to the next phase
@@ -2559,7 +2550,8 @@
   if (current_field != num_fields && !IsAligned<8>(field_offset.Uint32Value())) {
     for (size_t i = 0; i < grouped_and_sorted_fields.size(); i++) {
       Field* field = grouped_and_sorted_fields[i];
-      Primitive::Type type = field->GetPrimitiveType();
+      fh.ChangeField(field);
+      Primitive::Type type = fh.GetTypeAsPrimitiveType();
       CHECK(type != Primitive::kPrimNot);  // should only be working on primitive types
       if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) {
         continue;
@@ -2580,7 +2572,8 @@
   while (!grouped_and_sorted_fields.empty()) {
     Field* field = grouped_and_sorted_fields.front();
     grouped_and_sorted_fields.pop_front();
-    Primitive::Type type = field->GetPrimitiveType();
+    fh.ChangeField(field);
+    Primitive::Type type = fh.GetTypeAsPrimitiveType();
     CHECK(type != Primitive::kPrimNot);  // should only be working on primitive types
     fields->Set(current_field, field);
     field->SetOffset(field_offset);
@@ -2592,11 +2585,14 @@
   }
 
   // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
-  if (!is_static && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
+  std::string descriptor(ClassHelper(klass.get(), this).GetDescriptor());
+  if (!is_static &&  descriptor == "Ljava/lang/ref/Reference;") {
     // We know there are no non-reference fields in the Reference classes, and we know
     // that 'referent' is alphabetically last, so this is easy...
     CHECK_EQ(num_reference_fields, num_fields);
-    CHECK(fields->Get(num_fields - 1)->GetName()->Equals("referent"));
+    fh.ChangeField(fields->Get(num_fields - 1));
+    StringPiece name(fh.GetName());
+    CHECK(name == "referent");
     --num_reference_fields;
   }
 
@@ -2612,9 +2608,10 @@
                 << " field=" << PrettyField(field)
                 << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
     }
-    Primitive::Type type = field->GetPrimitiveType();
+    fh.ChangeField(field);
+    Primitive::Type type = fh.GetTypeAsPrimitiveType();
     bool is_primitive = type != Primitive::kPrimNot;
-    if (klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;") && field->GetName()->Equals("referent")) {
+    if (descriptor == "Ljava/lang/ref/Reference;" && StringPiece(fh.GetName()) == "referent") {
       is_primitive = true; // We lied above, so we have to expect a lie here.
     }
     if (is_primitive) {
@@ -2711,7 +2708,7 @@
 }
 
 Class* ClassLinker::ResolveType(const DexFile& dex_file,
-                                uint32_t type_idx,
+                                uint16_t type_idx,
                                 DexCache* dex_cache,
                                 const ClassLoader* class_loader) {
   Class* resolved = dex_cache->GetResolvedType(type_idx);
@@ -2842,4 +2839,15 @@
   return dex_lock_.GetOwner();
 }
 
+void ClassLinker::SetClassRoot(ClassRoot class_root, Class* klass) {
+  DCHECK(!init_done_);
+
+  DCHECK(klass != NULL);
+  DCHECK(klass->GetClassLoader() == NULL);
+
+  DCHECK(class_roots_ != NULL);
+  DCHECK(class_roots_->Get(class_root) == NULL);
+  class_roots_->Set(class_root, klass);
+}
+
 }  // namespace art
diff --git a/src/class_linker.h b/src/class_linker.h
index e408dbb..089040f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -18,6 +18,7 @@
 #define ART_SRC_CLASS_LINKER_H_
 
 #include <map>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -105,7 +106,7 @@
   // result in the DexCache. The referrer is used to identity the
   // target DexCache and ClassLoader to use for resolution.
   Class* ResolveType(const DexFile& dex_file,
-                     uint32_t type_idx,
+                     uint16_t type_idx,
                      const Class* referrer) {
     return ResolveType(dex_file,
                        type_idx,
@@ -116,7 +117,7 @@
   // Resolve a Type with the given index from the DexFile, storing the
   // result in the DexCache. The referrer is used to identify the
   // target DexCache and ClassLoader to use for resolution.
-  Class* ResolveType(uint32_t type_idx, const Method* referrer) {
+  Class* ResolveType(uint16_t type_idx, const Method* referrer) {
     Class* resolved_type = referrer->GetDexCacheResolvedTypes()->Get(type_idx);
     if (UNLIKELY(resolved_type == NULL)) {
       Class* declaring_class = referrer->GetDeclaringClass();
@@ -128,7 +129,7 @@
     return resolved_type;
   }
 
-  Class* ResolveType(uint32_t type_idx, const Field* referrer) {
+  Class* ResolveType(uint16_t type_idx, const Field* referrer) {
     Class* declaring_class = referrer->GetDeclaringClass();
     DexCache* dex_cache = declaring_class->GetDexCache();
     Class* resolved_type = dex_cache->GetResolvedType(type_idx);
@@ -145,7 +146,7 @@
   // type, since it may be referenced from but not contained within
   // the given DexFile.
   Class* ResolveType(const DexFile& dex_file,
-                     uint32_t type_idx,
+                     uint16_t type_idx,
                      DexCache* dex_cache,
                      const ClassLoader* class_loader);
 
@@ -244,7 +245,8 @@
   void VerifyClass(Class* klass);
 
   Class* CreateProxyClass(String* name, ObjectArray<Class>* interfaces, ClassLoader* loader,
-      ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws);
+                          ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws);
+  std::string GetDescriptorForProxy(const Class* proxy_class);
 
   pid_t GetClassesLockOwner(); // For SignalCatcher.
   pid_t GetDexLockOwner(); // For SignalCatcher.
@@ -303,10 +305,6 @@
                  SirtRef<Class>& klass,
                  const ClassLoader* class_loader);
 
-  void LoadInterfaces(const DexFile& dex_file,
-                      const DexFile::ClassDef& dex_class_def,
-                      SirtRef<Class>& klass);
-
   void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it, SirtRef<Class>& klass,
                  SirtRef<Field>& dst);
 
@@ -340,11 +338,11 @@
 
   bool LoadSuperAndInterfaces(SirtRef<Class>& klass, const DexFile& dex_file);
 
-  bool LinkMethods(SirtRef<Class>& klass);
+  bool LinkMethods(SirtRef<Class>& klass, ObjectArray<Class>* interfaces);
 
   bool LinkVirtualMethods(SirtRef<Class>& klass);
 
-  bool LinkInterfaceMethods(SirtRef<Class>& klass);
+  bool LinkInterfaceMethods(SirtRef<Class>& klass, ObjectArray<Class>* interfaces);
 
   bool LinkStaticFields(SirtRef<Class>& klass);
   bool LinkInstanceFields(SirtRef<Class>& klass);
@@ -364,8 +362,8 @@
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
 
-  Method* CreateProxyConstructor(SirtRef<Class>& klass);
-  Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype, ObjectArray<Class>* throws);
+  Method* CreateProxyConstructor(SirtRef<Class>& klass, Class* proxy_class);
+  Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype);
 
   const bool verbose_;
 
@@ -433,18 +431,7 @@
     return klass;
   }
 
-  void SetClassRoot(ClassRoot class_root, Class* klass) {
-    DCHECK(!init_done_);
-
-    DCHECK(klass != NULL);
-    DCHECK(klass->GetClassLoader() == NULL);
-    DCHECK(klass->GetDescriptor() != NULL);
-    DCHECK(klass->GetDescriptor()->Equals(GetClassRootDescriptor(class_root)));
-
-    DCHECK(class_roots_ != NULL);
-    DCHECK(class_roots_->Get(class_root) == NULL);
-    class_roots_->Set(class_root, klass);
-  }
+  void SetClassRoot(ClassRoot class_root, Class* klass);
 
   ObjectArray<Class>* GetClassRoots() {
     DCHECK(class_roots_ != NULL);
@@ -459,7 +446,6 @@
     return descriptor;
   }
 
-  ObjectArray<Class>* array_interfaces_;
   ObjectArray<InterfaceEntry>* array_iftable_;
 
   bool init_done_;
@@ -469,6 +455,7 @@
   friend class CommonTest;
   friend class ImageWriter;  // for GetClassRoots
   friend class ObjectTest;
+  FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
   FRIEND_TEST(DexCacheTest, Open);
   FRIEND_TEST(ExceptionTest, FindExceptionHandler);
   FRIEND_TEST(ObjectTest, AllocObjectArray);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index b51822f..c335ba9 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -30,11 +30,12 @@
   }
 
   void AssertPrimitiveClass(const std::string& descriptor, const Class* primitive) {
+    ClassHelper primitive_ch(primitive);
     ASSERT_TRUE(primitive != NULL);
     ASSERT_TRUE(primitive->GetClass() != NULL);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
     EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
-    ASSERT_TRUE(primitive->GetDescriptor()->Equals(descriptor));
+    ASSERT_STREQ(descriptor.c_str(), primitive_ch.GetDescriptor().c_str());
     EXPECT_TRUE(primitive->GetSuperClass() == NULL);
     EXPECT_FALSE(primitive->HasSuperClass());
     EXPECT_TRUE(primitive->GetClassLoader() == NULL);
@@ -56,7 +57,7 @@
     EXPECT_EQ(0U, primitive->NumVirtualMethods());
     EXPECT_EQ(0U, primitive->NumInstanceFields());
     EXPECT_EQ(0U, primitive->NumStaticFields());
-    EXPECT_EQ(0U, primitive->NumInterfaces());
+    EXPECT_EQ(0U, primitive_ch.NumInterfaces());
     EXPECT_TRUE(primitive->GetVTable() == NULL);
     EXPECT_EQ(0, primitive->GetIfTableCount());
     EXPECT_TRUE(primitive->GetIfTable() == NULL);
@@ -66,22 +67,25 @@
                         const std::string& component_type,
                         const ClassLoader* class_loader) {
     Class* array = class_linker_->FindClass(array_descriptor, class_loader);
-    EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
+    ClassHelper array_component_ch(array->GetComponentType());
+    EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor().c_str());
     EXPECT_EQ(class_loader, array->GetClassLoader());
     AssertArrayClass(array_descriptor, array);
   }
 
   void AssertArrayClass(const std::string& array_descriptor, Class* array) {
+    ClassHelper kh(array);
     ASSERT_TRUE(array != NULL);
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
     EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
-    ASSERT_TRUE(array->GetDescriptor()->Equals(array_descriptor));
+    ASSERT_STREQ(array_descriptor.c_str(), kh.GetDescriptor().c_str());
     EXPECT_TRUE(array->GetSuperClass() != NULL);
     EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
     EXPECT_TRUE(array->HasSuperClass());
     ASSERT_TRUE(array->GetComponentType() != NULL);
-    ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
+    kh.ChangeClass(array->GetComponentType());
+    ASSERT_TRUE(kh.GetDescriptor() != NULL);
     EXPECT_EQ(Class::kStatusInitialized, array->GetStatus());
     EXPECT_FALSE(array->IsErroneous());
     EXPECT_TRUE(array->IsLoaded());
@@ -99,20 +103,25 @@
     EXPECT_EQ(0U, array->NumVirtualMethods());
     EXPECT_EQ(0U, array->NumInstanceFields());
     EXPECT_EQ(0U, array->NumStaticFields());
-    EXPECT_EQ(2U, array->NumInterfaces());
+    kh.ChangeClass(array);
+    EXPECT_EQ(2U, kh.NumInterfaces());
     EXPECT_TRUE(array->GetVTable() != NULL);
     EXPECT_EQ(2, array->GetIfTableCount());
     ObjectArray<InterfaceEntry>* iftable = array->GetIfTable();
     ASSERT_TRUE(iftable != NULL);
-    EXPECT_TRUE(iftable->Get(0)->GetInterface()->GetDescriptor()->Equals("Ljava/lang/Cloneable;"));
-    EXPECT_TRUE(iftable->Get(1)->GetInterface()->GetDescriptor()->Equals("Ljava/io/Serializable;"));
+    kh.ChangeClass(kh.GetInterface(0));
+    EXPECT_STREQ(kh.GetDescriptor().c_str(), "Ljava/lang/Cloneable;");
+    kh.ChangeClass(array);
+    kh.ChangeClass(kh.GetInterface(1));
+    EXPECT_STREQ(kh.GetDescriptor().c_str(), "Ljava/io/Serializable;");
   }
 
   void AssertMethod(Class* klass, Method* method) {
+    MethodHelper mh(method);
     EXPECT_TRUE(method != NULL);
     EXPECT_TRUE(method->GetClass() != NULL);
-    EXPECT_TRUE(method->GetName() != NULL);
-    EXPECT_TRUE(method->GetSignature() != NULL);
+    EXPECT_TRUE(mh.GetName() != NULL);
+    EXPECT_TRUE(mh.GetSignature() != NULL);
 
     EXPECT_TRUE(method->GetDexCacheStrings() != NULL);
     EXPECT_TRUE(method->GetDexCacheResolvedTypes() != NULL);
@@ -135,17 +144,18 @@
   }
 
   void AssertField(Class* klass, Field* field) {
+    FieldHelper fh(field);
     EXPECT_TRUE(field != NULL);
     EXPECT_TRUE(field->GetClass() != NULL);
     EXPECT_EQ(klass, field->GetDeclaringClass());
-    EXPECT_TRUE(field->GetName() != NULL);
-    EXPECT_TRUE(field->GetType() != NULL);
+    EXPECT_TRUE(fh.GetName() != NULL);
+    EXPECT_TRUE(fh.GetType() != NULL);
   }
 
   void AssertClass(const std::string& descriptor, Class* klass) {
-    EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
-    SirtRef<String> Object_descriptor(String::AllocFromModifiedUtf8("Ljava/lang/Object;"));
-    if (klass->GetDescriptor()->Equals(Object_descriptor.get())) {
+    ClassHelper kh(klass);
+    EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor().c_str());
+    if (descriptor == "Ljava/lang/Object;") {
       EXPECT_FALSE(klass->HasSuperClass());
     } else {
       EXPECT_TRUE(klass->HasSuperClass());
@@ -160,11 +170,12 @@
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == NULL);
     EXPECT_TRUE(klass->IsInSamePackage(klass));
-    EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
+    EXPECT_TRUE(Class::IsInSamePackage(kh.GetDescriptor(), kh.GetDescriptor()));
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
       if (klass->NumDirectMethods() == 1) {
-        EXPECT_TRUE(klass->GetDirectMethod(0)->IsClassInitializer());
+        MethodHelper mh(klass->GetDirectMethod(0));
+        EXPECT_TRUE(mh.IsClassInitializer());
         EXPECT_TRUE(klass->GetDirectMethod(0)->IsDirect());
       } else {
         EXPECT_EQ(0U, klass->NumDirectMethods());
@@ -233,18 +244,21 @@
 
     // Confirm that all instances fields are packed together at the start
     EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
+    FieldHelper fh;
     for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
       Field* field = klass->GetInstanceField(i);
-      ASSERT_TRUE(!field->IsPrimitiveType());
-      Class* field_type = field->GetType();
+      fh.ChangeField(field);
+      ASSERT_TRUE(!fh.IsPrimitiveType());
+      Class* field_type = fh.GetType();
       ASSERT_TRUE(field_type != NULL);
       ASSERT_TRUE(!field_type->IsPrimitive());
     }
     for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
       Field* field = klass->GetInstanceField(i);
-      Class* field_type = field->GetType();
+      fh.ChangeField(field);
+      Class* field_type = fh.GetType();
       ASSERT_TRUE(field_type != NULL);
-      if (!field->IsPrimitiveType() || !field_type->IsPrimitive()) {
+      if (!fh.IsPrimitiveType() || !field_type->IsPrimitive()) {
         // While Reference.referent is not primitive, the ClassLinker
         // treats it as such so that the garbage collector won't scan it.
         EXPECT_EQ(PrettyField(field), "java.lang.Object java.lang.ref.Reference.referent");
@@ -265,7 +279,7 @@
     ASSERT_TRUE(descriptor != NULL);
     Class* klass = class_linker_->FindSystemClass(descriptor);
     ASSERT_TRUE(klass != NULL);
-    EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
+    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor().c_str());
     EXPECT_EQ(class_loader, klass->GetClassLoader());
     if (klass->IsPrimitive()) {
       AssertPrimitiveClass(descriptor, klass);
@@ -339,9 +353,12 @@
       error = true;
     }
 
+    FieldHelper fh;
     for (size_t i = 0; i < offsets.size(); i++) {
       Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
-      if (!field->GetName()->Equals(offsets[i].java_name)) {
+      fh.ChangeField(field);
+      StringPiece field_name(fh.GetName());
+      if (field_name != offsets[i].java_name) {
         error = true;
       }
     }
@@ -349,12 +366,14 @@
       for (size_t i = 0; i < offsets.size(); i++) {
         CheckOffset& offset = offsets[i];
         Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
-        if (!field->GetName()->Equals(offsets[i].java_name)) {
+        fh.ChangeField(field);
+        StringPiece field_name(fh.GetName());
+        if (field_name != offsets[i].java_name) {
           LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
         }
         LG << "Java field order:"
            << " i=" << i << " class=" << class_descriptor
-           << " Java=" << field->GetName()->ToModifiedUtf8()
+           << " Java=" << field_name
            << " CheckOffsets=" << offset.java_name;
       }
     }
@@ -401,17 +420,12 @@
 struct FieldOffsets : public CheckOffsets<Field> {
   FieldOffsets() : CheckOffsets<Field>(false, "Ljava/lang/reflect/Field;") {
     // alphabetical references
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_),               "declaringClass"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_type_),                  "genericType"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, name_),                          "name"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_),                          "type"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_), "declaringClass"));
 
     // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_types_are_initialized_), "genericTypesAreInitialized"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, access_flags_),                  "shadow$_access_flags_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, offset_),                        "shadow$_offset_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_idx_),                      "shadow$_type_idx_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, slot_),                          "slot"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, access_flags_),    "accessFlags"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, field_dex_idx_),   "fieldDexIndex"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, offset_),          "offset"));
   };
 };
 
@@ -419,43 +433,27 @@
   MethodOffsets() : CheckOffsets<Method>(false, "Ljava/lang/reflect/Method;") {
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_),                      "declaringClass"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_exception_types_),                 "exceptionTypes"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_formal_type_parameters_),          "formalTypeParameters"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_exception_types_),         "genericExceptionTypes"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_parameter_types_),         "genericParameterTypes"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_return_type_),             "genericReturnType"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, name_),                                 "name"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_parameter_types_),                 "parameterTypes"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_),                     "returnType"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "shadow$_dex_cache_code_and_direct_methods_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "shadow$_dex_cache_initialized_static_storage_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_),            "shadow$_dex_cache_resolved_fields_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "shadow$_dex_cache_resolved_methods_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "shadow$_dex_cache_resolved_types_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "shadow$_dex_cache_strings_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_),                               "shadow$_gc_map_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_),                               "shadow$_shorty_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_),                            "shadow$_signature_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "dexCacheCodeAndDirectMethods"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "dexCacheInitializedStaticStorage"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_),            "dexCacheResolvedFields"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "dexCacheResolvedMethods"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "dexCacheResolvedTypes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "dexCacheStrings"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, gc_map_),                               "gcMap"));
 
     // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_),   "genericTypesAreInitialized"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_),                         "shadow$_access_flags_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_),                                 "shadow$_code_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_item_offset_),                     "shadow$_code_item_offset_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_),                      "shadow$_core_spill_mask_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_),                        "shadow$_fp_spill_mask_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_),                  "shadow$_frame_size_in_bytes_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),                          "shadow$_invoke_stub_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_idx_),                 "shadow$_java_return_type_idx_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),                        "shadow$_mapping_table_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_),                         "shadow$_method_index_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_),                        "shadow$_native_method_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_ins_),                              "shadow$_num_ins_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_outs_),                             "shadow$_num_outs_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_),                        "shadow$_num_registers_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_),                            "shadow$_proto_idx_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_),                           "shadow$_vmap_table_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_),                            "slot"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_),        "accessFlags"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_),                "code"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_item_offset_),    "codeItemOffset"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_),     "coreSpillMask"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_),       "fpSpillMask"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_), "frameSizeInBytes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),         "invokeStub"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),       "mappingTable"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_dex_index_),    "methodDexIndex"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_),        "methodIndex"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_),       "nativeMethod"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_),          "vmapTable"));
   };
 };
 
@@ -472,23 +470,19 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_),                          "name"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_),                  "shadow$_class_loader_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_),                "shadow$_component_type_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, descriptor_),                    "shadow$_descriptor_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_),                     "shadow$_dex_cache_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_),                "shadow$_direct_methods_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_),                       "shadow$_ifields_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_),                       "shadow$_iftable_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_),                    "shadow$_interfaces_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_type_idx_),           "shadow$_interfaces_type_idx_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_),                       "shadow$_sfields_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, source_file_),                   "shadow$_source_file_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_),                   "shadow$_super_class_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_),            "shadow$_verify_error_class_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_),               "shadow$_virtual_methods_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_),                        "shadow$_vtable_"));
 
     // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_type_idx_),                  "dexTypeIndex"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_),                  "shadow$_access_flags_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, annotations_offset_),            "shadow$_annotations_offset_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_),                    "shadow$_class_size_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_),              "shadow$_clinit_thread_id_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
@@ -498,8 +492,6 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_),    "shadow$_reference_instance_offsets_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_),      "shadow$_reference_static_offsets_"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_),                        "shadow$_status_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_type_idx_),          "shadow$_super_class_type_idx_"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, type_idx_),                      "shadow$_type_idx_"));
   };
 };
 
@@ -595,16 +587,6 @@
   FieldClassOffsets() : CheckOffsets<FieldClass>(true, "Ljava/lang/reflect/Field;") {
     // alphabetical references
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, ORDER_BY_NAME_AND_DECLARING_CLASS_), "ORDER_BY_NAME_AND_DECLARING_CLASS"));
-
-    // alphabetical 32-bit
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_BOOLEAN_), "TYPE_BOOLEAN"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_BYTE_),    "TYPE_BYTE"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_CHAR_),    "TYPE_CHAR"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_DOUBLE_),  "TYPE_DOUBLE"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_FLOAT_),   "TYPE_FLOAT"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_INTEGER_), "TYPE_INTEGER"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_LONG_),    "TYPE_LONG"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_SHORT_),   "TYPE_SHORT"));
   };
 };
 
@@ -683,11 +665,12 @@
 
 TEST_F(ClassLinkerTest, FindClass) {
   Class* JavaLangObject = class_linker_->FindSystemClass("Ljava/lang/Object;");
+  ClassHelper kh(JavaLangObject);
   ASSERT_TRUE(JavaLangObject != NULL);
   ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
   ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
-  ASSERT_TRUE(JavaLangObject->GetDescriptor()->Equals("Ljava/lang/Object;"));
+  ASSERT_STREQ(kh.GetDescriptor().c_str(), "Ljava/lang/Object;");
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
   EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
@@ -708,20 +691,23 @@
   EXPECT_EQ(2U, JavaLangObject->NumDirectMethods());
   EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods());
   EXPECT_EQ(2U, JavaLangObject->NumInstanceFields());
-  EXPECT_TRUE(JavaLangObject->GetInstanceField(0)->GetName()->Equals("shadow$_klass_"));
-  EXPECT_TRUE(JavaLangObject->GetInstanceField(1)->GetName()->Equals("shadow$_monitor_"));
+  FieldHelper fh(JavaLangObject->GetInstanceField(0));
+  EXPECT_STREQ(fh.GetName(), "shadow$_klass_");
+  fh.ChangeField(JavaLangObject->GetInstanceField(1));
+  EXPECT_STREQ(fh.GetName(), "shadow$_monitor_");
 
   EXPECT_EQ(0U, JavaLangObject->NumStaticFields());
-  EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
+  EXPECT_EQ(0U, kh.NumInterfaces());
 
   SirtRef<ClassLoader> class_loader(LoadDex("MyClass"));
   AssertNonExistentClass("LMyClass;");
   Class* MyClass = class_linker_->FindClass("LMyClass;", class_loader.get());
+  kh.ChangeClass(MyClass);
   ASSERT_TRUE(MyClass != NULL);
   ASSERT_TRUE(MyClass->GetClass() != NULL);
   ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
   EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
-  ASSERT_TRUE(MyClass->GetDescriptor()->Equals("LMyClass;"));
+  ASSERT_STREQ(kh.GetDescriptor().c_str(), "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
   EXPECT_EQ(class_loader.get(), MyClass->GetClassLoader());
@@ -743,7 +729,7 @@
   EXPECT_EQ(0U, MyClass->NumVirtualMethods());
   EXPECT_EQ(0U, MyClass->NumInstanceFields());
   EXPECT_EQ(0U, MyClass->NumStaticFields());
-  EXPECT_EQ(0U, MyClass->NumInterfaces());
+  EXPECT_EQ(0U, kh.NumInterfaces());
 
   EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
 
@@ -785,21 +771,29 @@
   // This lets UnboxPrimitive avoid searching for the field by name at runtime.
   Class* c;
   c = class_linker_->FindClass("Ljava/lang/Boolean;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  FieldHelper fh(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Byte;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Character;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Double;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Float;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Integer;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Long;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
   c = class_linker_->FindClass("Ljava/lang/Short;", NULL);
-  EXPECT_EQ("value", c->GetIFields()->Get(0)->GetName()->ToModifiedUtf8());
+  fh.ChangeField(c->GetIFields()->Get(0));
+  EXPECT_STREQ("value", fh.GetName());
 }
 
 TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
@@ -826,48 +820,57 @@
   EXPECT_EQ(9U, statics->NumStaticFields());
 
   Field* s0 = statics->FindStaticField("s0", "Z");
-  EXPECT_TRUE(s0->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Field;"));
-  EXPECT_TRUE(s0->GetPrimitiveType() == Primitive::kPrimBoolean);
+  FieldHelper fh(s0);
+  EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor().c_str(), "Ljava/lang/reflect/Field;");
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
   EXPECT_EQ(true, s0->GetBoolean(NULL));
   s0->SetBoolean(NULL, false);
 
   Field* s1 = statics->FindStaticField("s1", "B");
-  EXPECT_TRUE(s1->GetPrimitiveType() == Primitive::kPrimByte);
+  fh.ChangeField(s1);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte);
   EXPECT_EQ(5, s1->GetByte(NULL));
   s1->SetByte(NULL, 6);
 
   Field* s2 = statics->FindStaticField("s2", "C");
-  EXPECT_TRUE(s2->GetPrimitiveType() == Primitive::kPrimChar);
+  fh.ChangeField(s2);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar);
   EXPECT_EQ('a', s2->GetChar(NULL));
   s2->SetChar(NULL, 'b');
 
   Field* s3 = statics->FindStaticField("s3", "S");
-  EXPECT_TRUE(s3->GetPrimitiveType() == Primitive::kPrimShort);
+  fh.ChangeField(s3);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort);
   EXPECT_EQ(-536, s3->GetShort(NULL));
   s3->SetShort(NULL, -535);
 
   Field* s4 = statics->FindStaticField("s4", "I");
-  EXPECT_TRUE(s4->GetPrimitiveType() == Primitive::kPrimInt);
+  fh.ChangeField(s4);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt);
   EXPECT_EQ(2000000000, s4->GetInt(NULL));
   s4->SetInt(NULL, 2000000001);
 
   Field* s5 = statics->FindStaticField("s5", "J");
-  EXPECT_TRUE(s5->GetPrimitiveType() == Primitive::kPrimLong);
+  fh.ChangeField(s5);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong);
   EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(NULL));
   s5->SetLong(NULL, 0x34567890abcdef12LL);
 
   Field* s6 = statics->FindStaticField("s6", "F");
-  EXPECT_TRUE(s6->GetPrimitiveType() == Primitive::kPrimFloat);
+  fh.ChangeField(s6);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
   EXPECT_EQ(0.5, s6->GetFloat(NULL));
   s6->SetFloat(NULL, 0.75);
 
   Field* s7 = statics->FindStaticField("s7", "D");
-  EXPECT_TRUE(s7->GetPrimitiveType() == Primitive::kPrimDouble);
+  fh.ChangeField(s7);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble);
   EXPECT_EQ(16777217, s7->GetDouble(NULL));
   s7->SetDouble(NULL, 16777219);
 
   Field* s8 = statics->FindStaticField("s8", "Ljava/lang/String;");
-  EXPECT_TRUE(s8->GetPrimitiveType() == Primitive::kPrimNot);
+  fh.ChangeField(s8);
+  EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot);
   EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("android"));
   s8->SetObject(NULL, String::AllocFromModifiedUtf8("robot"));
 
@@ -986,4 +989,15 @@
   EXPECT_TRUE(c->IsFinalizable());
 }
 
+TEST_F(ClassLinkerTest, ClassRootDescriptors) {
+  ClassHelper kh;
+  for (int i = 0; i < ClassLinker::kClassRootsMax; i++) {
+    Class* klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i));
+    kh.ChangeClass(klass);
+    EXPECT_TRUE(kh.GetDescriptor() != NULL);
+    EXPECT_STREQ(kh.GetDescriptor().c_str(),
+                 class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i;
+  }
+}
+
 }  // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index d140d40..48a9c39 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -17,6 +17,7 @@
 #include "gtest/gtest.h"
 #include "heap.h"
 #include "oat_file.h"
+#include "object_utils.h"
 #include "os.h"
 #include "runtime.h"
 #include "stl_util.h"
@@ -118,9 +119,9 @@
   void MakeExecutable(Method* method) {
     CHECK(method != NULL);
 
+    MethodHelper mh(method);
     const CompiledInvokeStub* compiled_invoke_stub =
-        compiler_->FindInvokeStub(method->IsStatic(),
-                                  method->GetShorty()->ToModifiedUtf8().c_str());
+        compiler_->FindInvokeStub(mh.IsStatic(), mh.GetShorty());
     CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method);
     const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
     MakeExecutable(invoke_stub);
diff --git a/src/compiler.cc b/src/compiler.cc
index fba767d..e437062 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -11,6 +11,7 @@
 #include "jni_compiler.h"
 #include "jni_internal.h"
 #include "oat_file.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "stl_util.h"
 
@@ -145,6 +146,18 @@
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
+bool Compiler::CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache,
+                                                uint32_t type_idx) const {
+  if (!IsImage()) {
+    return false;
+  }
+  Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
+  if (resolved_class == NULL) {
+    return false;
+  }
+  return IsImageClass(ClassHelper(resolved_class).GetDescriptor());
+}
+
 // Return true if the class should be skipped during compilation. We
 // never skip classes in the boot class loader. However, if we have a
 // non-boot class loader and we can resolve the class in the boot
diff --git a/src/compiler.h b/src/compiler.h
index 5203ffb..4e1be1d 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -70,16 +70,7 @@
   const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
 
   // Callbacks from OAT/ART compiler to see what runtime checks must be generated
-  bool CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache, uint32_t type_idx) const {
-    if (!IsImage()) {
-      return false;
-    }
-    Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
-    if (resolved_class == NULL) {
-      return false;
-    }
-    return IsImageClass(resolved_class->GetDescriptor()->ToModifiedUtf8());
-  }
+  bool CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache, uint32_t type_idx) const;
   bool CanAssumeStringIsPresentInDexCache(const DexCache* dex_cache, uint32_t string_idx) const {
     // TODO: Add support for loading strings referenced by image_classes_
     // See also Compiler::ResolveDexFile
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index 5d2c4e6..60a5f38 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -263,17 +263,19 @@
 
 
 /* Return sp-relative offset in bytes using Method* */
-extern int oatVRegOffsetFromMethod(Method* method, int reg)
+extern int oatVRegOffset(const art::DexFile::CodeItem* code_item,
+                         uint32_t core_spills, uint32_t fp_spills,
+                         size_t frame_size, int reg)
 {
-    int numIns = method->NumIns();
-    int numRegs = method->NumRegisters() - numIns;
-    int numOuts = method->NumOuts();
-    int numSpills = __builtin_popcount(method->GetCoreSpillMask()) +
-                    __builtin_popcount(method->GetFpSpillMask());
+    int numIns = code_item->ins_size_;
+    int numRegs = code_item->registers_size_ - numIns;
+    int numOuts = code_item->outs_size_;
+    int numSpills = __builtin_popcount(core_spills) +
+                    __builtin_popcount(fp_spills);
     int numPadding = (STACK_ALIGN_WORDS -
         (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
     int regsOffset = (numOuts + numPadding + 1) * 4;
-    int insOffset = method->GetFrameSizeInBytes() + 4;
+    int insOffset = frame_size + 4;
     return (reg < numRegs) ? regsOffset + (reg << 2) :
            insOffset + ((reg - numRegs) << 2);
 }
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 15fd1ba..2c3ee0d 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "object_utils.h"
+
 #define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
     (1 << kDebugDisplayMissingTargets))
 
@@ -192,7 +194,7 @@
     // See if we can find a dex reference for the storage class.
     // we may not if the dex file never references the super class,
     // but usually it will.
-    std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
+    std::string descriptor(art::FieldHelper(field).GetDeclaringClassDescriptor());
     const art::DexFile::StringId* string_id =
         cUnit->dex_file->FindStringId(descriptor);
     if (string_id == NULL) {
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index d4c1ed2..f8be881 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -18,6 +18,7 @@
 #include "debugger.h"
 #include "jni_internal.h"
 #include "object.h"
+#include "object_utils.h"
 #include "thread.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -65,7 +66,7 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   std::string descriptor;
   descriptor += "[";
-  descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+  descriptor += ClassHelper(element_class).GetDescriptor();
   Class* array_class = class_linker->FindClass(descriptor, NULL);
   Array* result = Array::Alloc(array_class, length);
   if (result == NULL) {
diff --git a/src/debugger.cc b/src/debugger.cc
index 3a6c154..b2f9629 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -23,6 +23,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "context.h"
+#include "object_utils.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "stack_indirect_reference_table.h"
@@ -87,15 +88,11 @@
 };
 
 struct AllocRecordStackTraceElement {
-  const Method* method;
+  Method* method;
   uintptr_t raw_pc;
 
   int32_t LineNumber() const {
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    Class* c = method->GetDeclaringClass();
-    DexCache* dex_cache = c->GetDexCache();
-    const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-    return dex_file.GetLineNumFromPC(method, method->ToDexPC(raw_pc));
+    return MethodHelper(method).GetLineNumFromNativePC(raw_pc);
   }
 };
 
@@ -452,7 +449,7 @@
 
 std::string Dbg::GetClassDescriptor(JDWP::RefTypeId classId) {
   Class* c = gRegistry->Get<Class*>(classId);
-  return c->GetDescriptor()->ToModifiedUtf8();
+  return ClassHelper(c).GetDescriptor();
 }
 
 JDWP::ObjectId Dbg::GetClassObject(JDWP::RefTypeId id) {
@@ -527,7 +524,7 @@
   }
 
   if (pDescriptor != NULL) {
-    *pDescriptor = c->GetDescriptor()->ToModifiedUtf8();
+    *pDescriptor = ClassHelper(c).GetDescriptor();
   }
 }
 
@@ -560,19 +557,14 @@
 std::string Dbg::GetSignature(JDWP::RefTypeId refTypeId) {
   Class* c = gRegistry->Get<Class*>(refTypeId);
   CHECK(c != NULL);
-  return c->GetDescriptor()->ToModifiedUtf8();
+  return ClassHelper(c).GetDescriptor();
 }
 
 bool Dbg::GetSourceFile(JDWP::RefTypeId refTypeId, std::string& result) {
   Class* c = gRegistry->Get<Class*>(refTypeId);
   CHECK(c != NULL);
-
-  String* source_file = c->GetSourceFile();
-  if (source_file == NULL) {
-    return false;
-  }
-  result = source_file->ToModifiedUtf8();
-  return true;
+  result = ClassHelper(c).GetSourceFile();
+  return result == NULL;
 }
 
 uint8_t Dbg::GetObjectTag(JDWP::ObjectId objectId) {
@@ -619,7 +611,7 @@
 uint8_t Dbg::GetArrayElementTag(JDWP::ObjectId arrayId) {
   Object* o = gRegistry->Get<Object*>(arrayId);
   Array* a = o->AsArray();
-  std::string descriptor(a->GetClass()->GetDescriptor()->ToModifiedUtf8());
+  std::string descriptor(ClassHelper(a->GetClass()).GetDescriptor());
   JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1);
   if (!IsPrimitiveTag(tag)) {
     tag = TagFromClass(a->GetClass()->GetComponentType());
@@ -635,8 +627,7 @@
     LOG(WARNING) << __FUNCTION__ << " access out of bounds: offset=" << offset << "; count=" << count;
     return false;
   }
-
-  std::string descriptor(a->GetClass()->GetDescriptor()->ToModifiedUtf8());
+  std::string descriptor(ClassHelper(a->GetClass()).GetDescriptor());
   JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1);
 
   if (IsPrimitiveTag(tag)) {
@@ -676,8 +667,7 @@
     LOG(WARNING) << __FUNCTION__ << " access out of bounds: offset=" << offset << "; count=" << count;
     return false;
   }
-
-  std::string descriptor(a->GetClass()->GetDescriptor()->ToModifiedUtf8());
+  std::string descriptor(ClassHelper(a->GetClass()).GetDescriptor());
   JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1);
 
   if (IsPrimitiveTag(tag)) {
@@ -763,7 +753,8 @@
 }
 
 std::string Dbg::GetMethodName(JDWP::RefTypeId refTypeId, JDWP::MethodId methodId) {
-  return FromMethodId(methodId)->GetName()->ToModifiedUtf8();
+  Method* m = FromMethodId(methodId);
+  return MethodHelper(m).GetName();
 }
 
 /*
@@ -808,8 +799,8 @@
   if (slot == kEclipseWorkaroundSlot) {
     return 0;
   } else if (slot == 0) {
-    Method* m = f.GetMethod();
-    return m->NumRegisters() - m->NumIns();
+    const DexFile::CodeItem* code_item = MethodHelper(f.GetMethod()).GetCodeItem();
+    return code_item->registers_size_ - code_item->ins_size_;
   }
   return slot;
 }
@@ -825,10 +816,10 @@
 
   for (size_t i = 0; i < instance_field_count + static_field_count; ++i) {
     Field* f = (i < instance_field_count) ? c->GetInstanceField(i) : c->GetStaticField(i - instance_field_count);
-
+    FieldHelper fh(f);
     expandBufAddFieldId(pReply, ToFieldId(f));
-    expandBufAddUtf8String(pReply, f->GetName()->ToModifiedUtf8().c_str());
-    expandBufAddUtf8String(pReply, f->GetTypeDescriptor());
+    expandBufAddUtf8String(pReply, fh.GetName());
+    expandBufAddUtf8String(pReply, fh.GetTypeDescriptor());
     if (with_generic) {
       static const char genericSignature[1] = "";
       expandBufAddUtf8String(pReply, genericSignature);
@@ -848,10 +839,10 @@
 
   for (size_t i = 0; i < direct_method_count + virtual_method_count; ++i) {
     Method* m = (i < direct_method_count) ? c->GetDirectMethod(i) : c->GetVirtualMethod(i - direct_method_count);
-
+    MethodHelper mh(m);
     expandBufAddMethodId(pReply, ToMethodId(m));
-    expandBufAddUtf8String(pReply, m->GetName()->ToModifiedUtf8().c_str());
-    expandBufAddUtf8String(pReply, m->GetSignature()->ToModifiedUtf8().c_str());
+    expandBufAddUtf8String(pReply, mh.GetName());
+    expandBufAddUtf8String(pReply, mh.GetSignature().c_str());
     if (with_generic) {
       static const char genericSignature[1] = "";
       expandBufAddUtf8String(pReply, genericSignature);
@@ -863,10 +854,11 @@
 void Dbg::OutputDeclaredInterfaces(JDWP::RefTypeId refTypeId, JDWP::ExpandBuf* pReply) {
   Class* c = gRegistry->Get<Class*>(refTypeId);
   CHECK(c != NULL);
-  size_t interface_count = c->NumInterfaces();
+  ClassHelper kh(c);
+  size_t interface_count = kh.NumInterfaces();
   expandBufAdd4BE(pReply, interface_count);
   for (size_t i = 0; i < interface_count; ++i) {
-    expandBufAddRefTypeId(pReply, gRegistry->Add(c->GetInterface(i)));
+    expandBufAddRefTypeId(pReply, gRegistry->Add(kh.GetInterface(i)));
   }
 }
 
@@ -885,17 +877,15 @@
   };
 
   Method* m = FromMethodId(methodId);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile& dex_file = class_linker->FindDexFile(m->GetDeclaringClass()->GetDexCache());
-  const DexFile::CodeItem* code_item = dex_file.GetCodeItem(m->GetCodeItemOffset());
-
+  MethodHelper mh(m);
   uint64_t start, end;
   if (m->IsNative()) {
     start = -1;
     end = -1;
   } else {
     start = 0;
-    end = code_item->insns_size_in_code_units_; // TODO: what are the units supposed to be? *2?
+    // TODO: what are the units supposed to be? *2?
+    end = mh.GetCodeItem()->insns_size_in_code_units_;
   }
 
   expandBufAdd8BE(pReply, start);
@@ -909,7 +899,8 @@
   context.numItems = 0;
   context.pReply = pReply;
 
-  dex_file.DecodeDebugInfo(code_item, m, DebugCallbackContext::Callback, NULL, &context);
+  mh.GetDexFile().DecodeDebugInfo(mh.GetCodeItem(), m->IsStatic(), m->GetDexMethodIndex(),
+                                  DebugCallbackContext::Callback, NULL, &context);
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
 }
@@ -941,13 +932,12 @@
   };
 
   Method* m = FromMethodId(methodId);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile& dex_file = class_linker->FindDexFile(m->GetDeclaringClass()->GetDexCache());
-  const DexFile::CodeItem* code_item = dex_file.GetCodeItem(m->GetCodeItemOffset());
+  MethodHelper mh(m);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
 
   // arg_count considers doubles and longs to take 2 units.
   // variable_count considers everything to take 1 unit.
-  std::string shorty(m->GetShorty()->ToModifiedUtf8());
+  std::string shorty(mh.GetShorty());
   expandBufAdd4BE(pReply, m->NumArgRegisters(shorty));
 
   // We don't know the total number of variables yet, so leave a blank and update it later.
@@ -959,24 +949,25 @@
   context.variable_count = 0;
   context.with_generic = with_generic;
 
-  dex_file.DecodeDebugInfo(code_item, m, NULL, DebugCallbackContext::Callback, &context);
+  mh.GetDexFile().DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(), NULL,
+                                  DebugCallbackContext::Callback, &context);
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
 }
 
 JDWP::JdwpTag Dbg::GetFieldBasicTag(JDWP::FieldId fieldId) {
-  return BasicTagFromDescriptor(FromFieldId(fieldId)->GetTypeDescriptor());
+  return BasicTagFromDescriptor(FieldHelper(FromFieldId(fieldId)).GetTypeDescriptor());
 }
 
 JDWP::JdwpTag Dbg::GetStaticFieldBasicTag(JDWP::FieldId fieldId) {
-  return BasicTagFromDescriptor(FromFieldId(fieldId)->GetTypeDescriptor());
+  return BasicTagFromDescriptor(FieldHelper(FromFieldId(fieldId)).GetTypeDescriptor());
 }
 
 void Dbg::GetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
   Object* o = gRegistry->Get<Object*>(objectId);
   Field* f = FromFieldId(fieldId);
 
-  JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor());
+  JDWP::JdwpTag tag = BasicTagFromDescriptor(FieldHelper(f).GetTypeDescriptor());
 
   if (IsPrimitiveTag(tag)) {
     expandBufAdd1(pReply, tag);
@@ -1002,7 +993,7 @@
   Object* o = gRegistry->Get<Object*>(objectId);
   Field* f = FromFieldId(fieldId);
 
-  JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor());
+  JDWP::JdwpTag tag = BasicTagFromDescriptor(FieldHelper(f).GetTypeDescriptor());
 
   if (IsPrimitiveTag(tag)) {
     if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) {
@@ -2120,11 +2111,11 @@
   StringTable() {
   }
 
-  void Add(const String* s) {
+  void Add(const char* s) {
     table_.insert(s);
   }
 
-  size_t IndexOf(const String* s) {
+  size_t IndexOf(const char* s) {
     return std::distance(table_.begin(), table_.find(s));
   }
 
@@ -2133,15 +2124,18 @@
   }
 
   void WriteTo(std::vector<uint8_t>& bytes) {
-    typedef std::set<const String*>::const_iterator It; // TODO: C++0x auto
+    typedef std::set<const char*>::const_iterator It; // TODO: C++0x auto
     for (It it = table_.begin(); it != table_.end(); ++it) {
-      const String* s = *it;
-      JDWP::AppendUtf16BE(bytes, s->GetCharArray()->GetData(), s->GetLength());
+      const char* s = *it;
+      size_t s_len = CountModifiedUtf8Chars(s);
+      UniquePtr<uint16_t> s_utf16(new uint16_t[s_len]);
+      ConvertModifiedUtf8ToUtf16(s_utf16.get(), s);
+      JDWP::AppendUtf16BE(bytes, s_utf16.get(), s_len);
     }
   }
 
  private:
-  std::set<const String*> table_;
+  std::set<const char*> table_;
   DISALLOW_COPY_AND_ASSIGN(StringTable);
 };
 
@@ -2206,14 +2200,16 @@
   while (count--) {
     AllocRecord* record = &recent_allocation_records_[idx];
 
-    class_names.Add(record->type->GetDescriptor());
+    class_names.Add(ClassHelper(record->type).GetDescriptor().c_str());
 
+    MethodHelper mh;
     for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
-      const Method* m = record->stack[i].method;
+      Method* m = record->stack[i].method;
+      mh.ChangeMethod(m);
       if (m != NULL) {
-        class_names.Add(m->GetDeclaringClass()->GetDescriptor());
-        method_names.Add(m->GetName());
-        filenames.Add(m->GetDeclaringClass()->GetSourceFile());
+        class_names.Add(mh.GetDeclaringClassDescriptor());
+        method_names.Add(mh.GetName());
+        filenames.Add(mh.GetDeclaringClassSourceFile());
       }
     }
 
@@ -2251,6 +2247,7 @@
 
   count = gAllocRecordCount;
   idx = headIndex();
+  ClassHelper kh;
   while (count--) {
     // For each entry:
     // (4b) total allocation size
@@ -2261,19 +2258,21 @@
     size_t stack_depth = record->GetDepth();
     JDWP::Append4BE(bytes, record->byte_count);
     JDWP::Append2BE(bytes, record->thin_lock_id);
-    JDWP::Append2BE(bytes, class_names.IndexOf(record->type->GetDescriptor()));
+    kh.ChangeClass(record->type);
+    JDWP::Append2BE(bytes, class_names.IndexOf(kh.GetDescriptor().c_str()));
     JDWP::Append1BE(bytes, stack_depth);
 
+    MethodHelper mh;
     for (size_t stack_frame = 0; stack_frame < stack_depth; ++stack_frame) {
       // For each stack frame:
       // (2b) method's class name
       // (2b) method name
       // (2b) method source file
       // (2b) line number, clipped to 32767; -2 if native; -1 if no source
-      const Method* m = record->stack[stack_frame].method;
-      JDWP::Append2BE(bytes, class_names.IndexOf(m->GetDeclaringClass()->GetDescriptor()));
-      JDWP::Append2BE(bytes, method_names.IndexOf(m->GetName()));
-      JDWP::Append2BE(bytes, filenames.IndexOf(m->GetDeclaringClass()->GetSourceFile()));
+      mh.ChangeMethod(record->stack[stack_frame].method);
+      JDWP::Append2BE(bytes, class_names.IndexOf(mh.GetDeclaringClassDescriptor()));
+      JDWP::Append2BE(bytes, method_names.IndexOf(mh.GetName()));
+      JDWP::Append2BE(bytes, filenames.IndexOf(mh.GetDeclaringClassSourceFile()));
       JDWP::Append2BE(bytes, record->stack[stack_frame].LineNumber());
     }
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 0e4c224..1261bb9 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -15,6 +15,7 @@
 #include "file.h"
 #include "image_writer.h"
 #include "oat_writer.h"
+#include "object_utils.h"
 #include "os.h"
 #include "runtime.h"
 #include "stringpiece.h"
@@ -242,7 +243,7 @@
     if (klass->IsArrayClass() || klass->IsPrimitive()) {
       return true;
     }
-    image_classes->insert(klass->GetDescriptor()->ToModifiedUtf8());
+    image_classes->insert(ClassHelper(klass).GetDescriptor());
     return true;
   }
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 5185ba8..01bb6d5 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -571,7 +571,7 @@
 }
 
 const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
-                                             const std::vector<uint16_t>& signature_type_ids) const {
+                                         const std::vector<uint16_t>& signature_type_idxs) const {
   uint32_t lo = 0;
   uint32_t hi = NumProtoIds() - 1;
   while (hi >= lo) {
@@ -581,15 +581,15 @@
     if (compare == 0) {
       DexFileParameterIterator it(*this, proto);
       size_t i = 0;
-      while (it.HasNext() && i < signature_type_ids.size() && compare == 0) {
-        compare = signature_type_ids[i] - it.GetTypeId();
+      while (it.HasNext() && i < signature_type_idxs.size() && compare == 0) {
+        compare = signature_type_idxs[i] - it.GetTypeIdx();
         it.Next();
         i++;
       }
       if (compare == 0) {
         if (it.HasNext()) {
           compare = -1;
-        } else if (i < signature_type_ids.size()) {
+        } else if (i < signature_type_idxs.size()) {
           compare = 1;
         }
       }
@@ -704,7 +704,8 @@
 
   // A method with no line number info should return -1
   LineNumFromPcContext context(rel_pc, -1);
-  DecodeDebugInfo(code_item, method, LineNumForPcCb, NULL, &context);
+  DecodeDebugInfo(code_item, method->IsStatic(), method->GetDexMethodIndex(), LineNumForPcCb,
+                  NULL, &context);
   return context.line_num_;
 }
 
@@ -733,7 +734,7 @@
   return -1;
 }
 
-void DexFile::DecodeDebugInfo0(const CodeItem* code_item, const Method* method,
+void DexFile::DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx,
                                DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
                                void* cnxt, const byte* stream, LocalInfo* local_in_reg) const {
   uint32_t line = DecodeUnsignedLeb128(&stream);
@@ -742,13 +743,11 @@
   uint32_t address = 0;
   bool need_locals = (local_cb != NULL);
 
-  if (!method->IsStatic()) {
+  if (!is_static) {
     if (need_locals) {
-      std::string descriptor = method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
-      const ClassDef* class_def = FindClassDef(descriptor);
-      CHECK(class_def != NULL) << descriptor;
+      const char* descriptor = GetMethodDeclaringClassDescriptor(GetMethodId(method_idx));
       local_in_reg[arg_reg].name_ = "this";
-      local_in_reg[arg_reg].descriptor_ = GetClassDescriptor(*class_def);
+      local_in_reg[arg_reg].descriptor_ = descriptor;
       local_in_reg[arg_reg].signature_ = NULL;
       local_in_reg[arg_reg].start_address_ = 0;
       local_in_reg[arg_reg].is_live_ = true;
@@ -756,7 +755,7 @@
     arg_reg++;
   }
 
-  DexFileParameterIterator it(*this, GetProtoId(method->GetProtoIdx()));
+  DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
   for (uint32_t i = 0; i < parameters_size && it.HasNext(); ++i, it.Next()) {
     if (arg_reg >= code_item->registers_size_) {
       LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
@@ -897,14 +896,14 @@
   }
 }
 
-void DexFile::DecodeDebugInfo(const CodeItem* code_item, const art::Method* method,
+void DexFile::DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
                                  DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
                                  void* cnxt) const {
   const byte* stream = GetDebugInfoStream(code_item);
   LocalInfo local_in_reg[code_item->registers_size_];
 
   if (stream != NULL) {
-    DecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg);
+    DecodeDebugInfo0(code_item, is_static, method_idx, posCb, local_cb, cnxt, stream, local_in_reg);
   }
   for (int reg = 0; reg < code_item->registers_size_; reg++) {
     InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_in_code_units_, local_in_reg, local_cb);
diff --git a/src/dex_file.h b/src/dex_file.h
index a7026d6..7f0f975 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -376,7 +376,9 @@
   const char* GetMethodShorty(const MethodId& method_id) const {
     return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
   }
-
+  const char* GetMethodShorty(const MethodId& method_id, int32_t* length) const {
+    return StringDataAndLengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length);
+  }
   // Returns the number of class definitions in the .dex file.
   size_t NumClassDefs() const {
     CHECK(header_ != NULL);
@@ -425,11 +427,11 @@
   }
 
   //
-  const CodeItem* GetCodeItem(const uint32_t code_off_) const {
-    if (code_off_ == 0) {
+  const CodeItem* GetCodeItem(const uint32_t code_off) const {
+    if (code_off == 0) {
       return NULL;  // native or abstract method
     } else {
-      const byte* addr = base_ + code_off_;
+      const byte* addr = base_ + code_off;
       return reinterpret_cast<const CodeItem*>(addr);
     }
   }
@@ -458,7 +460,7 @@
 
   // Looks up a proto id for a given return type and signature type list
   const ProtoId* FindProtoId(uint16_t return_type_id,
-                             const std::vector<uint16_t>& signature_type_ids_) const;
+                             const std::vector<uint16_t>& signature_type_idxs_) const;
 
   // Given a signature place the type ids into the given vector, returns true on success
   bool CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs,
@@ -592,7 +594,7 @@
   // This is used by runtime; therefore use art::Method not art::DexFile::Method.
   int32_t GetLineNumFromPC(const Method* method, uint32_t rel_pc) const;
 
-  void DecodeDebugInfo(const CodeItem* code_item, const Method* method,
+  void DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
                        DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
                        void* cnxt) const;
 
@@ -657,14 +659,12 @@
   // Returns true if the header magic is of the expected value.
   bool IsMagicValid();
 
-  void DecodeDebugInfo0(const CodeItem* code_item, const Method* method,
+  void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx,
       DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
       void* cnxt, const byte* stream, LocalInfo* local_in_reg) const;
 
 
-  // The index of descriptors to class definition indexes.
-  // TODO: given type_ids are sorted by string_id index, and string_ids are alphabetically, class
-  //   lookup can be done with a binary search. Is the index necessary?
+  // The index of descriptors to class definition indexes (as opposed to type id indexes)
   typedef std::map<const StringPiece, uint32_t> Index;
   Index index_;
 
@@ -721,11 +721,11 @@
   }
   bool HasNext() const { return pos_ < size_; }
   void Next() { ++pos_; }
-  uint16_t GetTypeId() {
+  uint16_t GetTypeIdx() {
     return type_list_->GetTypeItem(pos_).type_idx_;
   }
   const char* GetDescriptor() {
-    return dex_file_.StringByTypeIdx(GetTypeId());
+    return dex_file_.StringByTypeIdx(GetTypeIdx());
   }
  private:
   const DexFile& dex_file_;
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index d162aec..768880a 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -13,6 +13,7 @@
 #include "intern_table.h"
 #include "leb128.h"
 #include "logging.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "stringpiece.h"
 
@@ -69,7 +70,7 @@
       if (IsUnresolvedTypes()) {
         result += PrettyDescriptor(GetDescriptor());
       } else {
-        result += PrettyDescriptor(GetClass()->GetDescriptor());
+        result += PrettyDescriptor(GetClass());
       }
     }
   }
@@ -124,7 +125,8 @@
     Class* common_elem = ClassJoin(s_ct, t_ct);
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     const ClassLoader* class_loader = s->GetClassLoader();
-    std::string descriptor = "[" + common_elem->GetDescriptor()->ToModifiedUtf8();
+    std::string descriptor = "[";
+    descriptor += ClassHelper(common_elem).GetDescriptor();
     Class* array_class = class_linker->FindClass(descriptor.c_str(), class_loader);
     DCHECK(array_class != NULL);
     return array_class;
@@ -354,11 +356,15 @@
     return *entry;
   } else {
     DCHECK (type == RegType::kRegTypeReference);
+    ClassHelper kh;
     for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       // check resolved and unresolved references, ignore uninitialized references
-      if (cur_entry->IsReference() && cur_entry->GetClass()->GetDescriptor()->Equals(descriptor)) {
-        return *cur_entry;
+      if (cur_entry->IsReference()) {
+        kh.ChangeClass(cur_entry->GetClass());
+        if (descriptor == kh.GetDescriptor()) {
+          return *cur_entry;
+        }
       } else if (cur_entry->IsUnresolvedReference() &&
                  cur_entry->GetDescriptor()->Equals(descriptor)) {
         return *cur_entry;
@@ -887,7 +893,7 @@
     return true;
   }
   Class* super = klass->GetSuperClass();
-  if (super == NULL && !klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
+  if (super == NULL && ClassHelper(klass).GetDescriptor() != "Ljava/lang/Object;") {
     LOG(ERROR) << "Verifier rejected class " << PrettyClass(klass) << " that has no super class";
     return false;
   }
@@ -1574,7 +1580,8 @@
     cur_arg++;
   }
 
-  const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_->GetProtoIdx());
+  const DexFile::ProtoId& proto_id =
+      dex_file_->GetMethodPrototype(dex_file_->GetMethodId(method_->GetDexMethodIndex()));
   DexFileParameterIterator iterator(*dex_file_, proto_id);
 
   for (; iterator.HasNext(); iterator.Next()) {
@@ -2145,7 +2152,7 @@
           if (!res_class->IsArrayClass() || !component_type->IsPrimitive()  ||
               component_type->IsPrimitiveVoid()) {
             Fail(VERIFY_ERROR_GENERIC) << "invalid fill-array-data on "
-                                       << PrettyDescriptor(res_class->GetDescriptor());
+                                       << PrettyDescriptor(res_class);
           } else {
             const RegType& value_type = reg_types_.FromClass(component_type);
             DCHECK(!value_type.IsUnknown());
@@ -2366,7 +2373,7 @@
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
         } else {
-          descriptor = called_method->GetReturnTypeDescriptor();
+          descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
         }
         const RegType& return_type =
             reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
@@ -2444,7 +2451,7 @@
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
         } else {
-          descriptor = called_method->GetReturnTypeDescriptor();
+          descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
         }
         const RegType& return_type =
             reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
@@ -2465,7 +2472,7 @@
             uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
             descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
           } else {
-            descriptor = called_method->GetReturnTypeDescriptor();
+            descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
           }
           const RegType& return_type =
               reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
@@ -2520,7 +2527,7 @@
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
         } else {
-          descriptor = abs_method->GetReturnTypeDescriptor();
+          descriptor = MethodHelper(abs_method).GetReturnTypeDescriptor();
         }
         const RegType& return_type =
             reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(), descriptor);
@@ -2965,7 +2972,7 @@
   // check at runtime if access is allowed and so pass here.
   if (!result.IsUnresolvedTypes() && !referrer->CanAccess(result.GetClass())) {
     Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
-                                    << PrettyDescriptor(referrer->GetDescriptor()) << "' -> '"
+                                    << PrettyDescriptor(referrer) << "' -> '"
                                     << result << "'";
     return reg_types_.Unknown();
   } else {
@@ -3038,7 +3045,7 @@
       dex_cache->SetResolvedMethod(method_idx, res_method);
     } else {
       Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
-                                   << PrettyDescriptor(klass->GetDescriptor()) << "." << name
+                                   << PrettyDescriptor(klass) << "." << name
                                    << " " << signature;
       return NULL;
     }
@@ -3046,7 +3053,7 @@
   /* Check if access is allowed. */
   if (!referrer->CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
     Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method)
-                                  << " from " << PrettyDescriptor(referrer->GetDescriptor()) << ")";
+                                  << " from " << PrettyDescriptor(referrer) << ")";
     return NULL;
   }
   return res_method;
@@ -3088,11 +3095,11 @@
         Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from " << PrettyMethod(method_)
                                      << " to super " << PrettyMethod(res_method);
       } else {
+        MethodHelper mh(res_method);
         Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from " << PrettyMethod(method_)
-                                     << " to super " << PrettyDescriptor(super->GetDescriptor())
-                                     << "." << res_method->GetName()->ToModifiedUtf8()
-                                     << " " << res_method->GetSignature()->ToModifiedUtf8();
-
+                                     << " to super " << PrettyDescriptor(super)
+                                     << "." << mh.GetName()
+                                     << mh.GetSignature();
       }
       return NULL;
     }
@@ -3108,7 +3115,7 @@
         << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
     return NULL;
   }
-  std::string sig = res_method->GetSignature()->ToModifiedUtf8();
+  std::string sig(MethodHelper(res_method).GetSignature());
   if (sig[0] != '(') {
     Fail(VERIFY_ERROR_GENERIC) << "rejecting call to " << res_method
         << " as descriptor doesn't start with '(': " << sig;
@@ -3194,6 +3201,11 @@
   }
 }
 
+const RegType& DexVerifier::GetMethodReturnType() {
+  return reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(),
+                                   MethodHelper(method_).GetReturnTypeDescriptor());
+}
+
 void DexVerifier::VerifyAGet(const Instruction::DecodedInstruction& dec_insn,
                              const RegType& insn_type, bool is_primitive) {
   const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC_);
@@ -3218,20 +3230,20 @@
         const RegType& component_type = reg_types_.FromClass(component_class);
         if (!array_class->IsArrayClass()) {
           Fail(VERIFY_ERROR_GENERIC) << "not array type "
-              << PrettyDescriptor(array_class->GetDescriptor()) << " with aget";
+              << PrettyDescriptor(array_class) << " with aget";
         } else if (component_class->IsPrimitive() && !is_primitive) {
           Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
-                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << PrettyDescriptor(array_class)
                                      << " source for aget-object";
         } else if (!component_class->IsPrimitive() && is_primitive) {
           Fail(VERIFY_ERROR_GENERIC) << "reference array type "
-                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << PrettyDescriptor(array_class)
                                      << " source for category 1 aget";
         } else if (is_primitive && !insn_type.Equals(component_type) &&
                    !((insn_type.IsInteger() && component_type.IsFloat()) ||
                      (insn_type.IsLong() && component_type.IsDouble()))) {
           Fail(VERIFY_ERROR_GENERIC) << "array type "
-              << PrettyDescriptor(array_class->GetDescriptor())
+              << PrettyDescriptor(array_class)
               << " incompatible with aget of type " << insn_type;
         } else {
           // Use knowledge of the field type which is stronger than the type inferred from the
@@ -3261,20 +3273,20 @@
         const RegType& component_type = reg_types_.FromClass(component_class);
         if (!array_class->IsArrayClass()) {
           Fail(VERIFY_ERROR_GENERIC) << "not array type "
-              << PrettyDescriptor(array_class->GetDescriptor()) << " with aput";
+              << PrettyDescriptor(array_class) << " with aput";
         } else if (component_class->IsPrimitive() && !is_primitive) {
           Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
-                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << PrettyDescriptor(array_class)
                                      << " source for aput-object";
         } else if (!component_class->IsPrimitive() && is_primitive) {
           Fail(VERIFY_ERROR_GENERIC) << "reference array type "
-                                     << PrettyDescriptor(array_class->GetDescriptor())
+                                     << PrettyDescriptor(array_class)
                                      << " source for category 1 aput";
         } else if (is_primitive && !insn_type.Equals(component_type) &&
                    !((insn_type.IsInteger() && component_type.IsFloat()) ||
                      (insn_type.IsLong() && component_type.IsDouble()))) {
           Fail(VERIFY_ERROR_GENERIC) << "array type "
-              << PrettyDescriptor(array_class->GetDescriptor())
+              << PrettyDescriptor(array_class)
               << " incompatible with aput of type " << insn_type;
         } else {
           // The instruction agrees with the type of array, confirm the value to be stored does too
@@ -3367,7 +3379,7 @@
     const char* descriptor;
     const ClassLoader* loader;
     if (field != NULL) {
-      descriptor = field->GetTypeDescriptor();
+      descriptor = FieldHelper(field).GetTypeDescriptor();
       loader = field->GetDeclaringClass()->GetClassLoader();
     } else {
       const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
@@ -3419,7 +3431,7 @@
     const char* descriptor;
     const ClassLoader* loader;
     if (field != NULL) {
-      descriptor = field->GetTypeDescriptor();
+      descriptor = FieldHelper(field).GetTypeDescriptor();
       loader = field->GetDeclaringClass()->GetClassLoader();
     } else {
       const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 182c81a..201cd2b 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -1145,10 +1145,7 @@
    * DalvikJniReturnType, because if it's a reference type we need to do the class lookup.
    * Returned references are assumed to be initialized. Returns kRegTypeUnknown for "void".
    */
-  const RegType& GetMethodReturnType() {
-    return reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(),
-                                     method_->GetReturnTypeDescriptor());
-  }
+  const RegType& GetMethodReturnType();
 
   /*
    * Verify that the target instruction is not "move-exception". It's important that the only way
diff --git a/src/heap.cc b/src/heap.cc
index ac0c366..6b2ea71 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -10,6 +10,7 @@
 #include "image.h"
 #include "mark_sweep.h"
 #include "object.h"
+#include "object_utils.h"
 #include "space.h"
 #include "stl_util.h"
 #include "thread_list.h"
@@ -169,9 +170,9 @@
 Object* Heap::AllocObject(Class* klass, size_t byte_count) {
   {
     ScopedHeapLock lock;
-    DCHECK(klass == NULL || klass->GetDescriptor() == NULL ||
-        (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
-        (klass->IsVariableSize() || klass->GetObjectSize() == byte_count));
+    DCHECK(klass == NULL || (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
+           (klass->IsVariableSize() || klass->GetObjectSize() == byte_count) ||
+           ClassHelper(klass).GetDescriptor().empty());
     DCHECK_GE(byte_count, sizeof(Object));
     Object* obj = AllocateLocked(byte_count);
     if (obj != NULL) {
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index 3c5227f..d2134e0 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -23,13 +23,16 @@
  */
 
 #include "hprof.h"
-#include "heap.h"
+
+#include "class_linker.h"
 #include "debugger.h"
+#include "heap.h"
+#include "logging.h"
 #include "object.h"
+#include "object_utils.h"
 #include "stringprintf.h"
 #include "unordered_map.h"
 #include "unordered_set.h"
-#include "logging.h"
 
 #include <cutils/open_memstream.h>
 #include <sys/uio.h>
@@ -364,6 +367,8 @@
 
       rec->AddU2(0); // empty const pool
 
+      FieldHelper fh;
+
       // Static fields
       if (sFieldCount == 0) {
         rec->AddU2((uint16_t)0);
@@ -375,10 +380,11 @@
 
         for (size_t i = 0; i < sFieldCount; ++i) {
           Field* f = thisClass->GetStaticField(i);
+          fh.ChangeField(f);
 
           size_t size;
-          HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
-          rec->AddId(LookupStringId(f->GetName()));
+          HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), &size);
+          rec->AddId(LookupStringId(fh.GetName()));
           rec->AddU1(t);
           if (size == 1) {
             rec->AddU1(static_cast<uint8_t>(f->Get32(NULL)));
@@ -399,8 +405,9 @@
       rec->AddU2((uint16_t)iFieldCount);
       for (int i = 0; i < iFieldCount; ++i) {
         Field* f = thisClass->GetInstanceField(i);
-        HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
-        rec->AddId(LookupStringId(f->GetName()));
+        fh.ChangeField(f);
+        HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), NULL);
+        rec->AddId(LookupStringId(fh.GetName()));
         rec->AddU1(t);
       }
     } else if (clazz->IsArrayClass()) {
@@ -463,12 +470,14 @@
       // Write the instance data;  fields for this class, followed by super class fields,
       // and so on. Don't write the klass or monitor fields of Object.class.
       const Class* sclass = clazz;
+      FieldHelper fh;
       while (!sclass->IsObjectClass()) {
         int ifieldCount = sclass->NumInstanceFields();
         for (int i = 0; i < ifieldCount; i++) {
           Field* f = sclass->GetInstanceField(i);
+          fh.ChangeField(f);
           size_t size;
-          SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+          SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), &size);
           if (size == 1) {
             rec->AddU1(f->Get32(obj));
           } else if (size == 2) {
@@ -680,7 +689,7 @@
 }
 
 HprofStringId Hprof::LookupClassNameId(Class* clazz) {
-  return LookupStringId(PrettyDescriptor(clazz->GetDescriptor()));
+  return LookupStringId(PrettyDescriptor(clazz));
 }
 
 HprofClassObjectId Hprof::LookupClassId(Class* clazz) {
diff --git a/src/image_writer.cc b/src/image_writer.cc
index adc7b78..34ad955 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -18,6 +18,7 @@
 #include "intern_table.h"
 #include "logging.h"
 #include "object.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "space.h"
 #include "utils.h"
@@ -101,7 +102,7 @@
   if (klass->IsPrimitive()) { 
     return true;
   }
-  const std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+  const std::string descriptor(ClassHelper(klass).GetDescriptor());
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
@@ -160,7 +161,7 @@
 bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
   if (!context->image_writer->IsImageClass(klass)) {
-    context->non_image_classes->insert(klass->GetDescriptor()->ToModifiedUtf8());
+    context->non_image_classes->insert(ClassHelper(klass).GetDescriptor());
   }
   return true;
 }
@@ -178,7 +179,7 @@
     return;
   }
   Class* klass = obj->AsClass();
-  CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor()->ToModifiedUtf8();
+  CHECK(image_writer->IsImageClass(klass)) << PrettyDescriptor(klass);
 }
 
 void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void* arg) {
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index b85969e..92fb6fa 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -18,6 +18,7 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "object.h"
+#include "object_utils.h"
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 
@@ -63,6 +64,19 @@
   return AddLocalReference<jclass>(env, c);
 }
 
+jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) {
+  Class* c = Decode<Class*>(env, javaClass);
+  if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) {
+    return 0;  // primitive, array and proxy classes don't have class definitions
+  }
+  const DexFile::ClassDef* class_def = ClassHelper(c).GetClassDef();
+  if (class_def == NULL) {
+    return 0;  // not found
+  } else {
+    return class_def->annotations_off_;
+  }
+}
+
 template<typename T>
 jobjectArray ToArray(JNIEnv* env, const char* array_class_name, const std::vector<T*>& objects) {
   jclass array_class = env->FindClass(array_class_name);
@@ -81,14 +95,10 @@
   if (m->IsStatic()) {
     return false;
   }
-  if (m->GetName()->CharAt(0) != '<') {
-    return false;
-  }
-  m->InitJavaFields();
-  return true;
+  return m->IsConstructor();
 }
 
-jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
   Class* c = Decode<Class*>(env, javaClass);
 
   std::vector<Method*> constructors;
@@ -106,11 +116,10 @@
   if (public_only && !f->IsPublic()) {
     return false;
   }
-  f->InitJavaFields();
   return true;
 }
 
-jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
   Class* c = Decode<Class*>(env, javaClass);
 
   std::vector<Field*> fields;
@@ -140,14 +149,13 @@
   if (public_only && !m->IsPublic()) {
     return false;
   }
-  if (m->GetName()->CharAt(0) == '<') {
+  if (m->IsConstructor()) {
     return false;
   }
-  m->InitJavaFields();
   return true;
 }
 
-jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass, jclass javaClass, jboolean publicOnly) {
+jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
   Class* c = Decode<Class*>(env, javaClass);
 
   std::vector<Method*> methods;
@@ -188,44 +196,52 @@
   return Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache).GetDexObject(env);
 }
 
-jint Class_getNonInnerClassModifiers(JNIEnv* env, jclass, jclass javaClass) {
+jint Class_getNonInnerClassModifiers(JNIEnv* env, jclass javaClass) {
   Class* c = Decode<Class*>(env, javaClass);
   return c->GetAccessFlags() & kAccJavaFlagsMask;
 }
 
-jobject Class_getClassLoader(JNIEnv* env, jclass, jobject javaClass) {
+jobject Class_getClassLoaderNative(JNIEnv* env, jclass javaClass) {
   Class* c = Decode<Class*>(env, javaClass);
   Object* result = c->GetClassLoader();
   return AddLocalReference<jobject>(env, result);
 }
 
-jclass Class_getComponentType(JNIEnv* env, jobject javaThis) {
-  return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType());
+jclass Class_getComponentType(JNIEnv* env, jclass javaClass) {
+  return AddLocalReference<jclass>(env, Decode<Class*>(env, javaClass)->GetComponentType());
 }
 
-bool MethodMatches(Method* m, String* name, const std::string& signature) {
-  if (!m->GetName()->Equals(name)) {
+bool MethodMatches(MethodHelper* mh, const std::string& name, ObjectArray<Class>* arg_array) {
+  if (name != mh->GetName()) {
     return false;
   }
-  std::string method_signature = m->GetSignature()->ToModifiedUtf8();
-  if (!StringPiece(method_signature).starts_with(signature)) {
+  const DexFile::TypeList* m_type_list = mh->GetParameterTypeList();
+  uint32_t m_type_list_size = m_type_list == NULL ? 0 : m_type_list->Size();
+  uint32_t sig_length = arg_array->GetLength();
+
+  if (m_type_list_size != sig_length) {
     return false;
   }
-  if (m->IsMiranda()) {
-    return false;
+
+  for (uint32_t i = 0; i < sig_length; i++) {
+    if (mh->GetClassFromTypeIdx(m_type_list->GetTypeItem(i).type_idx_) != arg_array->Get(i)) {
+      return false;
+    }
   }
   return true;
 }
 
-Method* FindConstructorOrMethodInArray(ObjectArray<Method>* methods, String* name,
-    const std::string& signature) {
+Method* FindConstructorOrMethodInArray(ObjectArray<Method>* methods, const std::string& name,
+                                       ObjectArray<Class>* arg_array) {
   if (methods == NULL) {
     return NULL;
   }
   Method* result = NULL;
+  MethodHelper mh;
   for (int32_t i = 0; i < methods->GetLength(); ++i) {
     Method* method = methods->Get(i);
-    if (!MethodMatches(method, name, signature)) {
+    mh.ChangeMethod(method);
+    if (method->IsMiranda() || !MethodMatches(&mh, name, arg_array)) {
       continue;
     }
 
@@ -242,49 +258,42 @@
   return result;
 }
 
-jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass,
-    jclass javaClass, jstring javaName, jobjectArray javaSignature) {
+jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass javaClass, jstring javaName,
+                                             jobjectArray javaArgs) {
   Class* c = Decode<Class*>(env, javaClass);
-  String* name = Decode<String*>(env, javaName);
-  ObjectArray<Class>* signature_array = Decode<ObjectArray<Class>*>(env, javaSignature);
+  std::string name = Decode<String*>(env, javaName)->ToModifiedUtf8();
+  ObjectArray<Class>* arg_array = Decode<ObjectArray<Class>*>(env, javaArgs);
 
-  std::string signature;
-  signature += "(";
-  for (int i = 0; i < signature_array->GetLength(); i++) {
-    signature += signature_array->Get(i)->GetDescriptor()->ToModifiedUtf8();
-  }
-  signature += ")";
-
-  Method* m = FindConstructorOrMethodInArray(c->GetDirectMethods(), name, signature);
+  Method* m = FindConstructorOrMethodInArray(c->GetDirectMethods(), name, arg_array);
   if (m == NULL) {
-    m = FindConstructorOrMethodInArray(c->GetVirtualMethods(), name, signature);
+    m = FindConstructorOrMethodInArray(c->GetVirtualMethods(), name, arg_array);
   }
 
   if (m != NULL) {
-    m->InitJavaFields();
     return AddLocalReference<jobject>(env, m);
   } else {
     return NULL;
   }
 }
 
-jobject Class_getDeclaredField(JNIEnv* env, jclass, jclass jklass, jobject jname) {
+jobject Class_getDeclaredFieldNative(JNIEnv* env, jclass jklass, jobject jname) {
   Class* klass = Decode<Class*>(env, jklass);
   DCHECK(klass->IsClass());
   String* name = Decode<String*>(env, jname);
   DCHECK(name->GetClass()->IsStringClass());
 
+  FieldHelper fh;
   for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
     Field* f = klass->GetInstanceField(i);
-    if (f->GetName()->Equals(name)) {
-      f->InitJavaFields();
+    fh.ChangeField(f);
+    if (name->Equals(fh.GetName())) {
       return AddLocalReference<jclass>(env, f);
     }
   }
   for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
     Field* f = klass->GetStaticField(i);
-    if (f->GetName()->Equals(name)) {
-      f->InitJavaFields();
+    fh.ChangeField(f);
+    if (name->Equals(fh.GetName())) {
       return AddLocalReference<jclass>(env, f);
     }
   }
@@ -302,7 +311,7 @@
  */
 jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
   Class* c = Decode<Class*>(env, javaThis);
-  std::string descriptor(c->GetDescriptor()->ToModifiedUtf8());
+  std::string descriptor(ClassHelper(c).GetDescriptor());
   if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
     // The descriptor indicates that this is the class for
     // a primitive type; special-case the return value.
@@ -370,7 +379,7 @@
 }
 
 // Validate method/field access.
-bool CheckMemberAccess(const Class* access_from, const Class* access_to, uint32_t member_flags) {
+bool CheckMemberAccess(const Class* access_from, Class* access_to, uint32_t member_flags) {
   // quick accept for public access */
   if (member_flags & kAccPublic) {
     return true;
@@ -403,7 +412,7 @@
   Class* c = Decode<Class*>(env, javaThis);
   if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
-        "Class %s can not be instantiated", PrettyDescriptor(c->GetDescriptor()).c_str());
+        "Class %s can not be instantiated", PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str());
     return NULL;
   }
 
@@ -414,7 +423,7 @@
   Method* init = c->FindDirectMethod("<init>", "()V");
   if (init == NULL) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
-        "Class %s has no default <init>()V constructor", PrettyDescriptor(c->GetDescriptor()).c_str());
+        "Class %s has no default <init>()V constructor", PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str());
     return NULL;
   }
 
@@ -433,18 +442,19 @@
   Method* caller_caller = frame.GetMethod();
   Class* caller_class = caller_caller->GetDeclaringClass();
 
+  ClassHelper caller_ch(caller_class);
   if (!caller_class->CanAccess(c)) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
         "Class %s is not accessible from class %s",
-        PrettyDescriptor(c->GetDescriptor()).c_str(),
-        PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+        PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str(),
+        PrettyDescriptor(caller_ch.GetDescriptor()).c_str());
     return NULL;
   }
   if (!CheckMemberAccess(caller_class, init->GetDeclaringClass(), init->GetAccessFlags())) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessException;",
         "%s is not accessible from class %s",
         PrettyMethod(init).c_str(),
-        PrettyDescriptor(caller_class->GetDescriptor()).c_str());
+        PrettyDescriptor(caller_ch.GetDescriptor()).c_str());
     return NULL;
   }
 
@@ -463,15 +473,16 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
   NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
-  NATIVE_METHOD(Class, getClassLoader, "(Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
+  NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"),
+  NATIVE_METHOD(Class, getClassLoaderNative, "()Ljava/lang/ClassLoader;"),
   NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
-  NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
-  NATIVE_METHOD(Class, getDeclaredConstructors, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Constructor;"),
-  NATIVE_METHOD(Class, getDeclaredField, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"),
-  NATIVE_METHOD(Class, getDeclaredFields, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Field;"),
-  NATIVE_METHOD(Class, getDeclaredMethods, "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;"),
+  NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
+  NATIVE_METHOD(Class, getDeclaredConstructors, "(Z)[Ljava/lang/reflect/Constructor;"),
+  NATIVE_METHOD(Class, getDeclaredFieldNative, "(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
+  NATIVE_METHOD(Class, getDeclaredFields, "(Z)[Ljava/lang/reflect/Field;"),
+  NATIVE_METHOD(Class, getDeclaredMethods, "(Z)[Ljava/lang/reflect/Method;"),
   NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
-  NATIVE_METHOD(Class, getNonInnerClassModifiers, "(Ljava/lang/Class;)I"),
+  NATIVE_METHOD(Class, getNonInnerClassModifiers, "()I"),
   NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
   NATIVE_METHOD(Class, getSuperclass, "()Ljava/lang/Class;"),
   NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
diff --git a/src/java_lang_reflect_Array.cc b/src/java_lang_reflect_Array.cc
index 08960b1..50bfb83 100644
--- a/src/java_lang_reflect_Array.cc
+++ b/src/java_lang_reflect_Array.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "class_linker.h"
 #include "object.h"
+#include "object_utils.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 
@@ -43,7 +44,7 @@
     // old code assumed this but if you recurse from "[Foo" to "Foo" to "oo",
     // you shouldn't assume there isn't a class "oo".
   }
-  std::string sub_array_descriptor(array_class->GetDescriptor()->ToModifiedUtf8(), 1);
+  std::string sub_array_descriptor(ClassHelper(array_class).GetDescriptor(), 1);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* sub_array_class = class_linker->FindClass(sub_array_descriptor,
                                                    array_class->GetClassLoader());
@@ -77,9 +78,9 @@
   Class* element_class = Decode<Class*>(env, javaElementClass);
   DCHECK(element_class->IsClass());
   DCHECK(javaDimArray != NULL);
-  Object* dimensions_obj = Decode<Class*>(env, javaDimArray);
+  Object* dimensions_obj = Decode<Object*>(env, javaDimArray);
   DCHECK(dimensions_obj->IsArrayInstance());
-  DCHECK(dimensions_obj->GetClass()->GetDescriptor()->Equals("[I"));
+  DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor().c_str(), "[I");
   IntArray* dimensions_array = down_cast<IntArray*>(dimensions_obj);
 
   // Verify dimensions.
@@ -101,7 +102,7 @@
 
   // Generate the full name of the array class.
   std::string descriptor(num_dimensions, '[');
-  descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+  descriptor += ClassHelper(element_class).GetDescriptor();
 
   // Find/generate the array class.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -130,7 +131,7 @@
   }
   std::string descriptor;
   descriptor += '[';
-  descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+  descriptor += ClassHelper(element_class).GetDescriptor();
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* array_class = class_linker->FindClass(descriptor, element_class->GetClassLoader());
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
index f730543..36481f7 100644
--- a/src/java_lang_reflect_Constructor.cc
+++ b/src/java_lang_reflect_Constructor.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "class_linker.h"
 #include "object.h"
+#include "object_utils.h"
 #include "reflection.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -32,12 +33,13 @@
  * check.  We can also safely assume the constructor isn't associated
  * with an interface, array, or primitive class.
  */
-jobject Constructor_constructNative(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, jclass javaDeclaringClass, jobjectArray javaParams, jint, jboolean) {
+jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
   ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
-  Class* c = Decode<Class*>(env, javaDeclaringClass);
+  Method* m = Decode<Object*>(env, javaMethod)->AsMethod();
+  Class* c = m->GetDeclaringClass();
   if (c->IsAbstract()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
-        "Can't instantiate abstract class %s", PrettyDescriptor(c->GetDescriptor()).c_str());
+        "Can't instantiate abstract class %s", PrettyDescriptor(c).c_str());
     return NULL;
   }
 
@@ -52,14 +54,14 @@
   }
 
   jobject javaReceiver = AddLocalReference<jobject>(env, receiver);
-  InvokeMethod(env, javaMethod, javaReceiver, javaArgs, javaParams);
+  InvokeMethod(env, javaMethod, javaReceiver, javaArgs);
 
   // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod.
   return javaReceiver;
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Constructor, constructNative, "([Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;IZ)Ljava/lang/Object;"),
+  NATIVE_METHOD(Constructor, newInstance, "([Ljava/lang/Object;)Ljava/lang/Object;"),
 };
 
 }  // namespace
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index 7e66dd9..eb56edb 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "class_linker.h"
 #include "object.h"
+#include "object_utils.h"
 #include "reflection.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -25,13 +26,9 @@
 
 namespace {
 
-jint Field_getFieldModifiers(JNIEnv* env, jobject jfield, jclass javaDeclaringClass, jint slot) {
-  return Decode<Object*>(env, jfield)->AsField()->GetAccessFlags() & kAccJavaFlagsMask;
-}
-
 bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
   ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
-  switch (f->GetPrimitiveType()) {
+  switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
   case Primitive::kPrimBoolean:
     value.z = f->GetBoolean(o);
     return true;
@@ -72,24 +69,41 @@
   return false;
 }
 
-bool CheckReceiver(JNIEnv* env, jobject javaObj, jclass javaDeclaringClass, Field* f, Object*& o) {
+bool CheckReceiver(JNIEnv* env, jobject javaObj, Field* f, Object*& o) {
   if (f->IsStatic()) {
     o = NULL;
     return true;
   }
 
   o = Decode<Object*>(env, javaObj);
-  Class* declaringClass = Decode<Class*>(env, javaDeclaringClass);
+  Class* declaringClass = f->GetDeclaringClass();
   if (!VerifyObjectInClass(env, o, declaringClass)) {
     return false;
   }
   return true;
 }
 
-JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar dst_descriptor) {
+jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
   Field* f = DecodeField(env->FromReflectedField(javaField));
   Object* o = NULL;
-  if (!CheckReceiver(env, javaObj, javaDeclaringClass, f, o)) {
+  if (!CheckReceiver(env, javaObj, f, o)) {
+    return NULL;
+  }
+
+  // Get the field's value, boxing if necessary.
+  JValue value;
+  if (!GetFieldValue(o, f, value, true)) {
+    return NULL;
+  }
+  BoxPrimitive(env, FieldHelper(f).GetTypeAsPrimitiveType(), value);
+
+  return AddLocalReference<jobject>(env, value.l);
+}
+
+JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char dst_descriptor) {
+  Field* f = DecodeField(env->FromReflectedField(javaField));
+  Object* o = NULL;
+  if (!CheckReceiver(env, javaObj, f, o)) {
     return JValue();
   }
 
@@ -102,47 +116,47 @@
   // Widen it if necessary (and possible).
   JValue wide_value;
   Class* dst_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(dst_descriptor);
-  if (!ConvertPrimitiveValue(f->GetPrimitiveType(), dst_type->GetPrimitiveType(),
+  if (!ConvertPrimitiveValue(FieldHelper(f).GetTypeAsPrimitiveType(), dst_type->GetPrimitiveType(),
                              field_value, wide_value)) {
     return JValue();
   }
   return wide_value;
 }
 
-jbyte Field_getBField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).b;
+jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'Z').z;
 }
 
-jchar Field_getCField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).c;
+jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'B').b;
 }
 
-jdouble Field_getDField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).d;
+jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'C').c;
 }
 
-jfloat Field_getFField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).f;
+jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'D').d;
 }
 
-jint Field_getIField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).i;
+jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'F').f;
 }
 
-jlong Field_getJField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).j;
+jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'I').i;
 }
 
-jshort Field_getSField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).s;
+jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'J').j;
 }
 
-jboolean Field_getZField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar dst_descriptor) {
-  return GetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, dst_descriptor).z;
+jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) {
+  return GetPrimitiveField(env, javaField, javaObj, 'S').s;
 }
 
 void SetFieldValue(Object* o, Field* f, const JValue& new_value, bool allow_references) {
-  switch (f->GetPrimitiveType()) {
+  switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
   case Primitive::kPrimBoolean:
     f->SetBoolean(o, new_value.z);
     break;
@@ -187,14 +201,36 @@
   }
 }
 
-void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar src_descriptor, const JValue& new_value) {
+void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
+  Field* f = DecodeField(env->FromReflectedField(javaField));
+
+  // Unbox the value, if necessary.
+  Object* boxed_value = Decode<Object*>(env, javaValue);
+  JValue unboxed_value;
+  if (!UnboxPrimitive(env, boxed_value, FieldHelper(f).GetType(), unboxed_value)) {
+    return;
+  }
+
+  // Check that the receiver is non-null and an instance of the field's declaring class.
+  Object* o = NULL;
+  if (!CheckReceiver(env, javaObj, f, o)) {
+    return;
+  }
+
+  SetFieldValue(o, f, unboxed_value, true);
+}
+
+void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
+                       const JValue& new_value) {
   ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   Field* f = DecodeField(env->FromReflectedField(javaField));
   Object* o = NULL;
-  if (!CheckReceiver(env, javaObj, javaDeclaringClass, f, o)) {
+  if (!CheckReceiver(env, javaObj, f, o)) {
     return;
   }
-  if (f->GetPrimitiveType() == Primitive::kPrimNot) {
+  FieldHelper fh(f);
+  if (!fh.IsPrimitiveType()) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
         "Not a primitive field: %s", PrettyField(f).c_str());
     return;
@@ -203,7 +239,7 @@
   // Widen the value if necessary (and possible).
   JValue wide_value;
   Class* src_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(src_descriptor);
-  if (!ConvertPrimitiveValue(src_type->GetPrimitiveType(), f->GetPrimitiveType(),
+  if (!ConvertPrimitiveValue(src_type->GetPrimitiveType(), fh.GetTypeAsPrimitiveType(),
                              new_value, wide_value)) {
     return;
   }
@@ -212,112 +248,73 @@
   SetFieldValue(o, f, wide_value, false);
 }
 
-void Field_setBField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jbyte value) {
-  JValue v = { 0 };
-  v.b = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setCField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jchar value) {
-  JValue v = { 0 };
-  v.c = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setDField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jdouble value) {
-  JValue v = { 0 };
-  v.d = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setFField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jfloat value) {
-  JValue v = { 0 };
-  v.f = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setIField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jint value) {
-  JValue v = { 0 };
-  v.i = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setJField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jlong value) {
-  JValue v = { 0 };
-  v.j = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setSField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jshort value) {
-  JValue v = { 0 };
-  v.s = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
-}
-
-void Field_setZField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jchar src_descriptor, jboolean value) {
+void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean value) {
   JValue v = { 0 };
   v.z = value;
-  SetPrimitiveField(env, javaField, javaObj, javaDeclaringClass, src_descriptor, v);
+  SetPrimitiveField(env, javaField, javaObj, 'Z', v);
 }
 
-void Field_setField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jobject javaValue) {
-  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
-  Field* f = DecodeField(env->FromReflectedField(javaField));
-
-  // Unbox the value, if necessary.
-  Object* boxed_value = Decode<Object*>(env, javaValue);
-  JValue unboxed_value;
-  if (!UnboxPrimitive(env, boxed_value, f->GetType(), unboxed_value)) {
-    return;
-  }
-
-  // Check that the receiver is non-null and an instance of the field's declaring class.
-  Object* o = NULL;
-  if (!CheckReceiver(env, javaObj, javaDeclaringClass, f, o)) {
-    return;
-  }
-
-  SetFieldValue(o, f, unboxed_value, true);
+void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte value) {
+  JValue v = { 0 };
+  v.b = value;
+  SetPrimitiveField(env, javaField, javaObj, 'B', v);
 }
 
-jobject Field_getField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean) {
-  Field* f = DecodeField(env->FromReflectedField(javaField));
-  Object* o = NULL;
-  if (!CheckReceiver(env, javaObj, javaDeclaringClass, f, o)) {
-    return NULL;
-  }
+void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar value) {
+  JValue v = { 0 };
+  v.c = value;
+  SetPrimitiveField(env, javaField, javaObj, 'C', v);
+}
 
-  // Get the field's value, boxing if necessary.
-  JValue value;
-  if (!GetFieldValue(o, f, value, true)) {
-    return NULL;
-  }
-  BoxPrimitive(env, f->GetPrimitiveType(), value);
+void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble value) {
+  JValue v = { 0 };
+  v.d = value;
+  SetPrimitiveField(env, javaField, javaObj, 'D', v);
+}
 
-  return AddLocalReference<jobject>(env, value.l);
+void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat value) {
+  JValue v = { 0 };
+  v.f = value;
+  SetPrimitiveField(env, javaField, javaObj, 'F', v);
+}
+
+void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint value) {
+  JValue v = { 0 };
+  v.i = value;
+  SetPrimitiveField(env, javaField, javaObj, 'I', v);
+}
+
+void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong value) {
+  JValue v = { 0 };
+  v.j = value;
+  SetPrimitiveField(env, javaField, javaObj, 'J', v);
+}
+
+void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort value) {
+  JValue v = { 0 };
+  v.s = value;
+  SetPrimitiveField(env, javaField, javaObj, 'S', v);
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Field, getFieldModifiers, "(Ljava/lang/Class;I)I"),
-
-  NATIVE_METHOD(Field, getBField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)B"),
-  NATIVE_METHOD(Field, getCField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)C"),
-  NATIVE_METHOD(Field, getDField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)D"),
-  NATIVE_METHOD(Field, getFField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)F"),
-  NATIVE_METHOD(Field, getField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"),
-  NATIVE_METHOD(Field, getIField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)I"),
-  NATIVE_METHOD(Field, getJField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)J"),
-  NATIVE_METHOD(Field, getSField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)S"),
-  NATIVE_METHOD(Field, getZField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)Z"),
-  NATIVE_METHOD(Field, setBField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCB)V"),
-  NATIVE_METHOD(Field, setCField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCC)V"),
-  NATIVE_METHOD(Field, setDField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCD)V"),
-  NATIVE_METHOD(Field, setFField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCF)V"),
-  NATIVE_METHOD(Field, setField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZLjava/lang/Object;)V"),
-  NATIVE_METHOD(Field, setIField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCI)V"),
-  NATIVE_METHOD(Field, setJField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCJ)V"),
-  NATIVE_METHOD(Field, setSField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCS)V"),
-  NATIVE_METHOD(Field, setZField, "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCZ)V"),
+  NATIVE_METHOD(Field, get,        "(Ljava/lang/Object;)Ljava/lang/Object;"),
+  NATIVE_METHOD(Field, getBoolean, "(Ljava/lang/Object;)Z"),
+  NATIVE_METHOD(Field, getByte,    "(Ljava/lang/Object;)B"),
+  NATIVE_METHOD(Field, getChar,    "(Ljava/lang/Object;)C"),
+  NATIVE_METHOD(Field, getDouble,  "(Ljava/lang/Object;)D"),
+  NATIVE_METHOD(Field, getFloat,   "(Ljava/lang/Object;)F"),
+  NATIVE_METHOD(Field, getInt,     "(Ljava/lang/Object;)I"),
+  NATIVE_METHOD(Field, getLong,    "(Ljava/lang/Object;)J"),
+  NATIVE_METHOD(Field, getShort,   "(Ljava/lang/Object;)S"),
+  NATIVE_METHOD(Field, set,        "(Ljava/lang/Object;Ljava/lang/Object;)V"),
+  NATIVE_METHOD(Field, setBoolean, "(Ljava/lang/Object;Z)V"),
+  NATIVE_METHOD(Field, setByte,    "(Ljava/lang/Object;B)V"),
+  NATIVE_METHOD(Field, setChar,    "(Ljava/lang/Object;C)V"),
+  NATIVE_METHOD(Field, setDouble,  "(Ljava/lang/Object;D)V"),
+  NATIVE_METHOD(Field, setFloat,   "(Ljava/lang/Object;F)V"),
+  NATIVE_METHOD(Field, setInt,     "(Ljava/lang/Object;I)V"),
+  NATIVE_METHOD(Field, setLong,    "(Ljava/lang/Object;J)V"),
+  NATIVE_METHOD(Field, setShort,   "(Ljava/lang/Object;S)V"),
 };
 
 }  // namespace
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index e36078f..90d718d 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "class_linker.h"
 #include "object.h"
+#include "object_utils.h"
 #include "reflection.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -25,33 +26,19 @@
 
 namespace {
 
-jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
-  Method* m = Decode<Object*>(env, jmethod)->AsMethod();
-  jint access_flags = m->GetAccessFlags();
-  // We move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
-  // position, because the callers of this function are trying to convey
-  // the "traditional" meaning of the flags to their callers.
-  access_flags &= ~kAccSynchronized;
-  if ((access_flags & kAccDeclaredSynchronized) != 0) {
-    access_flags |= kAccSynchronized;
-  }
-
-  return access_flags & kAccJavaFlagsMask;
+jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
+  return InvokeMethod(env, javaMethod, javaReceiver, javaArgs);
 }
 
-jint Method_getProtoIndex(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
-  Method* m = Decode<Object*>(env, jmethod)->AsMethod();
-  return m->GetProtoIdx();
-}
-
-jobject Method_invokeNative(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jclass, jobject javaParams, jclass, jint, jboolean) {
-  return InvokeMethod(env, javaMethod, javaReceiver, javaArgs, javaParams);
+jobject Method_getReturnTypeNative(JNIEnv* env, jobject javaMethod) {
+  Method* m = Decode<Object*>(env, javaMethod)->AsMethod();
+  MethodHelper mh(m);
+  return AddLocalReference<jobject>(env, mh.GetReturnType());
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Method, getMethodModifiers, "(Ljava/lang/Class;Ljava/lang/reflect/AccessibleObject;I)I"),
-  NATIVE_METHOD(Method, getProtoIndex, "(Ljava/lang/Class;Ljava/lang/reflect/AccessibleObject;I)I"),
-  NATIVE_METHOD(Method, invokeNative, "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"),
+  NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+  NATIVE_METHOD(Method, getReturnTypeNative, "()Ljava/lang/Class;")
 };
 
 }  // namespace
diff --git a/src/java_lang_reflect_Proxy.cc b/src/java_lang_reflect_Proxy.cc
index 55ecd08..28fe514 100644
--- a/src/java_lang_reflect_Proxy.cc
+++ b/src/java_lang_reflect_Proxy.cc
@@ -25,6 +25,8 @@
 namespace {
 
 static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring javaName, jobjectArray javaInterfaces, jobject javaLoader, jobjectArray javaMethods, jobjectArray javaThrows) {
+  // Allocates Class so transition thread state to runnable
+  ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
   String* name = Decode<String*>(env, javaName);
   ObjectArray<Class>* interfaces = Decode<ObjectArray<Class>*>(env, javaInterfaces);
   ClassLoader* loader = Decode<ClassLoader*>(env, javaLoader);
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 82c120c..718659f 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -18,6 +18,7 @@
 #include "jni.h"
 #include "logging.h"
 #include "object.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "scoped_jni_thread_state.h"
 #include "stl_util.h"
@@ -119,24 +120,6 @@
   return num_bytes;
 }
 
-static size_t NumArgArrayBytes(const String* shorty) {
-  size_t num_bytes = 0;
-  size_t end = shorty->GetLength();
-  for (size_t i = 1; i < end; ++i) {
-    char ch = shorty->CharAt(i);
-    if (ch == 'D' || ch == 'J') {
-      num_bytes += 8;
-    } else if (ch == 'L') {
-      // Argument is a reference or an array.  The shorty descriptor
-      // does not distinguish between these types.
-      num_bytes += sizeof(Object*);
-    } else {
-      num_bytes += 4;
-    }
-  }
-  return num_bytes;
-}
-
 // For external use.
 template<typename T>
 T Decode(JNIEnv* public_env, jobject obj) {
@@ -177,11 +160,12 @@
 
 static byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) {
   JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
-  const String* shorty = method->GetShorty();
+  const char* shorty = MethodHelper(method).GetShorty();
+  size_t shorty_len = strlen(shorty);
   size_t num_bytes = NumArgArrayBytes(shorty);
   UniquePtr<byte[]> arg_array(new byte[num_bytes]);
-  for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) {
-    switch (shorty->CharAt(i)) {
+  for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
+    switch (shorty[i]) {
       case 'Z':
       case 'B':
       case 'C':
@@ -215,11 +199,12 @@
 
 static byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) {
   JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
-  size_t num_bytes = NumArgArrayBytes(method->GetShorty());
+  const char* shorty = MethodHelper(method).GetShorty();
+  size_t shorty_len = strlen(shorty);
+  size_t num_bytes = NumArgArrayBytes(shorty);
   UniquePtr<byte[]> arg_array(new byte[num_bytes]);
-  const String* shorty = method->GetShorty();
-  for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) {
-    switch (shorty->CharAt(i)) {
+  for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
+    switch (shorty[i]) {
       case 'Z':
       case 'B':
       case 'C':
@@ -313,9 +298,8 @@
 }
 
 static void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const char* name, const char* sig, const char* kind) {
-  std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
   ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
-      "no %s method \"%s.%s%s\"", kind, class_descriptor.c_str(), name, sig);
+      "no %s method \"%s.%s%s\"", kind, ClassHelper(c).GetDescriptor().c_str(), name, sig);
 }
 
 static jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
@@ -341,8 +325,6 @@
     return NULL;
   }
 
-  method->InitJavaFields();
-
   return EncodeMethod(method);
 }
 
@@ -374,26 +356,22 @@
     // Failed to find type from the signature of the field.
     DCHECK(ts.Self()->IsExceptionPending());
     ts.Self()->ClearException();
-    std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
     ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
         "no type \"%s\" found and so no field \"%s\" could be found in class "
-        "\"%s\" or its superclasses", sig, name, class_descriptor.c_str());
+        "\"%s\" or its superclasses", sig, name, ClassHelper(c).GetDescriptor().c_str());
     return NULL;
   }
-  std::string field_type_descriptor = field_type->GetDescriptor()->ToModifiedUtf8();
   if (is_static) {
-    field = c->FindStaticField(name, field_type_descriptor);
+    field = c->FindStaticField(name, ClassHelper(field_type).GetDescriptor());
   } else {
-    field = c->FindInstanceField(name, field_type_descriptor);
+    field = c->FindInstanceField(name, ClassHelper(field_type).GetDescriptor());
   }
   if (field == NULL) {
-    std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
     ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
         "no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
-        name, class_descriptor.c_str());
+        name, ClassHelper(c).GetDescriptor().c_str());
     return NULL;
   }
-  field->InitJavaFields();
   return EncodeField(field);
 }
 
@@ -1996,7 +1974,7 @@
     Class* element_class = Decode<Class*>(ts, element_jclass);
     std::string descriptor;
     descriptor += "[";
-    descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
+    descriptor += ClassHelper(element_class).GetDescriptor();
 
     // Find the class.
     ScopedLocalRef<jclass> java_array_class(env, FindClass(env, descriptor.c_str()));
@@ -2209,9 +2187,11 @@
         m = c->FindVirtualMethod(name, sig);
       }
       if (m == NULL) {
+        LOG(INFO) << "Failed to register native method " << name << sig;
         ThrowNoSuchMethodError(ts, c, name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
+        LOG(INFO) << "Failed to register non-native method " << name << sig << " as native";
         ThrowNoSuchMethodError(ts, c, name, sig, "native");
         return JNI_ERR;
       }
diff --git a/src/monitor.cc b/src/monitor.cc
index 3f041e4..69eb9ba 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -27,6 +27,7 @@
 #include "class_linker.h"
 #include "mutex.h"
 #include "object.h"
+#include "object_utils.h"
 #include "stl_util.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -824,15 +825,9 @@
     line_number = 0;
     return;
   }
-
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Class* c = method->GetDeclaringClass();
-  DexCache* dex_cache = c->GetDexCache();
-  const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-  const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8());
-
-  source_file = dex_file.GetSourceFile(*class_def);
-  line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(pc));
+  MethodHelper mh(method);
+  source_file = mh.GetDeclaringClassSourceFile();
+  line_number = mh.GetLineNumFromNativePC(pc);
 }
 
 MonitorList::MonitorList() : lock_("MonitorList lock") {
diff --git a/src/oatdump.cc b/src/oatdump.cc
index ac9449f..5cff2ea 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -12,6 +12,7 @@
 #include "file.h"
 #include "image.h"
 #include "os.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "space.h"
 #include "stringpiece.h"
@@ -299,7 +300,8 @@
     StringAppendF(&summary, "%p: ", obj);
     if (obj->IsClass()) {
       Class* klass = obj->AsClass();
-      StringAppendF(&summary, "CLASS %s", klass->GetDescriptor()->ToModifiedUtf8().c_str());
+      summary += "CLASS ";
+      summary += ClassHelper(klass).GetDescriptor();
       std::ostringstream ss;
       ss << " (" << klass->GetStatus() << ")";
       summary += ss.str();
@@ -317,7 +319,7 @@
       StringAppendF(&summary, "OBJECT");
     }
     StringAppendF(&summary, "\n");
-    std::string descriptor = obj->GetClass()->GetDescriptor()->ToModifiedUtf8();
+    std::string descriptor(ClassHelper(obj->GetClass()).GetDescriptor());
     StringAppendF(&summary, "\tclass %p: %s\n", obj->GetClass(), descriptor.c_str());
     state->stats_.descriptor_to_bytes[descriptor] += object_bytes;
     state->stats_.descriptor_to_count[descriptor] += 1;
@@ -359,10 +361,7 @@
           state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
         }
 
-        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-        class DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
-        const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-        const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
+        const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
       }
diff --git a/src/object.cc b/src/object.cc
index b8d82dc..14e8c5c 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -18,6 +18,7 @@
 #include "intern_table.h"
 #include "logging.h"
 #include "monitor.h"
+#include "object_utils.h"
 #include "runtime.h"
 #include "stack.h"
 #include "utils.h"
@@ -93,73 +94,18 @@
   java_lang_reflect_Field_ = NULL;
 }
 
-void Field::SetTypeIdx(uint32_t type_idx) {
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), type_idx, false);
-}
-
-Class* Field::GetTypeDuringLinking() const {
-  // We are assured that the necessary primitive types are in the dex cache
-  // early during class linking
-  return GetDeclaringClass()->GetDexCache()->GetResolvedType(GetTypeIdx());
-}
-
-bool Field::IsPrimitiveType() const {
-  Class* type = GetTypeDuringLinking();
-  return (type == NULL || type->IsPrimitive());
-}
-
-Primitive::Type Field::GetPrimitiveType() const {
-  Class* type = GetTypeDuringLinking();
-  if (type == NULL) {
-    return Primitive::kPrimNot;
-  }
-  return type->GetPrimitiveType();
-}
-
-size_t Field::PrimitiveSize() const {
-  return Primitive::FieldSize(GetPrimitiveType());
-}
-
-const char* Field::GetTypeDescriptor() const {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile& dex_file = class_linker->FindDexFile(GetDeclaringClass()->GetDexCache());
-  const char* descriptor = dex_file.StringByTypeIdx(GetTypeIdx());
-  DCHECK(descriptor != NULL);
-  return descriptor;
-}
-
-Class* Field::GetType() {
-  Class* type = GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Field, type_), false);
-  if (type == NULL) {
-    type = Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this);
-    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, type_), type, false);
-  }
-  return type;
-}
-
 void Field::SetOffset(MemberOffset num_bytes) {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  Primitive::Type type = GetPrimitiveType();
+#if 0 // TODO enable later in boot and under !NDEBUG
+  FieldHelper fh(this);
+  Primitive::Type type = fh.GetTypeAsPrimitiveType();
   if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
     DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
   }
+#endif
   SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), num_bytes.Uint32Value(), false);
 }
 
-void Field::InitJavaFields() {
-  Thread* self = Thread::Current();
-  ScopedThreadStateChange tsc(self, Thread::kRunnable);
-  MonitorEnter(self);
-  if (type_ == NULL) {
-    InitJavaFieldsLocked();
-  }
-  MonitorExit(self);
-}
-
-void Field::InitJavaFieldsLocked() {
-  GetType(); // Resolves type as a side-effect. May throw.
-}
-
 uint32_t Field::Get32(const Object* object) const {
   CHECK((object == NULL) == IsStatic()) << PrettyField(this);
   if (IsStatic()) {
@@ -209,107 +155,121 @@
 }
 
 bool Field::GetBoolean(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType())
+      << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetBoolean(Object* object, bool z) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType())
+      << PrettyField(this);
   Set32(object, z);
 }
 
 int8_t Field::GetByte(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType())
+      << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetByte(Object* object, int8_t b) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType())
+      << PrettyField(this);
   Set32(object, b);
 }
 
 uint16_t Field::GetChar(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType())
+      << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetChar(Object* object, uint16_t c) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   Set32(object, c);
 }
 
 int16_t Field::GetShort(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetShort(Object* object, int16_t s) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   Set32(object, s);
 }
 
 int32_t Field::GetInt(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimInt, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetInt(Object* object, int32_t i) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimInt, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   Set32(object, i);
 }
 
 int64_t Field::GetLong(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimLong, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   return Get64(object);
 }
 
 void Field::SetLong(Object* object, int64_t j) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimLong, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   Set64(object, j);
 }
 
 float Field::GetFloat(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   JValue float_bits;
   float_bits.i = Get32(object);
   return float_bits.f;
 }
 
 void Field::SetFloat(Object* object, float f) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   JValue float_bits;
   float_bits.f = f;
   Set32(object, float_bits.i);
 }
 
 double Field::GetDouble(const Object* object) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   JValue double_bits;
   double_bits.j = Get64(object);
   return double_bits.d;
 }
 
 void Field::SetDouble(Object* object, double d) const {
-  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   JValue double_bits;
   double_bits.d = d;
   Set64(object, double_bits.j);
 }
 
 Object* Field::GetObject(const Object* object) const {
-  CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   return GetObj(object);
 }
 
 void Field::SetObject(Object* object, const Object* l) const {
-  CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
+  DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType())
+       << PrettyField(this);
   SetObj(object, l);
 }
 
-bool Method::IsClassInitializer() const {
-  return IsStatic() && GetName()->Equals("<clinit>");
-}
-
 // TODO: get global references for these
 Class* Method::java_lang_reflect_Constructor_ = NULL;
 Class* Method::java_lang_reflect_Method_ = NULL;
@@ -361,118 +321,11 @@
   }
 }
 
-void Method::InitJavaFieldsLocked() {
-  // Create the array.
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  size_t arg_count = GetShorty()->GetLength() - 1;
-  Class* array_class = class_linker->FindSystemClass("[Ljava/lang/Class;");
-  ObjectArray<Class>* parameters = ObjectArray<Class>::Alloc(array_class, arg_count);
-  if (parameters == NULL) {
-    return;
-  }
-
-  // Parse the signature, filling the array.
-  const ClassLoader* cl = GetDeclaringClass()->GetClassLoader();
-  std::string signature(GetSignature()->ToModifiedUtf8());
-  const char* p = signature.c_str();
-  DCHECK_EQ(*p, '(');
-  ++p;
-  for (size_t i = 0; i < arg_count; ++i) {
-    Class* c = ExtractNextClassFromSignature(class_linker, cl, p);
-    if (c == NULL) {
-      return;
-    }
-    parameters->Set(i, c);
-  }
-
-  DCHECK_EQ(*p, ')');
-  ++p;
-
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_parameter_types_),
-                 parameters, false);
-  Class* java_return_type = ExtractNextClassFromSignature(class_linker, cl, p);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_),
-                 java_return_type, false);
-}
-
-void Method::InitJavaFields() {
-  Thread* self = Thread::Current();
-  ScopedThreadStateChange tsc(self, Thread::kRunnable);
-  MonitorEnter(self);
-  if (java_parameter_types_ == NULL || java_return_type_ == NULL) {
-    InitJavaFieldsLocked();
-  }
-  MonitorExit(self);
-}
-
 ObjectArray<String>* Method::GetDexCacheStrings() const {
   return GetFieldObject<ObjectArray<String>*>(
       OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_), false);
 }
 
-void Method::SetReturnTypeIdx(uint32_t new_return_type_idx) {
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
-             new_return_type_idx, false);
-}
-
-uint32_t Method::GetDexMethodIndex() const {
-  // TODO: add the method index to Method - which will also mean a number of Method fields can
-  // become dex file lookups (which will then mean we may want faster access to the dex file)
-  // Find the dex file
-  const DexCache* dex_cache = GetDeclaringClass()->GetDexCache();
-  const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache);
-  // Find the class_def in the dex file
-  uint32_t class_def_idx;
-  bool found_class_def =
-      dex_file.FindClassDefIndex(GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8(),
-                                 class_def_idx);
-  CHECK(found_class_def);
-  const DexFile::TypeId& type_id =
-      dex_file.GetTypeId(dex_file.GetClassDef(class_def_idx).class_idx_);
-  const DexFile::StringId* name_str_id = dex_file.FindStringId(GetName()->ToModifiedUtf8());
-  CHECK(name_str_id != NULL);  // Failed to find method's name?
-  uint16_t return_type_idx;
-  std::vector<uint16_t> param_type_idxs;
-  std::string signature = GetSignature()->ToModifiedUtf8();
-  bool found_type_list = dex_file.CreateTypeList(&return_type_idx, &param_type_idxs, signature);
-  CHECK(found_type_list);   // Failed to parse signature
-  const DexFile::ProtoId* sig_proto_id = dex_file.FindProtoId(return_type_idx, param_type_idxs);
-  CHECK(sig_proto_id != NULL);  // Failed to find method's prototype
-  const DexFile::MethodId* method_id =
-      dex_file.FindMethodId(type_id, *name_str_id, *sig_proto_id);
-  CHECK(method_id != NULL);  // Failed to find method?
-  uint32_t method_idx = dex_file.GetIndexForMethodId(*method_id);
-  DCHECK_EQ(PrettyMethod(method_idx, dex_file), PrettyMethod(this));
-  return method_idx;
-}
-
-const char* Method::GetReturnTypeDescriptor() const {
-  Class* declaring_class = GetDeclaringClass();
-  DexCache* dex_cache = declaring_class->GetDexCache();
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-  const char* descriptor = dex_file.StringByTypeIdx(GetReturnTypeIdx());
-  DCHECK(descriptor != NULL);
-  return descriptor;
-}
-
-Class* Method::GetReturnType() const {
-  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous())
-      << PrettyMethod(this);
-  Class* java_return_type = java_return_type_;
-  if (java_return_type != NULL) {
-      return java_return_type;
-  }
-  // Short-cut
-  Class* result = GetDexCacheResolvedTypes()->Get(GetReturnTypeIdx());
-  if (result == NULL) {
-    // Do full linkage and set cache value for next call
-    result = Runtime::Current()->GetClassLinker()->ResolveType(GetReturnTypeIdx(), this);
-  }
-  CHECK(result != NULL) << PrettyMethod(this);
-  return result;
-}
-
 void Method::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_),
                  new_dex_cache_strings, false);
@@ -545,85 +398,8 @@
   return num_registers;
 }
 
-size_t Method::NumArgs() const {
-  // "1 +" because the first in Args is the receiver.
-  // "- 1" because we don't count the return type.
-  return (IsStatic() ? 0 : 1) + GetShorty()->GetLength() - 1;
-}
-
-// The number of reference arguments to this method including implicit this
-// pointer
-size_t Method::NumReferenceArgs() const {
-  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);
-    if ((ch == 'L') || (ch == '[')) {
-      result++;
-    }
-  }
-  return result;
-}
-
-// The number of long or double arguments
-size_t Method::NumLongOrDoubleArgs() const {
-  const String* shorty = GetShorty();
-  size_t result = 0;
-  for (int i = 1; i < shorty->GetLength(); i++) {
-    char ch = shorty->CharAt(i);
-    if ((ch == 'D') || (ch == 'J')) {
-      result++;
-    }
-  }
-  return result;
-}
-
-// Is the given method parameter a reference?
-bool Method::IsParamAReference(unsigned int param) const {
-  CHECK_LT(param, NumArgs());
-  if (IsStatic()) {
-    param++;  // 0th argument must skip return value at start of the shorty
-  } else if (param == 0) {
-    return true;  // this argument
-  }
-  return GetShorty()->CharAt(param) == 'L';
-}
-
-// Is the given method parameter a long or double?
-bool Method::IsParamALongOrDouble(unsigned int param) const {
-  CHECK_LT(param, NumArgs());
-  if (IsStatic()) {
-    param++;  // 0th argument must skip return value at start of the shorty
-  } else if (param == 0) {
-    return false;  // this argument
-  }
-  char ch = GetShorty()->CharAt(param);
-  return (ch == 'J' || ch == 'D');
-}
-
-static size_t ShortyCharToSize(char x) {
-  switch (x) {
-    case 'V': return 0;
-    case '[': return kPointerSize;
-    case 'L': return kPointerSize;
-    case 'D': return 8;
-    case 'J': return 8;
-    default:  return 4;
-  }
-}
-
-size_t Method::ParamSize(unsigned int param) const {
-  CHECK_LT(param, NumArgs());
-  if (IsStatic()) {
-    param++;  // 0th argument must skip return value at start of the shorty
-  } else if (param == 0) {
-    return kPointerSize;  // this argument
-  }
-  return ShortyCharToSize(GetShorty()->CharAt(param));
-}
-
-size_t Method::ReturnSize() const {
-  return ShortyCharToSize(GetShorty()->CharAt(0));
+bool Method::IsProxyMethod() const {
+  return GetDeclaringClass()->IsProxyClass();
 }
 
 Method* Method::FindOverriddenMethod() const {
@@ -635,25 +411,39 @@
   uint16_t method_index = GetMethodIndex();
   ObjectArray<Method>* super_class_vtable = super_class->GetVTable();
   Method* result = NULL;
+  // Did this method override a super class method? If so load the result from the super class'
+  // vtable
   if (super_class_vtable != NULL && method_index < super_class_vtable->GetLength()) {
     result = super_class_vtable->Get(method_index);
   } else {
-    ObjectArray<Class>* interfaces = declaring_class->GetInterfaces();
-    String* name = GetName();
-    String* signature = GetSignature();
-    for (int32_t i = 0; i < interfaces->GetLength() && result == NULL; i++) {
-      Class* interface = interfaces->Get(i);
-      result = interface->FindInterfaceMethod(name, signature);
+    // Method didn't override superclass method so search interfaces
+    MethodHelper mh(this);
+    MethodHelper interface_mh;
+    ObjectArray<InterfaceEntry>* iftable = GetDeclaringClass()->GetIfTable();
+    for (int32_t i = 0; i < iftable->GetLength() && result == NULL; i++) {
+      InterfaceEntry* entry = iftable->Get(i);
+      Class* interface = entry->GetInterface();
+      for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
+        Method* interface_method = interface->GetVirtualMethod(j);
+        interface_mh.ChangeMethod(interface_method);
+        if (mh.HasSameNameAndSignature(&interface_mh)) {
+          result = interface_method;
+          break;
+        }
+      }
     }
   }
-  DCHECK(result == NULL || HasSameNameAndSignature(result));
+#ifndef NDEBUG
+  MethodHelper result_mh(result);
+  DCHECK(result == NULL || MethodHelper(this).HasSameNameAndSignature(&result_mh));
+#endif
   return result;
 }
 
 uint32_t Method::ToDexPC(const uintptr_t pc) const {
   const uint32_t* mapping_table = GetMappingTable();
   if (mapping_table == NULL) {
-    DCHECK(IsNative() || IsCalleeSaveMethod()) << PrettyMethod(this);
+    DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
     return DexFile::kDexNoIndex;   // Special no mapping case
   }
   size_t mapping_table_length = GetMappingTableLength();
@@ -695,10 +485,8 @@
 }
 
 uint32_t Method::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const {
-  DexCache* dex_cache = GetDeclaringClass()->GetDexCache();
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-  const DexFile::CodeItem* code_item = dex_file.GetCodeItem(GetCodeItemOffset());
+  MethodHelper mh(this);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
   // Iterate over the catch handlers associated with dex_pc
   for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
     uint16_t iter_type_idx = it.GetHandlerTypeIndex();
@@ -707,11 +495,11 @@
       return it.GetHandlerAddress();
     }
     // Does this catch exception type apply?
-    Class* iter_exception_type = dex_cache->GetResolvedType(iter_type_idx);
+    Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
     if (iter_exception_type == NULL) {
       // The verifier should take care of resolving all exception classes early
       LOG(WARNING) << "Unresolved exception class when finding catch block: "
-          << dex_file.GetTypeDescriptor(dex_file.GetTypeId(iter_type_idx));
+          << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
     } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
       return it.GetHandlerAddress();
     }
@@ -819,8 +607,9 @@
   }
 
   Class* super = GetSuperClass();
+  ClassHelper kh(this);
   os << "----- " << (IsInterface() ? "interface" : "class") << " "
-     << "'" << GetDescriptor()->ToModifiedUtf8() << "' cl=" << GetClassLoader() << " -----\n",
+     << "'" << kh.GetDescriptor() << "' cl=" << GetClassLoader() << " -----\n",
   os << "  objectSize=" << SizeOf() << " "
      << "(" << (super != NULL ? super->SizeOf() : -1) << " from super)\n",
   os << StringPrintf("  access=0x%04x.%04x\n",
@@ -831,10 +620,10 @@
   if (IsArrayClass()) {
     os << "  componentType=" << PrettyClass(GetComponentType()) << "\n";
   }
-  if (NumInterfaces() > 0) {
-    os << "  interfaces (" << NumInterfaces() << "):\n";
-    for (size_t i = 0; i < NumInterfaces(); ++i) {
-      Class* interface = GetInterface(i);
+  if (kh.NumInterfaces() > 0) {
+    os << "  interfaces (" << kh.NumInterfaces() << "):\n";
+    for (size_t i = 0; i < kh.NumInterfaces(); ++i) {
+      Class* interface = kh.GetInterface(i);
       const ClassLoader* cl = interface->GetClassLoader();
       os << StringPrintf("    %2d: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl);
     }
@@ -963,11 +752,7 @@
   return false;
 }
 
-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());
-
+bool Class::IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2) {
   size_t i = 0;
   while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) {
     ++i;
@@ -1009,7 +794,11 @@
     klass2 = klass2->GetComponentType();
   }
   // Compare the package part of the descriptor string.
-  return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
+  ClassHelper kh(klass1);
+  std::string descriptor1 = kh.GetDescriptor();
+  kh.ChangeClass(klass2);
+  std::string descriptor2 = kh.GetDescriptor();
+  return IsInSamePackage(descriptor1, descriptor2);
 }
 
 bool Class::IsClassClass() const {
@@ -1018,8 +807,7 @@
 }
 
 bool Class::IsStringClass() const {
-  // TODO use "this == String::GetJavaLangString()" instead? or do we need this too early?
-  return this == GetDescriptor()->GetClass();
+  return this == String::GetJavaLangString();
 }
 
 ClassLoader* Class::GetClassLoader() const {
@@ -1047,8 +835,7 @@
   if (can_throw) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
         "Class %s does not implement interface %s",
-        PrettyDescriptor(GetDescriptor()).c_str(),
-        PrettyDescriptor(declaring_class->GetDescriptor()).c_str());
+        PrettyDescriptor(this).c_str(), PrettyDescriptor(declaring_class).c_str());
   }
   return NULL;
 }
@@ -1071,30 +858,13 @@
   return NULL;
 }
 
-Method* Class::FindInterfaceMethod(String* name,  String* signature) const {
-  // Check the current class before checking the interfaces.
-  Method* method = FindVirtualMethod(name, signature);
-  if (method != NULL) {
-    return method;
-  }
-  int32_t iftable_count = GetIfTableCount();
-  ObjectArray<InterfaceEntry>* iftable = GetIfTable();
-  for (int32_t i = 0; i < iftable_count; i++) {
-    Class* interface = iftable->Get(i)->GetInterface();
-    method = interface->FindVirtualMethod(name, signature);
-    if (method != NULL) {
-      return method;
-    }
-  }
-  return NULL;
-}
-
 Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
                                         const StringPiece& signature) {
+  MethodHelper mh;
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     Method* method = GetDirectMethod(i);
-    if (method->GetName()->Equals(name) &&
-        method->GetSignature()->Equals(signature)) {
+    mh.ChangeMethod(method);
+    if (name == mh.GetName() && signature == mh.GetSignature()) {
       return method;
     }
   }
@@ -1114,19 +884,11 @@
 
 Method* Class::FindDeclaredVirtualMethod(const StringPiece& name,
                                          const StringPiece& signature) const {
+  MethodHelper mh;
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     Method* method = GetVirtualMethod(i);
-    if (method->GetName()->Equals(name) && method->GetSignature()->Equals(signature)) {
-      return method;
-    }
-  }
-  return NULL;
-}
-
-Method* Class::FindDeclaredVirtualMethod(String* name, String* signature) const {
-  for (size_t i = 0; i < NumVirtualMethods(); ++i) {
-    Method* method = GetVirtualMethod(i);
-    if (method->GetName() == name && method->GetSignature() == signature) {
+    mh.ChangeMethod(method);
+    if (name == mh.GetName() && signature == mh.GetSignature()) {
       return method;
     }
   }
@@ -1143,35 +905,14 @@
   return NULL;
 }
 
-Method* Class::FindVirtualMethod(String* name, String* signature) const {
-  for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
-    Method* method = klass->FindDeclaredVirtualMethod(name, signature);
-    if (method != NULL) {
-      return method;
-    }
-  }
-  return NULL;
-}
-
 Field* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) {
   // Is the field in this class?
   // Interfaces are not relevant because they can't contain instance fields.
+  FieldHelper fh;
   for (size_t i = 0; i < NumInstanceFields(); ++i) {
     Field* f = GetInstanceField(i);
-    if (f->GetName()->Equals(name) &&
-        StringPiece(f->GetTypeDescriptor()) == type) {
-      return f;
-    }
-  }
-  return NULL;
-}
-
-Field* Class::FindDeclaredInstanceField(String* name, String* type) {
-  // Is the field in this class?
-  // Interfaces are not relevant because they can't contain instance fields.
-  for (size_t i = 0; i < NumInstanceFields(); ++i) {
-    Field* f = GetInstanceField(i);
-    if (f->GetName() == name && type->Equals(f->GetTypeDescriptor())) {
+    fh.ChangeField(f);
+    if (name == fh.GetName() && type == fh.GetTypeDescriptor()) {
       return f;
     }
   }
@@ -1190,34 +931,13 @@
   return NULL;
 }
 
-Field* Class::FindInstanceField(String* name, String* type) {
-  // Is the field in this class, or any of its superclasses?
-  // Interfaces are not relevant because they can't contain instance fields.
-  for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
-    Field* f = c->FindDeclaredInstanceField(name, type);
-    if (f != NULL) {
-      return f;
-    }
-  }
-  return NULL;
-}
-
 Field* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& type) {
   DCHECK(type != NULL);
+  FieldHelper fh;
   for (size_t i = 0; i < NumStaticFields(); ++i) {
     Field* f = GetStaticField(i);
-    if (f->GetName()->Equals(name) && StringPiece(f->GetTypeDescriptor()) == type) {
-      return f;
-    }
-  }
-  return NULL;
-}
-
-Field* Class::FindDeclaredStaticField(String* name, String* type) {
-  DCHECK(type != NULL);
-  for (size_t i = 0; i < NumStaticFields(); ++i) {
-    Field* f = GetStaticField(i);
-    if (f->GetName() == name && type->Equals(f->GetTypeDescriptor())) {
+    fh.ChangeField(f);
+    if (name == fh.GetName() && type == fh.GetTypeDescriptor()) {
       return f;
     }
   }
@@ -1247,29 +967,6 @@
   return NULL;
 }
 
-Field* Class::FindStaticField(String* name, String* type) {
-  // Is the field in this class (or its interfaces), or any of its
-  // superclasses (or their interfaces)?
-  for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
-    // Is the field in this class?
-    Field* f = c->FindDeclaredStaticField(name, type);
-    if (f != NULL) {
-      return f;
-    }
-
-    // Is this field in any of this class' interfaces?
-    for (int32_t i = 0; i < c->GetIfTableCount(); ++i) {
-      InterfaceEntry* interface_entry = c->GetIfTable()->Get(i);
-      Class* interface = interface_entry->GetInterface();
-      f = interface->FindDeclaredStaticField(name, type);
-      if (f != NULL) {
-        return f;
-      }
-    }
-  }
-  return NULL;
-}
-
 Array* Array::Alloc(Class* array_class, int32_t component_count, size_t component_size) {
   DCHECK(array_class != NULL);
   DCHECK_GE(component_count, 0);
@@ -1284,7 +981,7 @@
   if (data_size >> component_shift != size_t(component_count) || size < data_size) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/OutOfMemoryError;",
         "%s of length %zd exceeds the VM limit",
-        PrettyDescriptor(array_class->GetDescriptor()).c_str(), component_count);
+        PrettyDescriptor(array_class).c_str(), component_count);
     return NULL;
   }
 
@@ -1553,9 +1250,9 @@
   java_lang_StackTraceElement_ = NULL;
 }
 
-StackTraceElement* StackTraceElement::Alloc(const String* declaring_class,
-                                            const String* method_name,
-                                            const String* file_name,
+StackTraceElement* StackTraceElement::Alloc(String* declaring_class,
+                                            String* method_name,
+                                            String* file_name,
                                             int32_t line_number) {
   StackTraceElement* trace =
       down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject());
diff --git a/src/object.h b/src/object.h
index 82cd0a3..1a58364 100644
--- a/src/object.h
+++ b/src/object.h
@@ -97,6 +97,7 @@
 
 static const uint32_t kAccConstructor = 0x00010000;  // method (dex only)
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
+static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
 static const uint32_t kAccWritable = 0x80000000; // method (dex only)
 
 // Special runtime-only flags.
@@ -380,10 +381,6 @@
 
   void SetDeclaringClass(Class *new_declaring_class);
 
-  String* GetName() const;
-
-  void SetName(String* new_name);
-
   uint32_t GetAccessFlags() const;
 
   void SetAccessFlags(uint32_t new_access_flags) {
@@ -402,25 +399,13 @@
     return (GetAccessFlags() & kAccFinal) != 0;
   }
 
-  uint32_t GetTypeIdx() const;
+  uint32_t GetDexFieldIndex() const {
+    return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, field_dex_idx_), false);
+  }
 
-  void SetTypeIdx(uint32_t type_idx);
-
-  // Gets type using type index and resolved types in the dex cache, may be null
-  // if type isn't yet resolved
-  Class* GetTypeDuringLinking() const;
-
-  bool IsPrimitiveType() const;
-
-  Primitive::Type GetPrimitiveType() const;
-
-  size_t PrimitiveSize() const;
-
-  const char* GetTypeDescriptor() const;
-
-  // Performs full resolution, may return null and set exceptions if type cannot
-  // be resolved
-  Class* GetType();
+  void SetDexFieldIndex(uint32_t new_idx) {
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Field, field_dex_idx_), new_idx, false);
+  }
 
   // Offset to field within an Object
   MemberOffset GetOffset() const;
@@ -473,35 +458,19 @@
     return (GetAccessFlags() & kAccVolatile) != 0;
   }
 
-  void InitJavaFields();
-
  private:
-  void InitJavaFieldsLocked();
-
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
-
-  // The class in which this field is declared.
+  // The class we are a part of
   Class* declaring_class_;
 
-  Object* generic_type_;
-
-  String* name_;
-
-  // The possibly null type of the field
-  Class* type_;
-
-  uint32_t generic_types_are_initialized_;
-
   uint32_t access_flags_;
 
+  // Dex cache index of field id
+  uint32_t field_dex_idx_;
+
   // Offset of field within an instance or in the Class' static fields
   uint32_t offset_;
 
-  // Dex cache index of resolved type
-  uint32_t type_idx_;
-
-  int32_t slot_;
-
   static Class* java_lang_reflect_Field_;
 
   friend struct FieldOffsets;  // for verifying offset information
@@ -526,23 +495,6 @@
     return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_));
   }
 
-  // Returns the method name, e.g. "<init>" or "eatLunch"
-  String* GetName() const;
-
-  void SetName(String* new_name);
-
-  String* GetShorty() const;
-
-  void SetShorty(String* new_shorty);
-
-  String* GetSignature() const;
-
-  void SetSignature(String* new_signature);
-
-  bool HasSameNameAndSignature(const Method* that) const {
-    return GetName() == that->GetName() && GetSignature() == that->GetSignature();
-  }
-
   uint32_t GetAccessFlags() const;
 
   void SetAccessFlags(uint32_t new_access_flags) {
@@ -569,9 +521,6 @@
     return (GetAccessFlags() & kAccConstructor) != 0;
   }
 
-  // Is this method <clinit>
-  bool IsClassInitializer() const;
-
   // Returns true if the method is static, private, or a constructor.
   bool IsDirect() const {
     return IsStatic() || IsPrivate() || IsConstructor();
@@ -603,7 +552,7 @@
     return (GetAccessFlags() & kAccSynthetic) != 0;
   }
 
-  uint32_t GetDexMethodIndex() const;
+  bool IsProxyMethod() const;
 
   uint16_t GetMethodIndex() const;
 
@@ -630,28 +579,10 @@
   // Number of 32bit registers that would be required to hold all the arguments
   static size_t NumArgRegisters(const StringPiece& shorty);
 
-  uint16_t NumRegisters() const;
+  uint32_t GetDexMethodIndex() const;
 
-  void SetNumRegisters(uint16_t new_num_registers) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), new_num_registers, false);
-  }
-
-  uint16_t NumIns() const;
-
-  void SetNumIns(uint16_t new_num_ins) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), new_num_ins, false);
-  }
-
-  uint16_t NumOuts() const;
-
-  void SetNumOuts(uint16_t new_num_outs) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), new_num_outs, false);
-  }
-
-  uint32_t GetProtoIdx() const;
-
-  void SetProtoIdx(uint32_t new_proto_idx) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), new_proto_idx, false);
+  void SetDexMethodIndex(uint32_t new_idx) {
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_dex_index_), new_idx, false);
   }
 
   ObjectArray<String>* GetDexCacheStrings() const;
@@ -692,63 +623,6 @@
   // Find the method that this method overrides
   Method* FindOverriddenMethod() const;
 
-  void SetReturnTypeIdx(uint32_t new_return_type_idx);
-
-  const char* GetReturnTypeDescriptor() const;
-
-  Class* GetReturnType() const;
-
-  bool IsReturnAReference() const;
-
-  bool IsReturnAFloat() const;
-
-  bool IsReturnADouble() const;
-
-  bool IsReturnAFloatOrDouble() const {
-    return IsReturnAFloat() || IsReturnADouble();
-  }
-
-  bool IsReturnALong() const;
-
-  bool IsReturnALongOrDouble() const {
-    return IsReturnALong() || IsReturnADouble();
-  }
-
-  bool IsReturnVoid() const;
-
-  // "Args" may refer to any of the 3 levels of "Args."
-  // To avoid confusion, our code will denote which "Args" clearly:
-  //  1. UserArgs: Args that a user see.
-  //  2. Args: Logical JVM-level Args. E.g., the first in Args will be the
-  //       receiver.
-  //  3. CConvArgs: Calling Convention Args, which is physical-level Args.
-  //       E.g., the first in Args is Method* for both static and non-static
-  //       methods. And CConvArgs doesn't deal with the receiver because
-  //       receiver is hardwired in an implicit register, so CConvArgs doesn't
-  //       need to deal with it.
-  //
-  // The number of Args that should be supplied to this method
-  size_t NumArgs() const;
-
-  // The number of reference arguments to this method including implicit this
-  // pointer.
-  size_t NumReferenceArgs() const;
-
-  // The number of long or double arguments.
-  size_t NumLongOrDoubleArgs() const;
-
-  // Is the given method parameter a reference?
-  bool IsParamAReference(unsigned int param) const;
-
-  // Is the given method parameter a long or double?
-  bool IsParamALongOrDouble(unsigned int param) const;
-
-  // Size in bytes of the given parameter
-  size_t ParamSize(unsigned int param) const;
-
-  // Size in bytes of the return value
-  size_t ReturnSize() const;
-
   void Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
 
   const void* GetCode() const {
@@ -924,18 +798,6 @@
     SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), fp_spill_mask, false);
   }
 
-  ObjectArray<Class>* GetExceptionTypes() const {
-    return GetFieldObject<ObjectArray<Class>*>(
-        OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), false);
-  }
-
-  void SetExceptionTypes(ObjectArray<Class>* exception_types);
-
-  ObjectArray<Class>* GetJavaParameterTypes() const {
-    return GetFieldObject<ObjectArray<Class>*>(
-        OFFSET_OF_OBJECT_MEMBER(Method, java_parameter_types_), false);
-  }
-
   // Is this a hand crafted method used for something like describing callee saves?
   bool IsCalleeSaveMethod() const {
     Runtime* runtime = Runtime::Current();
@@ -974,26 +836,10 @@
 
   static void ResetClasses();
 
-  void InitJavaFields();
-
  private:
-  uint32_t GetReturnTypeIdx() const;
-  void InitJavaFieldsLocked();
-
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
-  // the class we are a part of
+  // The class we are a part of
   Class* declaring_class_;
-  ObjectArray<Class>* java_exception_types_; // TODO
-  Object* java_formal_type_parameters_;
-  Object* java_generic_exception_types_;
-  Object* java_generic_parameter_types_;
-  Object* java_generic_return_type_;
-
-  String* name_;
-
-  // Initialized by InitJavaFields.
-  ObjectArray<Class>* java_parameter_types_;
-  Class* java_return_type_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
@@ -1016,23 +862,6 @@
   // Garbage collection map
   Object* gc_map_;
 
-  // The short-form method descriptor string.
-  String* shorty_;
-
-  // The method descriptor.  This represents the parameters a method
-  // takes and value it returns.  This string is a list of the type
-  // descriptors for the parameters enclosed in parenthesis followed
-  // by the return type descriptor.  For example, for the method
-  //
-  //   Object mymethod(int i, double d, Thread t)
-  //
-  // the method descriptor would be
-  //
-  //   (IDLjava/lang/Thread;)Ljava/lang/Object;
-  String* signature_;
-
-  uint32_t java_generic_types_are_initialized_;
-
   // Access flags; low 16 bits are defined by spec.
   uint32_t access_flags_;
 
@@ -1055,13 +884,12 @@
   // Native invocation stub entry point for calling from native to managed code.
   const InvokeStub* invoke_stub_;
 
-  // Index of the return type in the declaring classes dex cache or dex file's type ids
-  // TODO: value is really just 16bit
-  uint32_t java_return_type_idx_;
-
   // Mapping from native pc to dex pc
   const uint32_t* mapping_table_;
 
+  // Index into method_ids of the dex file associated with this method
+  uint32_t method_dex_index_;
+
   // For concrete virtual methods, this is the offset of the method in Class::vtable_.
   //
   // For abstract methods in an interface class, this is the offset of the method in
@@ -1071,24 +899,11 @@
   // The target native method registered with this method
   const void* native_method_;
 
-  // Method bounds; not needed for an abstract method.
-  //
-  // For a native method, we compute the size of the argument list, and
-  // set "insSize" and "registerSize" equal to it.
-  uint32_t num_ins_;
-  uint32_t num_outs_;
-  uint32_t num_registers_;  // ins + locals
-
-  // Method prototype descriptor string (return and argument types).
-  uint32_t proto_idx_;
-
   // When a register is promoted into a register, the spill mask holds which registers hold dex
   // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth
   // is vmap_table_[N]. vmap_table_[0] holds the length of the table.
   const uint16_t* vmap_table_;
 
-  uint32_t java_slot_;
-
   static Class* java_lang_reflect_Constructor_;
   static Class* java_lang_reflect_Method_;
 
@@ -1351,6 +1166,17 @@
     return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
   }
 
+  String* GetName() const;
+  void SetName(String* name);
+
+  bool IsProxyClass() const {
+    // Read access flags without using getter as whether something is a proxy can be check in
+    // any loaded state
+    // TODO: switch to a check if the super class is java.lang.reflect.Proxy?
+    uint32_t access_flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
+    return (access_flags & kAccClassIsProxy) != 0;
+  }
+
   Primitive::Type GetPrimitiveType() const {
     DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
     return static_cast<Primitive::Type>(
@@ -1444,16 +1270,6 @@
   // Creates a raw object instance but does not invoke the default constructor.
   Object* AllocObject();
 
-  const String* GetDescriptor() const {
-    const String* result = GetFieldObject<const String*>(
-        OFFSET_OF_OBJECT_MEMBER(Class, descriptor_), false);
-    // DCHECK(result != NULL);  // may be NULL prior to class linker initialization
-    // DCHECK_NE(0, result->GetLength());  // TODO: keep?
-    return result;
-  }
-
-  void SetDescriptor(String* new_descriptor);
-
   bool IsVariableSize() const {
     // Classes and arrays vary in size, and so the object_size_ field cannot
     // be used to get their instance size
@@ -1489,15 +1305,15 @@
   // Returns true if this class is in the same packages as that class.
   bool IsInSamePackage(const Class* that) const;
 
-  static bool IsInSamePackage(const String* descriptor1, const String* descriptor2);
+  static bool IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2);
 
   // Returns true if this class can access that class.
-  bool CanAccess(const Class* that) const {
+  bool CanAccess(Class* that) const {
     return that->IsPublic() || this->IsInSamePackage(that);
   }
 
   // Validate method/field access.
-  bool CanAccessMember(const Class* access_to, uint32_t member_flags) const {
+  bool CanAccessMember(Class* access_to, uint32_t member_flags) const {
     // quick accept for public access
     if (member_flags & kAccPublic) {
       return true;
@@ -1556,10 +1372,6 @@
     return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
   }
 
-  static MemberOffset SuperClassOffset() {
-    return MemberOffset(OFFSETOF_MEMBER(Class, super_class_));
-  }
-
   void SetSuperClass(Class *new_super_class) {
     // super class is assigned once, except during class linker initialization
     Class* old_super_class = GetFieldObject<Class*>(
@@ -1573,14 +1385,8 @@
     return GetSuperClass() != NULL;
   }
 
-  uint32_t GetSuperClassTypeIdx() const {
-    DCHECK(IsIdxLoaded() || IsErroneous());
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
-                      false);
-  }
-
-  void SetSuperClassTypeIdx(int32_t new_super_class_idx) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_), new_super_class_idx, false);
+  static MemberOffset SuperClassOffset() {
+    return MemberOffset(OFFSETOF_MEMBER(Class, super_class_));
   }
 
   ClassLoader* GetClassLoader() const;
@@ -1703,7 +1509,6 @@
   Method* FindVirtualMethodForInterface(Method* method, bool can_throw);
 
   Method* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const;
-  Method* FindInterfaceMethod(String* name, String* descriptor) const;
 
   Method* FindVirtualMethodForVirtualOrInterface(Method* method) {
     if (method->IsDirect()) {
@@ -1716,10 +1521,8 @@
   }
 
   Method* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const;
-  Method* FindDeclaredVirtualMethod(String* name, String* signature) const;
 
   Method* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const;
-  Method* FindVirtualMethod(String* name, String* descriptor) const;
 
   Method* FindDeclaredDirectMethod(const StringPiece& name,
                                    const StringPiece& signature);
@@ -1727,43 +1530,6 @@
   Method* FindDirectMethod(const StringPiece& name,
                            const StringPiece& signature);
 
-  size_t NumInterfaces() const {
-    CHECK(IsIdxLoaded() || IsErroneous()); // used during loading
-    ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>(
-        OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
-    return (interfaces != NULL) ? interfaces->GetLength() : 0;
-  }
-
-  IntArray* GetInterfacesTypeIdx() const {
-    CHECK(IsIdxLoaded() || IsErroneous());
-    return GetFieldObject<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false);
-  }
-
-  void SetInterfacesTypeIdx(IntArray* new_interfaces_idx);
-
-  ObjectArray<Class>* GetInterfaces() const {
-    CHECK(IsLoaded() || IsErroneous());
-    return GetFieldObject<ObjectArray<Class>*>(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
-  }
-
-  void SetInterfaces(ObjectArray<Class>* new_interfaces) {
-    DCHECK(NULL == GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false));
-    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), new_interfaces, false);
-  }
-
-  void SetInterface(uint32_t i, Class* f) {  // TODO: uint16_t
-    DCHECK_LT(i, NumInterfaces());
-    ObjectArray<Class>* interfaces =
-        GetFieldObject<ObjectArray<Class>*>(
-            OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
-    interfaces->Set(i, f);
-  }
-
-  Class* GetInterface(uint32_t i) const {
-    DCHECK_LT(i, NumInterfaces());
-    return GetInterfaces()->Get(i);
-  }
-
   int32_t GetIfTableCount() const {
     ObjectArray<InterfaceEntry>* iftable = GetIfTable();
     if (iftable == NULL) {
@@ -1890,17 +1656,13 @@
 
   // Finds the given instance field in this class or a superclass.
   Field* FindInstanceField(const StringPiece& name, const StringPiece& type);
-  Field* FindInstanceField(String* name, String* type);
 
   Field* FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type);
-  Field* FindDeclaredInstanceField(String* name, String* type);
 
   // Finds the given static field in this class or a superclass.
   Field* FindStaticField(const StringPiece& name, const StringPiece& type);
-  Field* FindStaticField(String* name, String* type);
 
   Field* FindDeclaredStaticField(const StringPiece& name, const StringPiece& type);
-  Field* FindDeclaredStaticField(String* name, String* type);
 
   pid_t GetClinitThreadId() const {
     DCHECK(IsIdxLoaded() || IsErroneous());
@@ -1920,26 +1682,14 @@
     klass->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
   }
 
-  uint32_t GetAnnotationsOffset() {
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, annotations_offset_), false);
+  uint16_t GetDexTypeIndex() const {
+    return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false);
   }
 
-  void SetAnnotationsOffset(uint32_t annotations_offset) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, annotations_offset_), annotations_offset, false);
+  void SetDexTypeIndex(uint16_t type_idx) {
+    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false);
   }
 
-  uint32_t GetTypeIdx() {
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, type_idx_), false);
-  }
-
-  void SetTypeIdx(uint32_t type_idx) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, type_idx_), type_idx, false);
-  }
-
-  String* GetSourceFile() const;
-
-  void SetSourceFile(String* new_source_file);
-
  private:
   bool Implements(const Class* klass) const;
   bool IsArrayAssignableFromArray(const Class* klass) const;
@@ -1955,9 +1705,6 @@
   // (for String[][][], this will be String[][]). NULL for non-array classes.
   Class* component_type_;
 
-  // descriptor for the class such as "Ljava/lang/Class;" or "[C"
-  String* descriptor_;
-
   // DexCache of resolved constant pool entries
   // (will be NULL for VM-generated, e.g. arrays and primitive classes)
   DexCache* dex_cache_;
@@ -1992,20 +1739,9 @@
   // of the concrete vtable_ methods for the methods in the interface.
   ObjectArray<InterfaceEntry>* iftable_;
 
-  // array of interfaces this class implements directly
-  // see also interfaces_type_idx_
-  ObjectArray<Class>* interfaces_;
-
-  // array of type_idx's for interfaces this class implements directly
-  // see also interfaces_
-  IntArray* interfaces_type_idx_;
-
   // Static fields
   ObjectArray<Field>* sfields_;
 
-  // source file name, if known.  Otherwise, NULL.
-  String* source_file_;
-
   // The superclass, or NULL if this is java.lang.Object or a
   // primitive type.
   // see also super_class_type_idx_;
@@ -2023,12 +1759,13 @@
   // virtual_ methods_ for miranda methods.
   ObjectArray<Method>* vtable_;
 
+  // type index from dex file
+  // TODO: really 16bits
+  uint32_t dex_type_idx_;
+
   // access flags; low 16 bits are defined by VM spec
   uint32_t access_flags_;
 
-  // annotation directory offset from dex file
-  uint32_t annotations_offset_;
-
   // Total size of the Class instance; used when allocating storage on gc heap.
   // See also object_size_.
   size_t class_size_;
@@ -2059,15 +1796,6 @@
   // state of class initialization
   Status status_;
 
-  // Set in LoadClass, used to LinkClass
-  // see also super_class_
-  // TODO: really 16bits
-  uint32_t super_class_type_idx_;
-
-  // type index from dex file
-  // TODO: really 16bits
-  uint32_t type_idx_;
-
   // TODO: ?
   // initiating class loader list
   // NOTE: for classes with low serialNumber, these are unused, and the
@@ -2187,32 +1915,6 @@
   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), new_declaring_class, false);
 }
 
-inline uint32_t Method::GetReturnTypeIdx() const {
-  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_), false);
-}
-
-inline bool Method::IsReturnAReference() const {
-  char d = GetReturnTypeDescriptor()[0];
-  return d == 'L' || d == '[';
-}
-
-inline bool Method::IsReturnAFloat() const {
-  return GetReturnTypeDescriptor()[0] == 'F';
-}
-
-inline bool Method::IsReturnADouble() const {
-  return GetReturnTypeDescriptor()[0] == 'D';
-}
-
-inline bool Method::IsReturnALong() const {
-  return GetReturnTypeDescriptor()[0] == 'J';
-}
-
-inline bool Method::IsReturnVoid() const {
-  return GetReturnTypeDescriptor()[0] == 'V';
-}
-
 inline size_t Array::SizeOf() const {
   // This is safe from overflow because the array was already allocated, so we know it's sane.
   return sizeof(Array) + GetLength() * GetClass()->GetComponentSize();
@@ -2309,14 +2011,6 @@
 class MANAGED FieldClass : public Class {
  private:
   Object* ORDER_BY_NAME_AND_DECLARING_CLASS_;
-  uint32_t TYPE_BOOLEAN_;
-  uint32_t TYPE_BYTE_;
-  uint32_t TYPE_CHAR_;
-  uint32_t TYPE_DOUBLE_;
-  uint32_t TYPE_FLOAT_;
-  uint32_t TYPE_INTEGER_;
-  uint32_t TYPE_LONG_;
-  uint32_t TYPE_SHORT_;
   friend struct FieldClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(FieldClass);
 };
@@ -2377,13 +2071,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
 };
 
-inline void Class::SetInterfacesTypeIdx(IntArray* new_interfaces_idx) {
-  DCHECK(NULL == GetFieldObject<IntArray*>(
-      OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false));
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_),
-                 new_interfaces_idx, false);
-}
-
 // C++ mirror of java.lang.String
 class MANAGED String : public Object {
  public:
@@ -2500,27 +2187,11 @@
   }
 };
 
-inline String* Field::GetName() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  String* result = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Field, name_), false);
-  DCHECK(result != NULL);
-  return result;
-}
-
-inline void Field::SetName(String* new_name) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, name_), new_name, false);
-}
-
 inline uint32_t Field::GetAccessFlags() const {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), false);
 }
 
-inline uint32_t Field::GetTypeIdx() const {
-  DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), false);
-}
-
 inline MemberOffset Field::GetOffset() const {
   DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
   return MemberOffset(GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
@@ -2531,43 +2202,6 @@
   return MemberOffset(GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
 }
 
-inline String* Method::GetName() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  String* result = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
-  DCHECK(result != NULL);
-  return result;
-}
-
-inline void Method::SetName(String* new_name) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, name_), new_name, false);
-}
-
-inline String* Method::GetShorty() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
-}
-
-inline void Method::SetShorty(String* new_shorty) {
-  DCHECK(NULL == GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false));
-  DCHECK_LE(1, new_shorty->GetLength());
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), new_shorty, false);
-}
-
-inline String* Method::GetSignature() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  String* result = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
-  DCHECK(result != NULL);
-  return result;
-}
-
-inline void Method::SetSignature(String* new_signature) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, signature_), new_signature, false);
-}
-
-inline void Method::SetExceptionTypes(ObjectArray<Class>* exception_types) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), exception_types, false);
-}
-
 inline uint32_t Class::GetAccessFlags() const {
   // Check class is loaded or this is java.lang.String that has a
   // circularity issue during loading the names of its members
@@ -2579,23 +2213,6 @@
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
 }
 
-inline void Class::SetDescriptor(String* new_descriptor) {
-  DCHECK(GetDescriptor() == NULL);
-  DCHECK(new_descriptor != NULL);
-  DCHECK_NE(0, new_descriptor->GetLength());
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, descriptor_),
-                 new_descriptor, false);
-}
-
-inline String* Class::GetSourceFile() const {
-  DCHECK(IsLoaded() || IsErroneous());
-  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()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
@@ -2606,24 +2223,16 @@
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), false);
 }
 
-inline uint16_t Method::NumRegisters() const {
+inline uint32_t Method::GetDexMethodIndex() const {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), false);
+  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_dex_index_), false);
 }
 
-inline uint16_t Method::NumIns() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), false);
+inline String* Class::GetName() const {
+  return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false);
 }
-
-inline uint16_t Method::NumOuts() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), false);
-}
-
-inline uint32_t Method::GetProtoIdx() const {
-  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-  return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), false);
+inline void Class::SetName(String* name) {
+  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
 }
 
 // C++ mirror of java.lang.Throwable
@@ -2675,9 +2284,9 @@
         OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_), false);
   }
 
-  static StackTraceElement* Alloc(const String* declaring_class,
-                                  const String* method_name,
-                                  const String* file_name,
+  static StackTraceElement* Alloc(String* declaring_class,
+                                  String* method_name,
+                                  String* file_name,
                                   int32_t line_number);
 
   static void SetClass(Class* java_lang_StackTraceElement);
@@ -2686,9 +2295,9 @@
 
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
-  const String* declaring_class_;
-  const String* file_name_;
-  const String* method_name_;
+  String* declaring_class_;
+  String* file_name_;
+  String* method_name_;
   int32_t line_number_;
 
   static Class* GetStackTraceElement() {
@@ -2719,7 +2328,7 @@
 
   size_t GetMethodArrayCount() const {
     ObjectArray<Method>* method_array = down_cast<ObjectArray<Method>*>(Get(kMethodArray));
-    if (method_array == 0) {
+    if (method_array == NULL) {
       return 0;
     }
     return method_array->GetLength();
diff --git a/src/object_test.cc b/src/object_test.cc
index 08abb6f..b1d5885 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -42,18 +42,12 @@
 
 TEST_F(ObjectTest, IsInSamePackage) {
   // Matches
-  SirtRef<String> Object_descriptor(String::AllocFromModifiedUtf8("Ljava/lang/Object;"));
-  SirtRef<String> Class_descriptor(String::AllocFromModifiedUtf8("Ljava/lang/Class;"));
-  EXPECT_TRUE(Class::IsInSamePackage(Object_descriptor.get(), Class_descriptor.get()));
-  SirtRef<String> Foo_descriptor(String::AllocFromModifiedUtf8("LFoo;"));
-  SirtRef<String> Bar_descriptor(String::AllocFromModifiedUtf8("LBar;"));
-  EXPECT_TRUE(Class::IsInSamePackage(Foo_descriptor.get(), Bar_descriptor.get()));
+  EXPECT_TRUE(Class::IsInSamePackage("Ljava/lang/Object;", "Ljava/lang/Class;"));
+  EXPECT_TRUE(Class::IsInSamePackage("LFoo;", "LBar;"));
 
   // Mismatches
-  SirtRef<String> File_descriptor(String::AllocFromModifiedUtf8("Ljava/io/File;"));
-  EXPECT_FALSE(Class::IsInSamePackage(Object_descriptor.get(), File_descriptor.get()));
-  SirtRef<String> Method_descriptor(String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;"));
-  EXPECT_FALSE(Class::IsInSamePackage(Object_descriptor.get(), Method_descriptor.get()));
+  EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;", "Ljava/io/File;"));
+  EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;", "Ljava/lang/reflect/Method;"));
 }
 
 TEST_F(ObjectTest, Clone) {
@@ -90,11 +84,10 @@
   self->ClearException();
 
   ASSERT_TRUE(oa->GetClass() != NULL);
-  ASSERT_EQ(2U, oa->GetClass()->NumInterfaces());
-  EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Cloneable;"),
-            oa->GetClass()->GetInterface(0));
-  EXPECT_EQ(class_linker_->FindSystemClass("Ljava/io/Serializable;"),
-            oa->GetClass()->GetInterface(1));
+  ClassHelper oa_ch(oa->GetClass());
+  ASSERT_EQ(2U, oa_ch.NumInterfaces());
+  EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Cloneable;"), oa_ch.GetInterface(0));
+  EXPECT_EQ(class_linker_->FindSystemClass("Ljava/io/Serializable;"), oa_ch.GetInterface(1));
 }
 
 TEST_F(ObjectTest, AllocArray) {
@@ -288,34 +281,50 @@
   ASSERT_TRUE(klass2 != NULL);
 
   Method* m1_1 = klass1->GetVirtualMethod(0);
-  EXPECT_TRUE(m1_1->GetName()->Equals("m1"));
+  MethodHelper mh(m1_1);
+  EXPECT_STREQ(mh.GetName(), "m1");
   Method* m2_1 = klass1->GetVirtualMethod(1);
-  EXPECT_TRUE(m2_1->GetName()->Equals("m2"));
+  mh.ChangeMethod(m2_1);
+  EXPECT_STREQ(mh.GetName(), "m2");
   Method* m3_1 = klass1->GetVirtualMethod(2);
-  EXPECT_TRUE(m3_1->GetName()->Equals("m3"));
+  mh.ChangeMethod(m3_1);
+  EXPECT_STREQ(mh.GetName(), "m3");
   Method* m4_1 = klass1->GetVirtualMethod(3);
-  EXPECT_TRUE(m4_1->GetName()->Equals("m4"));
+  mh.ChangeMethod(m4_1);
+  EXPECT_STREQ(mh.GetName(), "m4");
 
   Method* m1_2 = klass2->GetVirtualMethod(0);
-  EXPECT_TRUE(m1_2->GetName()->Equals("m1"));
+  mh.ChangeMethod(m1_2);
+  EXPECT_STREQ(mh.GetName(), "m1");
   Method* m2_2 = klass2->GetVirtualMethod(1);
-  EXPECT_TRUE(m2_2->GetName()->Equals("m2"));
+  mh.ChangeMethod(m2_2);
+  EXPECT_STREQ(mh.GetName(), "m2");
   Method* m3_2 = klass2->GetVirtualMethod(2);
-  EXPECT_TRUE(m3_2->GetName()->Equals("m3"));
+  mh.ChangeMethod(m3_2);
+  EXPECT_STREQ(mh.GetName(), "m3");
   Method* m4_2 = klass2->GetVirtualMethod(3);
-  EXPECT_TRUE(m4_2->GetName()->Equals("m4"));
+  mh.ChangeMethod(m4_2);
+  EXPECT_STREQ(mh.GetName(), "m4");
 
-  EXPECT_TRUE(m1_1->HasSameNameAndSignature(m1_2));
-  EXPECT_TRUE(m1_2->HasSameNameAndSignature(m1_1));
+  mh.ChangeMethod(m1_1);
+  MethodHelper mh2(m1_2);
+  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
+  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 
-  EXPECT_TRUE(m2_1->HasSameNameAndSignature(m2_2));
-  EXPECT_TRUE(m2_2->HasSameNameAndSignature(m2_1));
+  mh.ChangeMethod(m2_1);
+  mh2.ChangeMethod(m2_2);
+  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
+  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 
-  EXPECT_TRUE(m3_1->HasSameNameAndSignature(m3_2));
-  EXPECT_TRUE(m3_2->HasSameNameAndSignature(m3_1));
+  mh.ChangeMethod(m3_1);
+  mh2.ChangeMethod(m3_2);
+  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
+  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 
-  EXPECT_TRUE(m4_1->HasSameNameAndSignature(m4_2));
-  EXPECT_TRUE(m4_2->HasSameNameAndSignature(m4_1));
+  mh.ChangeMethod(m4_1);
+  mh2.ChangeMethod(m4_2);
+  EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
+  EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 }
 
 
diff --git a/src/object_utils.h b/src/object_utils.h
new file mode 100644
index 0000000..dc48aa0
--- /dev/null
+++ b/src/object_utils.h
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_OBJECT_UTILS_H_
+#define ART_SRC_OBJECT_UTILS_H_
+
+#include "class_linker.h"
+#include "dex_cache.h"
+#include "dex_file.h"
+#include "object.h"
+#include "runtime.h"
+
+#include <string>
+
+namespace art {
+
+class ClassHelper {
+ public:
+  ClassHelper() : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL),
+      interface_type_list_(NULL), klass_(NULL) {}
+  ClassHelper(const Class* c) : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL),
+      dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
+  ClassHelper(const Class* c, ClassLinker* l) : class_def_(NULL), class_linker_(l),
+      dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
+
+  void ChangeClass(const Class* new_c) {
+    DCHECK(new_c != NULL);
+    if (dex_cache_ != NULL) {
+      DexCache* new_c_dex_cache = new_c->GetDexCache();
+      if (new_c_dex_cache != dex_cache_) {
+        dex_cache_ = new_c_dex_cache;
+        dex_file_ = NULL;
+      }
+    }
+    klass_ = new_c;
+    interface_type_list_ = NULL;
+    class_def_ = NULL;
+  }
+
+  std::string GetDescriptor() {
+    if (klass_->IsArrayClass()) {
+      std::string result = "[";
+      const Class* saved_klass = klass_;
+      ChangeClass(klass_->GetComponentType());
+      result += GetDescriptor();
+      ChangeClass(saved_klass);
+      return result;
+    } else if (klass_->IsPrimitive()){
+      std::string result;
+      result += Primitive::DescriptorChar(klass_->GetPrimitiveType());
+      return result;
+    } else if (klass_->IsProxyClass()) {
+      return GetClassLinker()->GetDescriptorForProxy(klass_);
+    } else {
+      const DexFile& dex_file = GetDexFile();
+      const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex());
+      return dex_file.GetTypeDescriptor(type_id);
+    }
+  }
+  const DexFile::ClassDef* GetClassDef() {
+    const DexFile::ClassDef* result = class_def_;
+    if (result == NULL) {
+      result = GetDexFile().FindClassDef(GetDescriptor());
+      class_def_ = result;
+    }
+    return result;
+  }
+  uint32_t NumInterfaces() {
+    if (klass_->IsPrimitive()) {
+      return 0;
+    } else if (klass_->IsArrayClass()) {
+      return 2;
+    } else {
+      CHECK(!klass_->IsProxyClass());
+      const DexFile::TypeList* interfaces = GetInterfaceTypeList();
+      if (interfaces == NULL) {
+        return 0;
+      } else {
+        return interfaces->Size();
+      }
+    }
+  }
+  uint16_t GetInterfaceTypeIdx(uint32_t idx) {
+    DCHECK(!klass_->IsPrimitive());
+    DCHECK(!klass_->IsArrayClass());
+    return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
+  }
+  Class* GetInterface(uint32_t idx) {
+    DCHECK(!klass_->IsPrimitive());
+    if (klass_->IsArrayClass()) {
+      if (idx == 0) {
+        return GetClassLinker()->FindSystemClass("Ljava/lang/Cloneable;");
+      } else {
+        DCHECK_EQ(1U, idx);
+        return GetClassLinker()->FindSystemClass("Ljava/io/Serializable;");
+      }
+    } else {
+      uint16_t type_idx = GetInterfaceTypeIdx(idx);
+      Class* interface = GetDexCache()->GetResolvedType(type_idx);
+      if (interface == NULL) {
+        interface = GetClassLinker()->ResolveType(GetDexFile(), type_idx, klass_);
+        CHECK(interface != NULL || Thread::Current()->IsExceptionPending());
+      }
+      return interface;
+    }
+  }
+  const char* GetSourceFile() {
+    std::string descriptor = GetDescriptor();
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
+    if (dex_class_def == NULL) {
+      return NULL;
+    } else {
+      return dex_file.GetSourceFile(*dex_class_def);
+    }
+  }
+  std::string GetLocation() {
+    return GetDexCache()->GetLocation()->ToModifiedUtf8();
+  }
+
+  const DexFile& GetDexFile() {
+    const DexFile* result = dex_file_;
+    if (result == NULL) {
+      const DexCache* dex_cache = GetDexCache();
+      result = &GetClassLinker()->FindDexFile(dex_cache);
+      dex_file_ = result;
+    }
+    return *result;
+  }
+
+ private:
+  const DexFile::TypeList* GetInterfaceTypeList() {
+    const DexFile::TypeList* result = interface_type_list_;
+    if (result == NULL) {
+      const DexFile::ClassDef* class_def = GetClassDef();
+      if (class_def != NULL) {
+        result =  GetDexFile().GetInterfacesList(*class_def);
+        interface_type_list_ = result;
+      }
+    }
+    return result;
+  }
+  DexCache* GetDexCache() {
+    DexCache* result = dex_cache_;
+    if (result == NULL) {
+      result = klass_->GetDexCache();
+      dex_cache_ = result;
+    }
+    return result;
+  }
+  ClassLinker* GetClassLinker() {
+    ClassLinker* result = class_linker_;
+    if (result == NULL) {
+      result = Runtime::Current()->GetClassLinker();
+      class_linker_ = result;
+    }
+    return result;
+  }
+
+  const DexFile::ClassDef* class_def_;
+  ClassLinker* class_linker_;
+  DexCache* dex_cache_;
+  const DexFile* dex_file_;
+  const DexFile::TypeList* interface_type_list_;
+  const Class* klass_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClassHelper);
+};
+
+class FieldHelper {
+ public:
+  FieldHelper() : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), field_(NULL) {}
+  FieldHelper(const Field* f) : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), field_(f) {}
+  FieldHelper(const Field* f, ClassLinker* l) : class_linker_(l), dex_cache_(NULL), dex_file_(NULL),
+      field_(f) {}
+
+  void ChangeField(const Field* new_f) {
+    DCHECK(new_f != NULL);
+    if (dex_cache_ != NULL) {
+      DexCache* new_f_dex_cache = new_f->GetDeclaringClass()->GetDexCache();
+      if (new_f_dex_cache != dex_cache_) {
+        dex_cache_ = new_f_dex_cache;
+        dex_file_ = NULL;
+      }
+    }
+    field_ = new_f;
+  }
+  const char* GetName() {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetFieldName(dex_file.GetFieldId(field_->GetDexFieldIndex()));
+  }
+  String* GetNameAsString() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
+    return GetClassLinker()->ResolveString(dex_file, field_id.name_idx_, GetDexCache());
+  }
+  Class* GetType() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
+    Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
+    if (type == NULL) {
+      type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
+      CHECK(type != NULL || Thread::Current()->IsExceptionPending());
+    }
+    return type;
+  }
+  const char* GetTypeDescriptor() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
+    return dex_file.GetFieldTypeDescriptor(field_id);
+  }
+  Primitive::Type GetTypeAsPrimitiveType() {
+    return Primitive::GetType(GetTypeDescriptor()[0]);
+  }
+  bool IsPrimitiveType() {
+    Primitive::Type type = GetTypeAsPrimitiveType();
+    return type != Primitive::kPrimNot;
+  }
+  size_t FieldSize() {
+    Primitive::Type type = GetTypeAsPrimitiveType();
+    return Primitive::FieldSize(type);
+  }
+  const char* GetDeclaringClassDescriptor() {
+    uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex();
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
+  }
+
+ private:
+  DexCache* GetDexCache() {
+    DexCache* result = dex_cache_;
+    if (result == NULL) {
+      result = field_->GetDeclaringClass()->GetDexCache();
+      dex_cache_ = result;
+    }
+    return result;
+  }
+  ClassLinker* GetClassLinker() {
+    ClassLinker* result = class_linker_;
+    if (result == NULL) {
+      result = Runtime::Current()->GetClassLinker();
+      class_linker_ = result;
+    }
+    return result;
+  }
+  const DexFile& GetDexFile() {
+    const DexFile* result = dex_file_;
+    if (result == NULL) {
+      const DexCache* dex_cache = GetDexCache();
+      result = &GetClassLinker()->FindDexFile(dex_cache);
+      dex_file_ = result;
+    }
+    return *result;
+  }
+
+  ClassLinker* class_linker_;
+  DexCache* dex_cache_;
+  const DexFile* dex_file_;
+  const Field* field_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldHelper);
+};
+
+class MethodHelper {
+ public:
+  MethodHelper() : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), method_(NULL),
+      shorty_(NULL), shorty_len_(0) {}
+  MethodHelper(const Method* m) : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL),
+      method_(NULL), shorty_(NULL), shorty_len_(0) {
+    SetMethod(m);
+  }
+  MethodHelper(const Method* m, ClassLinker* l) : class_linker_(l), dex_cache_(NULL),
+      dex_file_(NULL), method_(NULL), shorty_(NULL), shorty_len_(0) {
+    SetMethod(m);
+  }
+
+  void ChangeMethod(Method* new_m) {
+    DCHECK(new_m != NULL);
+    if (dex_cache_ != NULL) {
+      Class* klass = new_m->GetDeclaringClass();
+      if (klass->IsProxyClass()) {
+        dex_cache_ = NULL;
+        dex_file_ = NULL;
+      } else {
+        DexCache* new_m_dex_cache = klass->GetDexCache();
+        if (new_m_dex_cache != dex_cache_) {
+          dex_cache_ = new_m_dex_cache;
+          dex_file_ = NULL;
+        }
+      }
+    }
+    SetMethod(new_m);
+    shorty_ = NULL;
+  }
+  const char* GetName() {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetMethodName(dex_file.GetMethodId(method_->GetDexMethodIndex()));
+  }
+  String* GetNameAsString() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
+    return GetClassLinker()->ResolveString(dex_file, method_id.name_idx_, GetDexCache());
+  }
+  const char* GetShorty() {
+    const char* result = shorty_;
+    if (result == NULL) {
+      const DexFile& dex_file = GetDexFile();
+      result = dex_file.GetMethodShorty(dex_file.GetMethodId(method_->GetDexMethodIndex()),
+                                        &shorty_len_);
+      shorty_ = result;
+    }
+    return result;
+  }
+  int32_t GetShortyLength() {
+    if (shorty_ == NULL) {
+      GetShorty();
+    }
+    return shorty_len_;
+  }
+  const std::string GetSignature() {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetMethodSignature(dex_file.GetMethodId(method_->GetDexMethodIndex()));
+  }
+  const DexFile::ProtoId& GetPrototype() {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex()));
+  }
+  const DexFile::TypeList* GetParameterTypeList() {
+    const DexFile::ProtoId& proto = GetPrototype();
+    return GetDexFile().GetProtoParameters(proto);
+  }
+  ObjectArray<Class>* GetParameterTypes() {
+    const DexFile::TypeList* params = GetParameterTypeList();
+    Class* array_class = GetClassLinker()->FindSystemClass("[Ljava/lang/Class;");
+    uint32_t num_params = params == NULL ? 0 : params->Size();
+    ObjectArray<Class>* result = ObjectArray<Class>::Alloc(array_class, num_params);
+    for (uint32_t i = 0; i < num_params; i++) {
+      Class* param_type = GetClassFromTypeIdx(params->GetTypeItem(i).type_idx_);
+      result->Set(i, param_type);
+    }
+    return result;
+  }
+  Class* GetReturnType() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
+    const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id);
+    uint16_t return_type_idx = proto_id.return_type_idx_;
+    return GetClassFromTypeIdx(return_type_idx);
+  }
+  const char* GetReturnTypeDescriptor() {
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
+    const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id);
+    uint16_t return_type_idx = proto_id.return_type_idx_;
+    return dex_file.GetTypeDescriptor(dex_file.GetTypeId(return_type_idx));
+  }
+  int32_t GetLineNumFromNativePC(uintptr_t raw_pc) {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetLineNumFromPC(method_, method_->ToDexPC(raw_pc));
+  }
+  const char* GetDeclaringClassDescriptor() {
+    Class* klass = method_->GetDeclaringClass();
+    CHECK(!klass->IsProxyClass());
+    uint16_t type_idx = klass->GetDexTypeIndex();
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
+  }
+  const char* GetDeclaringClassSourceFile() {
+    const char* descriptor = GetDeclaringClassDescriptor();
+    const DexFile& dex_file = GetDexFile();
+    const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
+    if (dex_class_def == NULL) {
+      return NULL;
+    } else {
+      return dex_file.GetSourceFile(*dex_class_def);
+    }
+  }
+  bool IsStatic() {
+    return method_->IsStatic();
+  }
+  bool IsClassInitializer() {
+    return IsStatic() && StringPiece(GetName()) == "<clinit>";
+  }
+  size_t NumArgs() {
+    // "1 +" because the first in Args is the receiver.
+    // "- 1" because we don't count the return type.
+    return (IsStatic() ? 0 : 1) + GetShortyLength() - 1;
+  }
+  // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods
+  bool IsParamALongOrDouble(size_t param) {
+    CHECK_LT(param, NumArgs());
+    if (IsStatic()) {
+      param++;  // 0th argument must skip return value at start of the shorty
+    } else if (param == 0) {
+      return false;  // this argument
+    }
+    char ch = GetShorty()[param];
+    return (ch == 'J' || ch == 'D');
+  }
+  // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods
+  bool IsParamAReference(size_t param) {
+    CHECK_LT(param, NumArgs());
+    if (IsStatic()) {
+      param++;  // 0th argument must skip return value at start of the shorty
+    } else if (param == 0) {
+      return true;  // this argument
+    }
+    return GetShorty()[param] == 'L';  // An array also has a shorty character of 'L' (not '[')
+  }
+  bool HasSameNameAndSignature(MethodHelper* other) {
+    StringPiece name(GetName());
+    StringPiece other_name(other->GetName());
+    if (name != other_name) {
+      return false;
+    }
+    if (GetDexCache() == other->GetDexCache()) {
+      const DexFile& dex_file = GetDexFile();
+      const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex());
+      const DexFile::MethodId& other_mid =
+          dex_file.GetMethodId(other->method_->GetDexMethodIndex());
+      return mid.proto_idx_ == other_mid.proto_idx_;
+    }
+    return GetSignature() == other->GetSignature();
+  }
+  const DexFile::CodeItem* GetCodeItem() {
+    return GetDexFile().GetCodeItem(method_->GetCodeItemOffset());
+  }
+  Class* GetClassFromTypeIdx(uint16_t type_idx) {
+    Class* type = method_->GetDexCacheResolvedTypes()->Get(type_idx);
+    if (type == NULL) {
+      type = GetClassLinker()->ResolveType(type_idx, method_);
+      CHECK(type != NULL || Thread::Current()->IsExceptionPending());
+    }
+    return type;
+  }
+  const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
+    const DexFile& dex_file = GetDexFile();
+    return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
+  }
+  Class* GetDexCacheResolvedType(uint16_t type_idx) {
+    return GetDexCache()->GetResolvedType(type_idx);
+  }
+  const DexFile& GetDexFile() {
+    const DexFile* result = dex_file_;
+    if (result == NULL) {
+      const DexCache* dex_cache = GetDexCache();
+      result = &GetClassLinker()->FindDexFile(dex_cache);
+      dex_file_ = result;
+    }
+    return *result;
+  }
+ private:
+  // Set the method_ field, for proxy methods looking up the interface method via the resolved
+  // methods table.
+  void SetMethod(const Method* method) {
+    if (method != NULL) {
+      Class* klass = method->GetDeclaringClass();
+      if (klass->IsProxyClass()) {
+        method = method->GetDexCacheResolvedMethods()->Get(method->GetDexMethodIndex());
+        CHECK(method != NULL);
+      }
+    }
+    method_ = method;
+  }
+  DexCache* GetDexCache() {
+    DexCache* result = dex_cache_;
+    if (result == NULL) {
+      Class* klass = method_->GetDeclaringClass();
+      result = klass->GetDexCache();
+      dex_cache_ = result;
+    }
+    return result;
+  }
+  ClassLinker* GetClassLinker() {
+    ClassLinker* result = class_linker_;
+    if (result == NULL) {
+      result = Runtime::Current()->GetClassLinker();
+      class_linker_ = result;
+    }
+    return result;
+  }
+
+  ClassLinker* class_linker_;
+  DexCache* dex_cache_;
+  const DexFile* dex_file_;
+  const Method* method_;
+  const char* shorty_;
+  int32_t shorty_len_;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodHelper);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_OBJECT_UTILS_H_
diff --git a/src/primitive.h b/src/primitive.h
index 5d41966..402a2b5 100644
--- a/src/primitive.h
+++ b/src/primitive.h
@@ -101,11 +101,13 @@
       case kPrimInt:
         return 'I';
       case kPrimFloat:
-        return 'J';
+        return 'F';
       case kPrimLong:
         return 'J';
       case kPrimDouble:
         return 'D';
+      case kPrimVoid:
+        return 'V';
       default:
         LOG(FATAL) << "Primitive char conversion on invalid type " << static_cast<int>(type);
         return 0;
diff --git a/src/reflection.cc b/src/reflection.cc
index f02c2d2..a6ae096 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -19,6 +19,7 @@
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "object.h"
+#include "object_utils.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 
@@ -45,7 +46,7 @@
   gShort_valueOf = class_linker->FindSystemClass("Ljava/lang/Short;")->FindDeclaredDirectMethod("valueOf", "(S)Ljava/lang/Short;");
 }
 
-jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jobject javaParams) {
+jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
   Thread* self = Thread::Current();
   ScopedThreadStateChange tsc(self, Thread::kRunnable);
 
@@ -72,21 +73,23 @@
 
   // Get our arrays of arguments and their types, and check they're the same size.
   ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
-  ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
-  int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
-  if (arg_count != classes->GetLength()) {
+  MethodHelper mh(m);
+  const DexFile::TypeList* classes = mh.GetParameterTypeList();
+  uint32_t classes_size = classes == NULL ? 0 : classes->Size();
+  uint32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
+  if (arg_count != classes_size) {
     self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
         "wrong number of arguments; expected %d, got %d",
-        classes->GetLength(), arg_count);
+        classes_size, arg_count);
     return NULL;
   }
 
   // Translate javaArgs to a jvalue[].
   UniquePtr<jvalue[]> args(new jvalue[arg_count]);
   JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
-  for (int32_t i = 0; i < arg_count; ++i) {
+  for (uint32_t i = 0; i < arg_count; ++i) {
     Object* arg = objects->Get(i);
-    Class* dst_class = classes->Get(i);
+    Class* dst_class = mh.GetClassFromTypeIdx(classes->GetTypeItem(i).type_idx_);
     if (dst_class->IsPrimitive()) {
       if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i])) {
         return NULL;
@@ -111,7 +114,7 @@
   }
 
   // Box if necessary and return.
-  BoxPrimitive(env, m->GetReturnType()->GetPrimitiveType(), value);
+  BoxPrimitive(env, mh.GetReturnType()->GetPrimitiveType(), value);
   return AddLocalReference<jobject>(env, value.l);
 }
 
@@ -121,7 +124,7 @@
     return false;
   }
   if (!o->InstanceOf(c)) {
-    std::string expectedClassName(PrettyDescriptor(c->GetDescriptor()));
+    std::string expectedClassName(PrettyDescriptor(c));
     std::string actualClassName(PrettyTypeOf(o));
     jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
         "expected receiver of type %s, but got %s",
@@ -283,7 +286,7 @@
     if (o != NULL && !o->InstanceOf(dst_class)) {
       jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
           "expected object of type %s, but got %s",
-          PrettyDescriptor(dst_class->GetDescriptor()).c_str(),
+          PrettyDescriptor(dst_class).c_str(),
           PrettyTypeOf(o).c_str());
       return false;
     }
@@ -302,37 +305,37 @@
   }
 
   JValue boxed_value = { 0 };
-  const String* src_descriptor = o->GetClass()->GetDescriptor();
+  std::string src_descriptor = ClassHelper(o->GetClass()).GetDescriptor();
   Class* src_class = NULL;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Field* primitive_field = o->GetClass()->GetIFields()->Get(0);
-  if (src_descriptor->Equals("Ljava/lang/Boolean;")) {
+  if (src_descriptor == "Ljava/lang/Boolean;") {
     src_class = class_linker->FindPrimitiveClass('Z');
     boxed_value.i = primitive_field->GetBoolean(o);  // and extend read value to 32bits
-  } else if (src_descriptor->Equals("Ljava/lang/Byte;")) {
+  } else if (src_descriptor == "Ljava/lang/Byte;") {
     src_class = class_linker->FindPrimitiveClass('B');
     boxed_value.i = primitive_field->GetByte(o);  // and extend read value to 32bits
-  } else if (src_descriptor->Equals("Ljava/lang/Character;")) {
+  } else if (src_descriptor == "Ljava/lang/Character;") {
     src_class = class_linker->FindPrimitiveClass('C');
     boxed_value.i = primitive_field->GetChar(o);  // and extend read value to 32bits
-  } else if (src_descriptor->Equals("Ljava/lang/Float;")) {
+  } else if (src_descriptor == "Ljava/lang/Float;") {
     src_class = class_linker->FindPrimitiveClass('F');
     boxed_value.f = primitive_field->GetFloat(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Double;")) {
+  } else if (src_descriptor == "Ljava/lang/Double;") {
     src_class = class_linker->FindPrimitiveClass('D');
     boxed_value.d = primitive_field->GetDouble(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Integer;")) {
+  } else if (src_descriptor == "Ljava/lang/Integer;") {
     src_class = class_linker->FindPrimitiveClass('I');
     boxed_value.i = primitive_field->GetInt(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Long;")) {
+  } else if (src_descriptor == "Ljava/lang/Long;") {
     src_class = class_linker->FindPrimitiveClass('J');
     boxed_value.j = primitive_field->GetLong(o);
-  } else if (src_descriptor->Equals("Ljava/lang/Short;")) {
+  } else if (src_descriptor == "Ljava/lang/Short;") {
     src_class = class_linker->FindPrimitiveClass('S');
     boxed_value.i = primitive_field->GetShort(o);  // and extend read value to 32bits
   } else {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
-        "%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str());
+        "%s is not a boxed primitive type", PrettyDescriptor(src_descriptor.c_str()).c_str());
     return false;
   }
 
diff --git a/src/reflection.h b/src/reflection.h
index df19deb..e832c3d 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -32,7 +32,7 @@
 
 bool ConvertPrimitiveValue(Primitive::Type src_class, Primitive::Type dst_class, const JValue& src, JValue& dst);
 
-jobject InvokeMethod(JNIEnv* env, jobject method, jobject receiver, jobject args, jobject params);
+jobject InvokeMethod(JNIEnv* env, jobject method, jobject receiver, jobject args);
 
 bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c);
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 9e6ebb1..6491138 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -800,19 +800,8 @@
   Class* method_class = Method::GetMethodClass();
   SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject()));
   method->SetDeclaringClass(method_class);
-  const char* name;
-  if (type == kSaveAll) {
-    name = "$$$callee_save_method$$$";
-  } else if (type == kRefsOnly) {
-    name = "$$$refs_only_callee_save_method$$$";
-  } else {
-    DCHECK(type == kRefsAndArgs);
-    name = "$$$refs_and_args_callee_save_method$$$";
-  }
-  method->SetName(intern_table_->InternStrong(name));
-  CHECK(method->GetName() != NULL);
-  method->SetSignature(intern_table_->InternStrong("()V"));
-  CHECK(method->GetSignature() != NULL);
+  // TODO: use a special method for callee saves
+  method->SetMethodIndex(DexFile::kDexNoIndex16);
   method->SetCode(NULL);
   if ((instruction_set == kThumb2) || (instruction_set == kArm)) {
     uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) |
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index e6011da..1d05527 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -19,6 +19,8 @@
 #include "dex_cache.h"
 #include "dex_verifier.h"
 #include "macros.h"
+#include "object.h"
+#include "object_utils.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
 
@@ -172,7 +174,7 @@
   result += "tried to access class ";
   result += class_name;
   result += " from class ";
-  result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+  result += PrettyDescriptor(method->GetDeclaringClass());
   return result;
 }
 
@@ -194,7 +196,7 @@
   result += "tried to access field ";
   result += class_name + "." + field_name;
   result += " from class ";
-  result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+  result += PrettyDescriptor(method->GetDeclaringClass());
   return result;
 }
 
@@ -217,7 +219,7 @@
   result += class_name + "." + method_name + ":" +
       dex_file.CreateMethodSignature(id.proto_idx_, NULL);
   result += " from class ";
-  result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor());
+  result += PrettyDescriptor(method->GetDeclaringClass());
   return result;
 }
 
@@ -352,9 +354,7 @@
     Method* caller = *caller_sp;
     // less two as return address may span into next dex instruction
     uint32_t dex_pc = caller->ToDexPC(caller_pc - 2);
-    const DexFile& dex_file = Runtime::Current()->GetClassLinker()
-                                  ->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
-    const DexFile::CodeItem* code = dex_file.GetCodeItem(caller->GetCodeItemOffset());
+    const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
     CHECK_LT(dex_pc, code->insns_size_in_code_units_);
     const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
     Instruction::Code instr_code = instr->Opcode();
@@ -473,14 +473,16 @@
                                            Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int32_t))) {
+    FieldHelper fh(field);
+    if (LIKELY(fh.IsPrimitiveType() && fh.FieldSize() == sizeof(int32_t))) {
       return field->Get32(NULL);
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (field != NULL) {
-    if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int32_t)) {
+    FieldHelper fh(field);
+    if (!fh.IsPrimitiveType() || fh.FieldSize() != sizeof(int32_t)) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted read of 32-bit primitive on field '%s'",
                                PrettyField(field, true).c_str());
@@ -495,14 +497,16 @@
                                            Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int64_t))) {
+    FieldHelper fh(field);
+    if (LIKELY(fh.IsPrimitiveType() && fh.FieldSize() == sizeof(int64_t))) {
       return field->Get64(NULL);
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (field != NULL) {
-    if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int64_t)) {
+    FieldHelper fh(field);
+    if (!fh.IsPrimitiveType() || fh.FieldSize() != sizeof(int64_t)) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted read of 64-bit primitive on field '%s'",
                                PrettyField(field, true).c_str());
@@ -517,14 +521,16 @@
                                            Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(!field->IsPrimitiveType())) {
+    FieldHelper fh(field);
+    if (LIKELY(!fh.IsPrimitiveType())) {
       return field->GetObj(NULL);
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (field != NULL) {
-    if (field->IsPrimitiveType()) {
+    FieldHelper fh(field);
+    if (fh.IsPrimitiveType()) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted read of reference on primitive field '%s'",
                                PrettyField(field, true).c_str());
@@ -539,7 +545,8 @@
                                        uint32_t new_value, Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int32_t))) {
+    FieldHelper fh(field);
+    if (LIKELY(fh.IsPrimitiveType() && fh.FieldSize() == sizeof(int32_t))) {
       field->Set32(NULL, new_value);
       return 0;  // success
     }
@@ -547,7 +554,8 @@
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (field != NULL) {
-    if (!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int32_t)) {
+    FieldHelper fh(field);
+    if (!fh.IsPrimitiveType() || fh.FieldSize() != sizeof(int32_t)) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted write of 32-bit primitive to field '%s'",
                                PrettyField(field, true).c_str());
@@ -563,7 +571,8 @@
                                       uint64_t new_value, Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(field->IsPrimitiveType() && field->PrimitiveSize() == sizeof(int64_t))) {
+    FieldHelper fh(field);
+    if (LIKELY(fh.IsPrimitiveType() && fh.FieldSize() == sizeof(int64_t))) {
       field->Set64(NULL, new_value);
       return 0;  // success
     }
@@ -571,7 +580,8 @@
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (LIKELY(field != NULL)) {
-    if (UNLIKELY(!field->IsPrimitiveType() || field->PrimitiveSize() != sizeof(int64_t))) {
+    FieldHelper fh(field);
+    if (UNLIKELY(!fh.IsPrimitiveType() || fh.FieldSize() != sizeof(int64_t))) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted write of 64-bit primitive to field '%s'",
                                PrettyField(field, true).c_str());
@@ -587,7 +597,7 @@
                                        Object* new_value, Thread* self, Method** sp) {
   Field* field = FindFieldFast(field_idx, referrer);
   if (LIKELY(field != NULL)) {
-    if (LIKELY(!field->IsPrimitiveType())) {
+    if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
       field->SetObj(NULL, new_value);
       return 0;  // success
     }
@@ -595,7 +605,7 @@
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, true);
   if (field != NULL) {
-    if (field->IsPrimitiveType()) {
+    if (FieldHelper(field).IsPrimitiveType()) {
       self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
                                "Attempted write of reference to primitive field '%s'",
                                PrettyField(field, true).c_str());
@@ -643,8 +653,8 @@
   Class* referrer = method->GetDeclaringClass();
   if (UNLIKELY(!referrer->CanAccess(klass))) {
     self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", "illegal class access: '%s' -> '%s'",
-                             PrettyDescriptor(referrer->GetDescriptor()).c_str(),
-                             PrettyDescriptor(klass->GetDescriptor()).c_str());
+                             PrettyDescriptor(referrer).c_str(),
+                             PrettyDescriptor(klass).c_str());
     return NULL;  // Failure
   }
   if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
@@ -672,11 +682,11 @@
     if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
       Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
           "Bad filled array request for type %s",
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
+          PrettyDescriptor(klass).c_str());
     } else {
       Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
           "Found type %s; filled-new-array not implemented for anything but \'int\'",
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
+          PrettyDescriptor(klass).c_str());
     }
     return NULL;  // Failure
   } else {
@@ -731,8 +741,8 @@
     FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
         "%s cannot be cast to %s",
-        PrettyDescriptor(a->GetDescriptor()).c_str(),
-        PrettyDescriptor(b->GetDescriptor()).c_str());
+        PrettyDescriptor(a).c_str(),
+        PrettyDescriptor(b).c_str());
     return -1;  // Failure
   }
 }
@@ -751,8 +761,8 @@
     FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
         "Cannot store an object of type %s in to an array of type %s",
-        PrettyDescriptor(element_class->GetDescriptor()).c_str(),
-        PrettyDescriptor(array_class->GetDescriptor()).c_str());
+        PrettyDescriptor(element_class).c_str(),
+        PrettyDescriptor(array_class).c_str());
     return -1;  // Failure
   }
 }
@@ -769,7 +779,7 @@
   //
   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
   // running.
-  if (klass == referrer->GetDeclaringClass() && referrer->IsClassInitializer()) {
+  if (klass == referrer->GetDeclaringClass() && MethodHelper(referrer).IsClassInitializer()) {
     return klass;
   }
   if (!class_linker->EnsureInitialized(klass, true)) {
@@ -792,14 +802,14 @@
   if (UNLIKELY(!referrer->GetDeclaringClass()->CanAccess(klass))) {
     self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
         "Class %s is inaccessible to method %s",
-        PrettyDescriptor(klass->GetDescriptor()).c_str(),
+        PrettyDescriptor(klass).c_str(),
         PrettyMethod(referrer, true).c_str());
   }
   // If we are the <clinit> of this class, just return our storage.
   //
   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
   // running.
-  if (klass == referrer->GetDeclaringClass() && referrer->IsClassInitializer()) {
+  if (klass == referrer->GetDeclaringClass() && MethodHelper(referrer).IsClassInitializer()) {
     return klass;
   }
   if (!class_linker->EnsureInitialized(klass, true)) {
@@ -1000,10 +1010,11 @@
 
   // Placing into local references incoming arguments from the caller's register arguments,
   // replacing original Object* with jobject
-  const size_t num_params = proxy_method->NumArgs();
+  MethodHelper proxy_mh(proxy_method);
+  const size_t num_params = proxy_mh.NumArgs();
   size_t args_in_regs = 0;
   for (size_t i = 1; i < num_params; i++) {  // skip receiver
-    args_in_regs = args_in_regs + (proxy_method->IsParamALongOrDouble(i) ? 2 : 1);
+    args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
     if (args_in_regs > 2) {
       args_in_regs = 2;
       break;
@@ -1012,23 +1023,23 @@
   size_t cur_arg = 0;  // current stack location to read
   size_t param_index = 1;  // skip receiver
   while (cur_arg < args_in_regs && param_index < num_params) {
-    if (proxy_method->IsParamAReference(param_index)) {
+    if (proxy_mh.IsParamAReference(param_index)) {
       Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
       jobject jobj = AddLocalReference<jobject>(env, obj);
       *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
-    cur_arg = cur_arg + (proxy_method->IsParamALongOrDouble(param_index) ? 2 : 1);
+    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
     param_index++;
   }
   // Placing into local references incoming arguments from the caller's stack arguments
   cur_arg += 11;  // skip callee saves, LR, Method* and out arg spills for R1 to R3
   while (param_index < num_params) {
-    if (proxy_method->IsParamAReference(param_index)) {
+    if (proxy_mh.IsParamAReference(param_index)) {
       Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
       jobject jobj = AddLocalReference<jobject>(env, obj);
       *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
-    cur_arg = cur_arg + (proxy_method->IsParamALongOrDouble(param_index) ? 2 : 1);
+    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
     param_index++;
   }
   // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
@@ -1049,13 +1060,14 @@
   // Convert proxy method into expected interface method
   Method* interface_method = proxy_method->FindOverriddenMethod();
   CHECK(interface_method != NULL);
+  CHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
   args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
   LOG(INFO) << "Interface method is " << PrettyMethod(interface_method, true);
   // Box arguments
   cur_arg = 0;  // reset stack location to read to start
   // reset index, will index into param type array which doesn't include the receiver
   param_index = 0;
-  ObjectArray<Class>* param_types = interface_method->GetJavaParameterTypes();
+  ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
   CHECK(param_types != NULL);
   // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
   CHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
@@ -1119,7 +1131,7 @@
     Object* result_ref = self->DecodeJObject(result);
     if (result_ref != NULL) {
       JValue result_unboxed;
-      UnboxPrimitive(env, result_ref, interface_method->GetReturnType(), result_unboxed);
+      UnboxPrimitive(env, result_ref, proxy_mh.GetReturnType(), result_unboxed);
       *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
     } else {
       *reinterpret_cast<jobject*>(stack_args) = NULL;
@@ -1132,7 +1144,10 @@
     if (!exception->IsCheckedException()) {
       self->SetException(exception);
     } else {
-      ObjectArray<Class>* declared_exceptions = proxy_method->GetExceptionTypes();
+      // TODO: get the correct intersection of exceptions as passed to the class linker's create
+      // proxy code.
+      UNIMPLEMENTED(FATAL);
+      ObjectArray<Class>* declared_exceptions = NULL; // proxy_mh.GetExceptionTypes();
       Class* exception_class = exception->GetClass();
       bool declares_exception = false;
       for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
diff --git a/src/stack.cc b/src/stack.cc
index 542ac47..9944ec3 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -18,9 +18,12 @@
 
 #include "compiler.h"
 #include "object.h"
+#include "object_utils.h"
 #include "thread_list.h"
 
-int oatVRegOffsetFromMethod(art::Method* method, int reg);
+int oatVRegOffset(const art::DexFile::CodeItem* code_item,
+                  uint32_t core_spills, uint32_t fp_spills,
+                  size_t frame_size, int reg);
 
 namespace art {
 
@@ -45,16 +48,31 @@
   return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
-uint32_t Frame::GetVReg(Method* method, int vreg) const {
-  DCHECK(method == GetMethod());
-  int offset = oatVRegOffsetFromMethod(method, vreg);
+uint32_t Frame::GetVReg(const DexFile::CodeItem* code_item, uint32_t core_spills,
+                        uint32_t fp_spills, size_t frame_size, int vreg) const {
+  int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
   byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
   return *reinterpret_cast<uint32_t*>(vreg_addr);
 }
 
-void Frame::SetVReg(Method* method, int vreg, uint32_t new_value) {
-  DCHECK(method == GetMethod());
-  int offset = oatVRegOffsetFromMethod(method, vreg);
+uint32_t Frame::GetVReg(Method* m, int vreg) const {
+  DCHECK(m == GetMethod());
+  const art::DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+  DCHECK(code_item != NULL);  // can't be NULL or how would we compile its instructions?
+  uint32_t core_spills = m->GetCoreSpillMask();
+  uint32_t fp_spills = m->GetFpSpillMask();
+  size_t frame_size = m->GetFrameSizeInBytes();
+  return GetVReg(code_item, core_spills, fp_spills, frame_size, vreg);
+}
+
+void Frame::SetVReg(Method* m, int vreg, uint32_t new_value) {
+  DCHECK(m == GetMethod());
+  const art::DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+  DCHECK(code_item != NULL);  // can't be NULL or how would we compile its instructions?
+  uint32_t core_spills = m->GetCoreSpillMask();
+  uint32_t fp_spills = m->GetFpSpillMask();
+  size_t frame_size = m->GetFrameSizeInBytes();
+  int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg);
   byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset;
   *reinterpret_cast<uint32_t*>(vreg_addr) = new_value;
 }
diff --git a/src/stack.h b/src/stack.h
index a0f13d3..eee1d56 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_STACK_H_
 #define ART_SRC_STACK_H_
 
+#include "dex_file.h"
 #include "jni.h"
 #include "macros.h"
 
@@ -54,7 +55,11 @@
 
   uintptr_t LoadCalleeSave(int num) const;
 
-  uint32_t GetVReg(Method* method, int vreg) const;
+
+  uint32_t GetVReg(const DexFile::CodeItem* code_item, uint32_t core_spills, uint32_t fp_spills,
+                    size_t frame_size, int vreg) const;
+
+  uintptr_t GetVReg(Method* m, int vreg) const;
   void SetVReg(Method* method, int vreg, uint32_t new_value);
 
   Method** GetSP() const {
diff --git a/src/thread.cc b/src/thread.cc
index b6962f9..092c071 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -35,6 +35,7 @@
 #include "jni_internal.h"
 #include "monitor.h"
 #include "object.h"
+#include "object_utils.h"
 #include "reflection.h"
 #include "runtime.h"
 #include "runtime_support.h"
@@ -534,8 +535,9 @@
       if (m->IsNative()) {
         os << "(Native method)";
       } else {
-        SirtRef<String> source_file(c->GetSourceFile());
-        os << "(" << (source_file.get() != NULL ? source_file->ToModifiedUtf8() : "unavailable")
+        mh.ChangeMethod(m);
+        const char* source_file(mh.GetDeclaringClassSourceFile());
+        os << "(" << (source_file != NULL ? source_file : "unavailable")
            << ":" << line_number << ")";
       }
       os << "\n";
@@ -545,6 +547,7 @@
       Monitor::DescribeWait(os, thread);
     }
   }
+  MethodHelper mh;
   Method* last_method;
   int last_line_number;
   int repetition_count;
@@ -1172,27 +1175,32 @@
     *stack_depth = depth;
   }
 
+  MethodHelper mh;
   for (int32_t i = 0; i < depth; ++i) {
     // Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
     Method* method = down_cast<Method*>(method_trace->Get(i));
+    mh.ChangeMethod(method);
     uint32_t native_pc = pc_trace->Get(i);
-    Class* klass = method->GetDeclaringClass();
-    std::string class_name(PrettyDescriptor(klass->GetDescriptor()));
-    int32_t line_number = -1;
-    DexCache* dex_cache = klass->GetDexCache();
-    if (dex_cache != NULL) {
-      const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
-      line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(native_pc));
-    }
+    int32_t line_number = mh.GetLineNumFromNativePC(native_pc);
     // Allocate element, potentially triggering GC
     // TODO: reuse class_name_object via Class::name_?
+    std::string class_name(PrettyDescriptor(mh.GetDeclaringClassDescriptor()));
     SirtRef<String> class_name_object(String::AllocFromModifiedUtf8(class_name.c_str()));
     if (class_name_object.get() == NULL) {
       return NULL;
     }
+    SirtRef<String> method_name_object(String::AllocFromModifiedUtf8(mh.GetName()));
+    if (method_name_object.get() == NULL) {
+      return NULL;
+    }
+    SirtRef<String>
+        source_name_object(String::AllocFromModifiedUtf8(mh.GetDeclaringClassSourceFile()));
+    if (source_name_object.get() == NULL) {
+      return NULL;
+    }
     StackTraceElement* obj = StackTraceElement::Alloc(class_name_object.get(),
-                                                      method->GetName(),
-                                                      klass->GetSourceFile(),
+                                                      method_name_object.get(),
+                                                      source_name_object.get(),
                                                       line_number);
     if (obj == NULL) {
       return NULL;
@@ -1247,7 +1255,7 @@
 
 void Thread::ThrowOutOfMemoryError(Class* c, size_t byte_count) {
   std::string msg(StringPrintf("Failed to allocate a %zd-byte %s", byte_count,
-      PrettyDescriptor(c->GetDescriptor()).c_str()));
+      PrettyDescriptor(c).c_str()));
   ThrowOutOfMemoryError(msg.c_str());
 }
 
@@ -1432,8 +1440,14 @@
       const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
       CHECK(reg_bitmap != NULL);
       const VmapTable vmap_table(m->GetVmapTableRaw());
+      const art::DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+      DCHECK(code_item != NULL);  // can't be NULL or how would we compile its instructions?
+      uint32_t core_spills = m->GetCoreSpillMask();
+      uint32_t fp_spills = m->GetFpSpillMask();
+      size_t frame_size = m->GetFrameSizeInBytes();
       // For all dex registers in the bitmap
-      size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(m->NumRegisters()));
+      size_t num_regs = std::min(map.RegWidth() * 8,
+                                 static_cast<size_t>(code_item->registers_size_));
       for (size_t reg = 0; reg < num_regs; ++reg) {
         // Does this register hold a reference?
         if (TestBitmap(reg, reg_bitmap)) {
@@ -1454,7 +1468,8 @@
             spill_shifts--;  // wind back one as we want the last match
             ref = reinterpret_cast<Object*>(context_->GetGPR(spill_shifts));
           } else {
-            ref = reinterpret_cast<Object*>(frame.GetVReg(m, reg));
+            ref = reinterpret_cast<Object*>(frame.GetVReg(code_item, core_spills, fp_spills,
+                                                          frame_size, reg));
           }
           if (ref != NULL) {
             root_visitor_(ref, arg_);
diff --git a/src/utils.cc b/src/utils.cc
index 63787a8..943899d 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -13,6 +13,7 @@
 #include "class_loader.h"
 #include "file.h"
 #include "object.h"
+#include "object_utils.h"
 #include "os.h"
 
 #if defined(HAVE_PRCTL)
@@ -68,6 +69,14 @@
   return PrettyDescriptor(java_descriptor->ToModifiedUtf8());
 }
 
+std::string PrettyDescriptor(const Class* klass) {
+  if (klass == NULL) {
+    return "null";
+  }
+  return PrettyDescriptor(ClassHelper(klass).GetDescriptor());
+
+}
+
 std::string PrettyDescriptor(const std::string& descriptor) {
   // Count the number of '['s to get the dimensionality.
   const char* c = descriptor.c_str();
@@ -126,14 +135,15 @@
   if (f == NULL) {
     return "null";
   }
+  FieldHelper fh(f);
   std::string result;
   if (with_type) {
-    result += PrettyDescriptor(f->GetTypeDescriptor());
+    result += PrettyDescriptor(fh.GetTypeDescriptor());
     result += ' ';
   }
-  result += PrettyDescriptor(f->GetDeclaringClass()->GetDescriptor());
+  result += PrettyDescriptor(fh.GetDeclaringClassDescriptor());
   result += '.';
-  result += f->GetName()->ToModifiedUtf8();
+  result += fh.GetName();
   return result;
 }
 
@@ -141,14 +151,14 @@
   if (m == NULL) {
     return "null";
   }
-  Class* c = m->GetDeclaringClass();
-  std::string result(PrettyDescriptor(c->GetDescriptor()));
+  MethodHelper mh(m);
+  std::string result(PrettyDescriptor(mh.GetDeclaringClassDescriptor()));
   result += '.';
-  result += m->GetName()->ToModifiedUtf8();
+  result += mh.GetName();
   if (with_signature) {
     // TODO: iterate over the signature's elements and pass them all to
     // PrettyDescriptor? We'd need to pull out the return type specially, too.
-    result += m->GetSignature()->ToModifiedUtf8();
+    result += mh.GetSignature();
   }
   return result;
 }
@@ -173,9 +183,11 @@
   if (obj->GetClass() == NULL) {
     return "(raw)";
   }
-  std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+  ClassHelper kh(obj->GetClass());
+  std::string result(PrettyDescriptor(kh.GetDescriptor()));
   if (obj->IsClass()) {
-    result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()) + ">";
+    kh.ChangeClass(obj->AsClass());
+    result += "<" + PrettyDescriptor(kh.GetDescriptor()) + ">";
   }
   return result;
 }
@@ -186,7 +198,7 @@
   }
   std::string result;
   result += "java.lang.Class<";
-  result += PrettyDescriptor(c->GetDescriptor());
+  result += PrettyDescriptor(c);
   result += ">";
   return result;
 }
@@ -197,7 +209,7 @@
   }
   std::string result;
   result += "java.lang.Class<";
-  result += PrettyDescriptor(c->GetDescriptor());
+  result += PrettyDescriptor(c);
   result += ",";
   result += PrettyTypeOf(c->GetClassLoader());
   // TODO: add an identifying hash value for the loader
@@ -254,16 +266,15 @@
 }
 
 std::string JniShortName(const Method* m) {
-  Class* declaring_class = m->GetDeclaringClass();
-
-  std::string class_name(declaring_class->GetDescriptor()->ToModifiedUtf8());
+  MethodHelper mh(m);
+  std::string class_name(mh.GetDeclaringClassDescriptor());
   // Remove the leading 'L' and trailing ';'...
   CHECK_EQ(class_name[0], 'L') << class_name;
   CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
   class_name.erase(0, 1);
   class_name.erase(class_name.size() - 1, 1);
 
-  std::string method_name(m->GetName()->ToModifiedUtf8());
+  std::string method_name(mh.GetName());
 
   std::string short_name;
   short_name += "Java_";
@@ -278,7 +289,7 @@
   long_name += JniShortName(m);
   long_name += "__";
 
-  std::string signature(m->GetSignature()->ToModifiedUtf8());
+  std::string signature(MethodHelper(m).GetSignature());
   signature.erase(0, 1);
   signature.erase(signature.begin() + signature.find(')'), signature.end());
 
diff --git a/src/utils.h b/src/utils.h
index f5e0c49..5b3a036 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -159,6 +159,7 @@
 std::string PrettyDescriptor(const String* descriptor);
 std::string PrettyDescriptor(const std::string& descriptor);
 std::string PrettyDescriptor(Primitive::Type type);
+std::string PrettyDescriptor(const Class* klass);
 
 // Returns a human-readable signature for 'f'. Something like "a.b.C.f" or
 // "int a.b.C.f" (depending on the value of 'with_type').
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index 77fe2ee..547f8c9 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -6,13 +6,14 @@
 #include "class_linker.h"
 #include "dex_verifier.h"
 #include "object.h"
+#include "object_utils.h"
 #include "thread.h"
 #include "jni.h"
 
 namespace art {
 
-#define IS_IN_REF_BITMAP(method, ref_bitmap, reg) \
-  ( ((reg) < (method)->NumRegisters()) &&                       \
+#define IS_IN_REF_BITMAP(mh, ref_bitmap, reg) \
+  ( ((reg) < mh.GetCodeItem()->registers_size_) &&                       \
     (( *((ref_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
 
 #define CHECK_REGS_CONTAIN_REFS(...)     \
@@ -20,7 +21,7 @@
     int t[] = {__VA_ARGS__};             \
     int t_size = sizeof(t) / sizeof(*t);      \
     for (int i = 0; i < t_size; ++i)          \
-      CHECK(IS_IN_REF_BITMAP(m, ref_bitmap, t[i])) \
+      CHECK(IS_IN_REF_BITMAP(mh, ref_bitmap, t[i])) \
           << "Error: Reg @ " << i << "-th argument is not in GC map"; \
   } while(false)
 
@@ -52,7 +53,8 @@
       art::verifier::DexVerifier::VerifyMethodAndDump(m);
     }
     const uint8_t* ref_bitmap = NULL;
-    std::string m_name = m->GetName()->ToModifiedUtf8();
+    MethodHelper mh(m);
+    std::string m_name(mh.GetName());
 
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/StackWalk/stack_walk_jni.cc
index ad9c674..06b3d41 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/StackWalk/stack_walk_jni.cc
@@ -6,19 +6,20 @@
 #include "class_linker.h"
 #include "dex_verifier.h"
 #include "object.h"
+#include "object_utils.h"
 #include "jni.h"
 
 namespace art {
 
-#define REG(method, reg_bitmap, reg) \
-  ( ((reg) < (method)->NumRegisters()) &&                       \
+#define REG(mh, reg_bitmap, reg) \
+  ( ((reg) < mh.GetCodeItem()->registers_size_) &&                       \
     (( *((reg_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01) )
 
 #define CHECK_REGS(...) do {          \
     int t[] = {__VA_ARGS__};             \
     int t_size = sizeof(t) / sizeof(*t);      \
     for (int i = 0; i < t_size; ++i)          \
-      CHECK(REG(m, reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap";  \
+      CHECK(REG(mh, reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap";  \
   } while(false)
 
 static int gJava_StackWalk_refmap_calls = 0;
@@ -39,12 +40,13 @@
     }
     verifier::PcToReferenceMap map(m);
     const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
-    String* m_name = m->GetName();
+    MethodHelper mh(m);
+    StringPiece m_name(mh.GetName());
 
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
-    if (m_name->Equals("f")) {
+    if (m_name == "f") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(1U, m->ToDexPC(pc));
         CHECK_REGS(1);
@@ -53,7 +55,7 @@
         CHECK_EQ(5U, m->ToDexPC(pc));
         CHECK_REGS(1);
       }
-    } else if (m_name->Equals("g")) {
+    } else if (m_name == "g") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0xcU, m->ToDexPC(pc));
         CHECK_REGS(0, 2);  // Note that v1 is not in the minimal root set
@@ -62,7 +64,7 @@
         CHECK_EQ(0xcU, m->ToDexPC(pc));
         CHECK_REGS(0, 2);
       }
-    } else if (m_name->Equals("shlemiel")) {
+    } else if (m_name == "shlemiel") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(0x380U, m->ToDexPC(pc));
         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);