Change MethodHelper to use a Handle.

Added ConstHandle to help prevent errors where you modify the value
stored in the handle of the caller. Also fixed compaction bugs
related to not knowing MethodHelper::GetReturnType can resolve types.
This bug was present in interpreter RETURN_OBJECT.

Bug: 13077697

Change-Id: I71f964d4d810ab4debda1a09bc968af8f3c874a3
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 46c4389..a816489 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -129,7 +129,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 class_name(MethodHelper(method).GetDeclaringClassDescriptor());
+  std::string class_name(method->GetDeclaringClassDescriptor());
   if (!vm->trace.empty() && class_name.find(vm->trace) != std::string::npos) {
     return true;
   }
@@ -284,7 +284,7 @@
     if (m == nullptr) {
       return;
     }
-    if (*expectedType != MethodHelper(m).GetShorty()[0]) {
+    if (*expectedType != m->GetShorty()[0]) {
       JniAbortF(function_name_, "the return type of %s does not match %s",
                 function_name_, PrettyMethod(m).c_str());
     }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 330b110..a43fda1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2807,7 +2807,7 @@
 }
 
 static void CheckProxyConstructor(mirror::ArtMethod* constructor);
-static void CheckProxyMethod(mirror::ArtMethod* method,
+static void CheckProxyMethod(Handle<mirror::ArtMethod> method,
                              Handle<mirror::ArtMethod> prototype);
 
 mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name,
@@ -2929,11 +2929,12 @@
     CHECK(klass->GetIFields() == nullptr);
     CheckProxyConstructor(klass->GetDirectMethod(0));
     for (size_t i = 0; i < num_virtual_methods; ++i) {
-      StackHandleScope<1> hs(self);
+      StackHandleScope<2> hs(self);
       mirror::ObjectArray<mirror::ArtMethod>* decoded_methods =
           soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods);
       Handle<mirror::ArtMethod> prototype(hs.NewHandle(decoded_methods->Get(i)));
-      CheckProxyMethod(klass->GetVirtualMethod(i), prototype);
+      Handle<mirror::ArtMethod> virtual_method(hs.NewHandle(klass->GetVirtualMethod(i)));
+      CheckProxyMethod(virtual_method, prototype);
     }
 
     mirror::String* decoded_name = soa.Decode<mirror::String*>(name);
@@ -3014,9 +3015,9 @@
 static void CheckProxyConstructor(mirror::ArtMethod* constructor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(constructor->IsConstructor());
-  MethodHelper mh(constructor);
-  CHECK_STREQ(mh.GetName(), "<init>");
-  CHECK_STREQ(mh.GetSignature().ToString().c_str(), "(Ljava/lang/reflect/InvocationHandler;)V");
+  CHECK_STREQ(constructor->GetName(), "<init>");
+  CHECK_STREQ(constructor->GetSignature().ToString().c_str(),
+              "(Ljava/lang/reflect/InvocationHandler;)V");
   DCHECK(constructor->IsPublic());
 }
 
@@ -3049,7 +3050,7 @@
   return method;
 }
 
-static void CheckProxyMethod(mirror::ArtMethod* method, Handle<mirror::ArtMethod> prototype)
+static void CheckProxyMethod(Handle<mirror::ArtMethod> method, Handle<mirror::ArtMethod> prototype)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Basic sanity
   CHECK(!prototype->IsFinal());
@@ -3064,9 +3065,9 @@
   CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
 
   MethodHelper mh(method);
-  MethodHelper mh2(prototype.Get());
-  CHECK_STREQ(mh.GetName(), mh2.GetName());
-  CHECK_STREQ(mh.GetShorty(), mh2.GetShorty());
+  MethodHelper mh2(prototype);
+  CHECK_STREQ(method->GetName(), prototype->GetName());
+  CHECK_STREQ(method->GetShorty(), prototype->GetShorty());
   // More complex sanity - via dex cache
   CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
 }
@@ -3321,16 +3322,18 @@
     return true;
   }
   // Begin with the methods local to the superclass.
-  MethodHelper mh;
-  MethodHelper super_mh;
+  StackHandleScope<2> hs(Thread::Current());
+  MethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
   if (klass->HasSuperClass() &&
       klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
     for (int i = klass->GetSuperClass()->GetVTable()->GetLength() - 1; i >= 0; --i) {
       mh.ChangeMethod(klass->GetVTable()->GetWithoutChecks(i));
       super_mh.ChangeMethod(klass->GetSuperClass()->GetVTable()->GetWithoutChecks(i));
-      bool is_override = mh.GetMethod() != super_mh.GetMethod();
-      if (is_override && !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
-        ThrowLinkageError(klass.Get(), "Class %s method %s resolves differently in superclass %s",
+      if (mh.GetMethod() != super_mh.GetMethod() &&
+          !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
+        ThrowLinkageError(klass.Get(),
+                          "Class %s method %s resolves differently in superclass %s",
                           PrettyDescriptor(klass.Get()).c_str(),
                           PrettyMethod(mh.GetMethod()).c_str(),
                           PrettyDescriptor(klass->GetSuperClass()).c_str());
@@ -3344,9 +3347,10 @@
       for (uint32_t j = 0; j < num_methods; ++j) {
         mh.ChangeMethod(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j));
         super_mh.ChangeMethod(klass->GetIfTable()->GetInterface(i)->GetVirtualMethod(j));
-        bool is_override = mh.GetMethod() != super_mh.GetMethod();
-        if (is_override && !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
-          ThrowLinkageError(klass.Get(), "Class %s method %s resolves differently in interface %s",
+        if (mh.GetMethod() != super_mh.GetMethod() &&
+            !mh.HasSameSignatureWithDifferentClassLoaders(&super_mh)) {
+          ThrowLinkageError(klass.Get(),
+                            "Class %s method %s resolves differently in interface %s",
                             PrettyDescriptor(klass.Get()).c_str(),
                             PrettyMethod(mh.GetMethod()).c_str(),
                             PrettyDescriptor(klass->GetIfTable()->GetInterface(i)).c_str());
@@ -3388,7 +3392,7 @@
   if (!LinkSuperClass(klass)) {
     return false;
   }
-  if (!LinkMethods(klass, interfaces)) {
+  if (!LinkMethods(self, klass, interfaces)) {
     return false;
   }
   if (!LinkInstanceFields(klass)) {
@@ -3507,7 +3511,7 @@
 }
 
 // Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(Handle<mirror::Class> klass,
+bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass,
                               Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
   if (klass->IsInterface()) {
     // No vtable.
@@ -3523,20 +3527,19 @@
     return LinkInterfaceMethods(klass, interfaces);
   } else {
     // Link virtual and interface method tables
-    return LinkVirtualMethods(klass) && LinkInterfaceMethods(klass, interfaces);
+    return LinkVirtualMethods(self, klass) && LinkInterfaceMethods(klass, interfaces);
   }
   return true;
 }
 
-bool ClassLinker::LinkVirtualMethods(Handle<mirror::Class> klass) {
-  Thread* self = Thread::Current();
+bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) {
   if (klass->HasSuperClass()) {
-    uint32_t max_count = (klass->NumVirtualMethods() +
-                          klass->GetSuperClass()->GetVTable()->GetLength());
+    uint32_t max_count = klass->NumVirtualMethods() +
+        klass->GetSuperClass()->GetVTable()->GetLength();
     size_t actual_count = klass->GetSuperClass()->GetVTable()->GetLength();
     CHECK_LE(actual_count, max_count);
     // TODO: do not assign to the vtable field until it is fully constructed.
-    StackHandleScope<1> hs(self);
+    StackHandleScope<3> hs(self);
     Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
         hs.NewHandle(klass->GetSuperClass()->GetVTable()->CopyOf(self, max_count)));
     if (UNLIKELY(vtable.Get() == NULL)) {
@@ -3544,20 +3547,22 @@
       return false;
     }
     // See if any of our virtual methods override the superclass.
+    MethodHelper local_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+    MethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
     for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
       mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i);
-      MethodHelper local_mh(local_method);
+      local_mh.ChangeMethod(local_method);
       size_t j = 0;
       for (; j < actual_count; ++j) {
         mirror::ArtMethod* super_method = vtable->Get(j);
-        MethodHelper super_mh(super_method);
+        super_mh.ChangeMethod(super_method);
         if (local_mh.HasSameNameAndSignature(&super_mh)) {
           if (klass->CanAccessMember(super_method->GetDeclaringClass(),
                                      super_method->GetAccessFlags())) {
             if (super_method->IsFinal()) {
               ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
                                 PrettyMethod(local_method).c_str(),
-                                super_mh.GetDeclaringClassDescriptor());
+                                super_method->GetDeclaringClassDescriptor());
               return false;
             }
             vtable->Set<false>(j, local_method);
@@ -3566,7 +3571,7 @@
           } else {
             LOG(WARNING) << "Before Android 4.1, method " << PrettyMethod(local_method)
                          << " would have incorrectly overridden the package-private method in "
-                         << PrettyDescriptor(super_mh.GetDeclaringClassDescriptor());
+                         << PrettyDescriptor(super_method->GetDeclaringClassDescriptor());
           }
         }
       }
@@ -3592,7 +3597,7 @@
     }
     klass->SetVTable(vtable.Get());
   } else {
-    CHECK(klass.Get() == GetClassRoot(kJavaLangObject));
+    CHECK_EQ(klass.Get(), GetClassRoot(kJavaLangObject));
     uint32_t num_virtual_methods = klass->NumVirtualMethods();
     if (!IsUint(16, num_virtual_methods)) {
       ThrowClassFormatError(klass.Get(), "Too many methods: %d", num_virtual_methods);
@@ -3618,8 +3623,9 @@
 bool ClassLinker::LinkInterfaceMethods(Handle<mirror::Class> klass,
                                        Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
   Thread* const self = Thread::Current();
+  Runtime* const runtime = Runtime::Current();
   // Set the imt table to be all conflicts by default.
-  klass->SetImTable(Runtime::Current()->GetDefaultImt());
+  klass->SetImTable(runtime->GetDefaultImt());
   size_t super_ifcount;
   if (klass->HasSuperClass()) {
     super_ifcount = klass->GetSuperClass()->GetIfTableCount();
@@ -3657,7 +3663,7 @@
       return true;
     }
   }
-  StackHandleScope<2> hs(self);
+  StackHandleScope<4> hs(self);
   Handle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
   if (UNLIKELY(iftable.Get() == NULL)) {
     CHECK(self->IsExceptionPending());  // OOME.
@@ -3737,6 +3743,8 @@
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
   }
+  MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MethodHelper vtable_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
   std::vector<mirror::ArtMethod*> miranda_list;
   for (size_t i = 0; i < ifcount; ++i) {
     size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
@@ -3753,7 +3761,7 @@
           hs.NewHandle(klass->GetVTableDuringLinking()));
       for (size_t j = 0; j < num_methods; ++j) {
         mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
-        MethodHelper interface_mh(interface_method);
+        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
@@ -3765,7 +3773,7 @@
         // matter which direction we go.  We walk it backward anyway.)
         for (k = vtable->GetLength() - 1; k >= 0; --k) {
           mirror::ArtMethod* vtable_method = vtable->Get(k);
-          MethodHelper vtable_mh(vtable_method);
+          vtable_mh.ChangeMethod(vtable_method);
           if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
             if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
               ThrowIllegalAccessError(
@@ -3782,7 +3790,7 @@
               imtable->Set<false>(imt_index, vtable_method);
               imtable_changed = true;
             } else {
-              imtable->Set<false>(imt_index, Runtime::Current()->GetImtConflictMethod());
+              imtable->Set<false>(imt_index, runtime->GetImtConflictMethod());
             }
             break;
           }
@@ -3790,11 +3798,10 @@
         if (k < 0) {
           StackHandleScope<1> hs(self);
           auto miranda_method = hs.NewHandle<mirror::ArtMethod>(nullptr);
-          for (size_t mir = 0; mir < miranda_list.size(); mir++) {
-            mirror::ArtMethod* mir_method = miranda_list[mir];
-            MethodHelper vtable_mh(mir_method);
+          for (mirror::ArtMethod* mir_method : miranda_list) {
+            vtable_mh.ChangeMethod(mir_method);
             if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-              miranda_method.Assign(miranda_list[mir]);
+              miranda_method.Assign(mir_method);
               break;
             }
           }
@@ -3815,7 +3822,7 @@
   }
   if (imtable_changed) {
     // Fill in empty entries in interface method table with conflict.
-    mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
+    mirror::ArtMethod* imt_conflict_method = runtime->GetImtConflictMethod();
     for (size_t i = 0; i < kImtSize; i++) {
       if (imtable->Get(i) == NULL) {
         imtable->Set<false>(i, imt_conflict_method);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index ccf0558..a1d7bc6 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -499,11 +499,11 @@
   bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkMethods(Handle<mirror::Class> klass,
+  bool LinkMethods(Thread* self, Handle<mirror::Class> klass,
                    Handle<mirror::ObjectArray<mirror::Class>> interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkVirtualMethods(Handle<mirror::Class> klass)
+  bool LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool LinkInterfaceMethods(Handle<mirror::Class> klass,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 45ab33a..04f6946 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -152,11 +152,10 @@
   }
 
   void AssertMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    MethodHelper mh(method);
     EXPECT_TRUE(method != NULL);
     EXPECT_TRUE(method->GetClass() != NULL);
-    EXPECT_TRUE(mh.GetName() != NULL);
-    EXPECT_TRUE(mh.GetSignature() != Signature::NoSignature());
+    EXPECT_TRUE(method->GetName() != NULL);
+    EXPECT_TRUE(method->GetSignature() != Signature::NoSignature());
 
     EXPECT_TRUE(method->GetDexCacheStrings() != NULL);
     EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL);
@@ -203,8 +202,7 @@
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
       if (klass->NumDirectMethods() == 1) {
-        MethodHelper mh(klass->GetDirectMethod(0));
-        EXPECT_TRUE(mh.IsClassInitializer());
+        EXPECT_TRUE(klass->GetDirectMethod(0)->IsClassInitializer());
         EXPECT_TRUE(klass->GetDirectMethod(0)->IsDirect());
       } else {
         EXPECT_EQ(0U, klass->NumDirectMethods());
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index a3e3cfa..8de3068 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -363,7 +363,7 @@
 }
 
 void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
-  const DexFile::CodeItem* code = MethodHelper(throw_location.GetMethod()).GetCodeItem();
+  const DexFile::CodeItem* code = throw_location.GetMethod()->GetCodeItem();
   uint32_t throw_dex_pc = throw_location.GetDexPc();
   CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
   const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 8e2340c..73ed590 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -70,7 +70,7 @@
   }
 
   int32_t LineNumber() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return MethodHelper(method).GetLineNumFromDexPC(dex_pc);
+    return method->GetLineNumFromDexPC(dex_pc);
   }
 };
 
@@ -1373,7 +1373,7 @@
 std::string Dbg::GetMethodName(JDWP::MethodId method_id)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtMethod* m = FromMethodId(method_id);
-  return MethodHelper(m).GetName();
+  return m->GetName();
 }
 
 std::string Dbg::GetFieldName(JDWP::FieldId field_id)
@@ -1401,7 +1401,7 @@
  */
 static uint16_t MangleSlot(uint16_t slot, mirror::ArtMethod* m)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item == nullptr) {
     // We should not get here for a method without code (native, proxy or abstract). Log it and
     // return the slot as is since all registers are arguments.
@@ -1423,7 +1423,7 @@
  */
 static uint16_t DemangleSlot(uint16_t slot, mirror::ArtMethod* m)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item == nullptr) {
     // We should not get here for a method without code (native, proxy or abstract). Log it and
     // return the slot as is since all registers are arguments.
@@ -1480,10 +1480,9 @@
 
   for (size_t i = 0; i < direct_method_count + virtual_method_count; ++i) {
     mirror::ArtMethod* m = (i < direct_method_count) ? c->GetDirectMethod(i) : c->GetVirtualMethod(i - direct_method_count);
-    MethodHelper mh(m);
     expandBufAddMethodId(pReply, ToMethodId(m));
-    expandBufAddUtf8String(pReply, mh.GetName());
-    expandBufAddUtf8String(pReply, mh.GetSignature().ToString());
+    expandBufAddUtf8String(pReply, m->GetName());
+    expandBufAddUtf8String(pReply, m->GetSignature().ToString());
     if (with_generic) {
       static const char genericSignature[1] = "";
       expandBufAddUtf8String(pReply, genericSignature);
@@ -1525,8 +1524,7 @@
     }
   };
   mirror::ArtMethod* m = FromMethodId(method_id);
-  MethodHelper mh(m);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   uint64_t start, end;
   if (code_item == nullptr) {
     DCHECK(m->IsNative() || m->IsProxyMethod());
@@ -1550,25 +1548,30 @@
   context.pReply = pReply;
 
   if (code_item != nullptr) {
-    mh.GetDexFile().DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
-                                    DebugCallbackContext::Callback, NULL, &context);
+    m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
+                                     DebugCallbackContext::Callback, NULL, &context);
   }
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
 }
 
-void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool with_generic, JDWP::ExpandBuf* pReply) {
+void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool with_generic,
+                              JDWP::ExpandBuf* pReply) {
   struct DebugCallbackContext {
     mirror::ArtMethod* method;
     JDWP::ExpandBuf* pReply;
     size_t variable_count;
     bool with_generic;
 
-    static void Callback(void* context, uint16_t slot, uint32_t startAddress, uint32_t endAddress, const char* name, const char* descriptor, const char* signature)
+    static void Callback(void* context, uint16_t slot, uint32_t startAddress, uint32_t endAddress,
+                         const char* name, const char* descriptor, const char* signature)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context);
 
-      VLOG(jdwp) << StringPrintf("    %2zd: %d(%d) '%s' '%s' '%s' actual slot=%d mangled slot=%d", pContext->variable_count, startAddress, endAddress - startAddress, name, descriptor, signature, slot, MangleSlot(slot, pContext->method));
+      VLOG(jdwp) << StringPrintf("    %2zd: %d(%d) '%s' '%s' '%s' actual slot=%d mangled slot=%d",
+                                 pContext->variable_count, startAddress, endAddress - startAddress,
+                                 name, descriptor, signature, slot,
+                                 MangleSlot(slot, pContext->method));
 
       slot = MangleSlot(slot, pContext->method);
 
@@ -1585,11 +1588,10 @@
     }
   };
   mirror::ArtMethod* m = FromMethodId(method_id);
-  MethodHelper mh(m);
 
   // arg_count considers doubles and longs to take 2 units.
   // variable_count considers everything to take 1 unit.
-  std::string shorty(mh.GetShorty());
+  std::string shorty(m->GetShorty());
   expandBufAdd4BE(pReply, mirror::ArtMethod::NumArgRegisters(shorty));
 
   // We don't know the total number of variables yet, so leave a blank and update it later.
@@ -1602,10 +1604,11 @@
   context.variable_count = 0;
   context.with_generic = with_generic;
 
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item != nullptr) {
-    mh.GetDexFile().DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(), NULL,
-                                    DebugCallbackContext::Callback, &context);
+    m->GetDexFile()->DecodeDebugInfo(
+        code_item, m->IsStatic(), m->GetDexMethodIndex(), NULL, DebugCallbackContext::Callback,
+        &context);
   }
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
@@ -1614,7 +1617,7 @@
 void Dbg::OutputMethodReturnValue(JDWP::MethodId method_id, const JValue* return_value,
                                   JDWP::ExpandBuf* pReply) {
   mirror::ArtMethod* m = FromMethodId(method_id);
-  JDWP::JdwpTag tag = BasicTagFromDescriptor(MethodHelper(m).GetShorty());
+  JDWP::JdwpTag tag = BasicTagFromDescriptor(m->GetShorty());
   OutputJValue(tag, return_value, pReply);
 }
 
@@ -1632,8 +1635,7 @@
   if (m == NULL) {
     return JDWP::ERR_INVALID_METHODID;
   }
-  MethodHelper mh(m);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   size_t byte_count = code_item->insns_size_in_code_units_ * 2;
   const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
   const uint8_t* end = begin + byte_count;
@@ -2875,18 +2877,18 @@
 
 static bool IsMethodPossiblyInlined(Thread* self, mirror::ArtMethod* m)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  MethodHelper mh(m);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   if (code_item == nullptr) {
     // TODO We should not be asked to watch location in a native or abstract method so the code item
     // should never be null. We could just check we never encounter this case.
     return false;
   }
   StackHandleScope<2> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
-  verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
-                                    &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
+  mirror::Class* declaring_class = m->GetDeclaringClass();
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
+  verifier::MethodVerifier verifier(dex_cache->GetDexFile(), &dex_cache, &class_loader,
+                                    &m->GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                     m->GetAccessFlags(), false, true, false);
   // Note: we don't need to verify the method.
   return InlineMethodAnalyser::AnalyseMethodCode(&verifier, nullptr);
@@ -3156,11 +3158,10 @@
   single_step_control->dex_pcs.clear();
   mirror::ArtMethod* m = single_step_control->method;
   if (!m->IsNative()) {
-    MethodHelper mh(m);
-    const DexFile::CodeItem* const code_item = mh.GetCodeItem();
+    const DexFile::CodeItem* const code_item = m->GetCodeItem();
     DebugCallbackContext context(single_step_control, line_number, code_item);
-    mh.GetDexFile().DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
-                                    DebugCallbackContext::Callback, NULL, &context);
+    m->GetDexFile()->DecodeDebugInfo(code_item, m->IsStatic(), m->GetDexMethodIndex(),
+                                     DebugCallbackContext::Callback, NULL, &context);
   }
 
   //
@@ -3308,32 +3309,41 @@
     }
 
     // Check the argument list matches the method.
-    MethodHelper mh(m);
-    if (mh.GetShortyLength() - 1 != arg_count) {
+    uint32_t shorty_len = 0;
+    const char* shorty = m->GetShorty(&shorty_len);
+    if (shorty_len - 1 != arg_count) {
       return JDWP::ERR_ILLEGAL_ARGUMENT;
     }
-    const char* shorty = mh.GetShorty();
-    const DexFile::TypeList* types = mh.GetParameterTypeList();
-    for (size_t i = 0; i < arg_count; ++i) {
-      if (shorty[i + 1] != JdwpTagToShortyChar(arg_types[i])) {
-        return JDWP::ERR_ILLEGAL_ARGUMENT;
-      }
 
-      if (shorty[i + 1] == 'L') {
-        // Did we really get an argument of an appropriate reference type?
-        mirror::Class* parameter_type = mh.GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
-        mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i]);
-        if (argument == ObjectRegistry::kInvalidObject) {
-          return JDWP::ERR_INVALID_OBJECT;
-        }
-        if (argument != NULL && !argument->InstanceOf(parameter_type)) {
+    {
+      StackHandleScope<3> hs(soa.Self());
+      MethodHelper mh(hs.NewHandle(m));
+      HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&receiver));
+      HandleWrapper<mirror::Class> h_klass(hs.NewHandleWrapper(&c));
+      const DexFile::TypeList* types = m->GetParameterTypeList();
+      for (size_t i = 0; i < arg_count; ++i) {
+        if (shorty[i + 1] != JdwpTagToShortyChar(arg_types[i])) {
           return JDWP::ERR_ILLEGAL_ARGUMENT;
         }
 
-        // Turn the on-the-wire ObjectId into a jobject.
-        jvalue& v = reinterpret_cast<jvalue&>(arg_values[i]);
-        v.l = gRegistry->GetJObject(arg_values[i]);
+        if (shorty[i + 1] == 'L') {
+          // Did we really get an argument of an appropriate reference type?
+          mirror::Class* parameter_type = mh.GetClassFromTypeIdx(types->GetTypeItem(i).type_idx_);
+          mirror::Object* argument = gRegistry->Get<mirror::Object*>(arg_values[i]);
+          if (argument == ObjectRegistry::kInvalidObject) {
+            return JDWP::ERR_INVALID_OBJECT;
+          }
+          if (argument != NULL && !argument->InstanceOf(parameter_type)) {
+            return JDWP::ERR_ILLEGAL_ARGUMENT;
+          }
+
+          // Turn the on-the-wire ObjectId into a jobject.
+          jvalue& v = reinterpret_cast<jvalue&>(arg_values[i]);
+          v.l = gRegistry->GetJObject(arg_values[i]);
+        }
       }
+      // Update in case it moved.
+      m = mh.GetMethod();
     }
 
     req->receiver = receiver;
@@ -3452,7 +3462,7 @@
   mirror::Throwable* exception = soa.Self()->GetException(NULL);
   soa.Self()->ClearException();
   pReq->exception = gRegistry->Add(exception);
-  pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.Get()).GetShorty());
+  pReq->result_tag = BasicTagFromDescriptor(m.Get()->GetShorty());
   if (pReq->exception != 0) {
     VLOG(jdwp) << "  JDWP invocation returning with exception=" << exception
         << " " << exception->Dump();
@@ -4296,10 +4306,10 @@
   DISALLOW_COPY_AND_ASSIGN(StringTable);
 };
 
-static const char* GetMethodSourceFile(MethodHelper* mh)
+static const char* GetMethodSourceFile(mirror::ArtMethod* method)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(mh != nullptr);
-  const char* source_file = mh->GetDeclaringClassSourceFile();
+  DCHECK(method != nullptr);
+  const char* source_file = method->GetDeclaringClassSourceFile();
   return (source_file != nullptr) ? source_file : "";
 }
 
@@ -4368,14 +4378,12 @@
 
       class_names.Add(record->type->GetDescriptor().c_str());
 
-      MethodHelper mh;
       for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
         mirror::ArtMethod* m = record->stack[i].method;
         if (m != NULL) {
-          mh.ChangeMethod(m);
-          class_names.Add(mh.GetDeclaringClassDescriptor());
-          method_names.Add(mh.GetName());
-          filenames.Add(GetMethodSourceFile(&mh));
+          class_names.Add(m->GetDeclaringClassDescriptor());
+          method_names.Add(m->GetName());
+          filenames.Add(GetMethodSourceFile(m));
         }
       }
 
@@ -4427,17 +4435,16 @@
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
       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
-        mh.ChangeMethod(record->stack[stack_frame].method);
-        size_t class_name_index = class_names.IndexOf(mh.GetDeclaringClassDescriptor());
-        size_t method_name_index = method_names.IndexOf(mh.GetName());
-        size_t file_name_index = filenames.IndexOf(GetMethodSourceFile(&mh));
+        mirror::ArtMethod* m = record->stack[stack_frame].method;
+        size_t class_name_index = class_names.IndexOf(m->GetDeclaringClassDescriptor());
+        size_t method_name_index = method_names.IndexOf(m->GetName());
+        size_t file_name_index = filenames.IndexOf(GetMethodSourceFile(m));
         JDWP::Append2BE(bytes, class_name_index);
         JDWP::Append2BE(bytes, method_name_index);
         JDWP::Append2BE(bytes, file_name_index);
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 320273d..a0e32f5 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -189,18 +189,21 @@
       // Do nothing.
       return zero;
     } else {
+      StackHandleScope<1> hs(soa.Self());
+      MethodHelper mh_interface_method(
+          hs.NewHandle(soa.Decode<mirror::ArtMethod*>(interface_method_jobj)));
+      // This can cause thread suspension.
+      mirror::Class* result_type = mh_interface_method.GetReturnType();
       mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
       mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
-      mirror::ArtMethod* interface_method =
-          soa.Decode<mirror::ArtMethod*>(interface_method_jobj);
-      mirror::Class* result_type = MethodHelper(interface_method).GetReturnType();
       mirror::ArtMethod* proxy_method;
-      if (interface_method->GetDeclaringClass()->IsInterface()) {
-        proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+      if (mh_interface_method.GetMethod()->GetDeclaringClass()->IsInterface()) {
+        proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
+            mh_interface_method.GetMethod());
       } else {
         // Proxy dispatch to a method defined in Object.
-        DCHECK(interface_method->GetDeclaringClass()->IsObjectClass());
-        proxy_method = interface_method;
+        DCHECK(mh_interface_method.GetMethod()->GetDeclaringClass()->IsObjectClass());
+        proxy_method = mh_interface_method.GetMethod();
       }
       ThrowLocation throw_location(rcvr, proxy_method, -1);
       JValue result_unboxed;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index d0ae746..09899c0 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -433,9 +433,8 @@
       if (access_check &&
           (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) {
         // Behavior to agree with that of the verifier.
-        MethodHelper mh(resolved_method);
-        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(),
-                               mh.GetSignature());
+        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+                               resolved_method->GetName(), resolved_method->GetSignature());
         return nullptr;  // Failure.
       }
       DCHECK(vtable != nullptr);
@@ -450,9 +449,8 @@
         vtable = (super_class != nullptr) ? super_class->GetVTable() : nullptr;
         if (vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength())) {
           // Behavior to agree with that of the verifier.
-          MethodHelper mh(resolved_method);
-          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(),
-                                 mh.GetSignature());
+          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+                                 resolved_method->GetName(), resolved_method->GetSignature());
           return nullptr;  // Failure.
         }
       } else {
@@ -682,11 +680,13 @@
     JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str());
   }
   // Make sure that the result is an instance of the type this method was expected to return.
-  mirror::Class* return_type = MethodHelper(m).GetReturnType();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
+  mirror::Class* return_type = MethodHelper(h_m).GetReturnType();
 
   if (!o->InstanceOf(return_type)) {
-    JniAbortF(NULL, "attempt to return an instance of %s from %s",
-              PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
+    JniAbortF(NULL, "attempt to return an instance of %s from %s", PrettyTypeOf(o).c_str(),
+              PrettyMethod(h_m.Get()).c_str());
   }
 }
 
diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
index 1005d0e..335a617 100644
--- a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
@@ -26,7 +26,7 @@
                                                        mirror::Array* array,
                                                        uint32_t payload_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
+  const DexFile::CodeItem* code_item = method->GetCodeItem();
   const Instruction::ArrayDataPayload* payload =
       reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item->insns_ + payload_offset);
   DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
index 3a898e8..eb50ec3 100644
--- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
@@ -41,9 +41,8 @@
 
   // When we return, the caller will branch to this address, so it had better not be 0!
   if (UNLIKELY(code == NULL)) {
-      MethodHelper mh(method);
       LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
-                 << " location: " << mh.GetDexFile().GetLocation();
+                 << " location: " << method->GetDexFile()->GetLocation();
   }
   return method;
 }
diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
index 1fdb832..189e6b5 100644
--- a/runtime/entrypoints/portable/portable_throw_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
@@ -79,8 +79,9 @@
     return -1;
   }
   mirror::Class* exception_type = exception->GetClass();
-  MethodHelper mh(current_method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  StackHandleScope<1> hs(self);
+  MethodHelper mh(hs.NewHandle(current_method));
+  const DexFile::CodeItem* code_item = current_method->GetCodeItem();
   DCHECK_LT(ti_offset, code_item->tries_size_);
   const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
 
@@ -102,7 +103,7 @@
       // TODO: check, the verifier (class linker?) should take care of resolving all exception
       //       classes early.
       LOG(WARNING) << "Unresolved exception class when finding catch block: "
-          << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
+          << current_method->GetTypeDescriptorFromTypeIdx(iter_type_idx);
     } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
       catch_dex_pc = it.GetHandlerAddress();
       result = iter_index;
@@ -112,13 +113,11 @@
   }
   if (result != -1) {
     // Handler found.
-    Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self,
-                                                                   throw_location,
-                                                                   current_method,
-                                                                   catch_dex_pc,
-                                                                   exception);
+    Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(
+        self, throw_location, current_method, catch_dex_pc, exception);
     // If the catch block has no move-exception then clear the exception for it.
-    const Instruction* first_catch_instr = Instruction::At(&mh.GetCodeItem()->insns_[catch_dex_pc]);
+    const Instruction* first_catch_instr = Instruction::At(
+        &current_method->GetCodeItem()->insns_[catch_dex_pc]);
     if (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION) {
       self->ClearException();
     }
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 3756f47..6825e78 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -196,8 +196,9 @@
     return 0;
   } else {
     const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
-    MethodHelper mh(method);
-    const DexFile::CodeItem* code_item = mh.GetCodeItem();
+    StackHandleScope<2> hs(self);
+    MethodHelper mh(hs.NewHandle(method));
+    const DexFile::CodeItem* code_item = method->GetCodeItem();
     uint16_t num_regs = code_item->registers_size_;
     void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
     ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
@@ -214,7 +215,6 @@
 
     if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
       // Ensure static method's class is initialized.
-      StackHandleScope<1> hs(self);
       Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
       if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
         DCHECK(Thread::Current()->IsExceptionPending());
@@ -294,7 +294,8 @@
   jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
 
   // Placing arguments into args vector and remove the receiver.
-  MethodHelper proxy_mh(proxy_method);
+  StackHandleScope<1> hs(self);
+  MethodHelper proxy_mh(hs.NewHandle(proxy_method));
   std::vector<jvalue> args;
   BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
   local_ref_visitor.VisitArguments();
@@ -327,7 +328,7 @@
   InvokeType invoke_type;
   bool is_range;
   if (called->IsRuntimeMethod()) {
-    const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
+    const DexFile::CodeItem* code = 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();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 5374f22..05033fc 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -474,16 +474,16 @@
   } else {
     DCHECK(!method->IsNative()) << PrettyMethod(method);
     const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
-    MethodHelper mh(method);
-    const DexFile::CodeItem* code_item = mh.GetCodeItem();
+    const DexFile::CodeItem* code_item = method->GetCodeItem();
     DCHECK(code_item != nullptr) << PrettyMethod(method);
     uint16_t num_regs = code_item->registers_size_;
     void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
     ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
                                                   method, 0, memory));
     size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
-    BuildQuickShadowFrameVisitor shadow_frame_builder(sp, mh.IsStatic(), mh.GetShorty(),
-                                                      mh.GetShortyLength(),
+    uint32_t shorty_len = 0;
+    const char* shorty = method->GetShorty(&shorty_len);
+    BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
                                                       shadow_frame, first_arg_reg);
     shadow_frame_builder.VisitArguments();
     // Push a transition back into managed code onto the linked list in thread.
@@ -503,6 +503,8 @@
       }
     }
 
+    StackHandleScope<1> hs(self);
+    MethodHelper mh(hs.NewHandle(method));
     JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
     // Pop transition.
     self->PopManagedStackFragment(fragment);
@@ -604,11 +606,13 @@
   jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
 
   // Placing arguments into args vector and remove the receiver.
-  MethodHelper proxy_mh(proxy_method);
-  DCHECK(!proxy_mh.IsStatic()) << PrettyMethod(proxy_method);
+  mirror::ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy();
+  CHECK(!non_proxy_method->IsStatic()) << PrettyMethod(proxy_method) << " "
+      << PrettyMethod(non_proxy_method);
   std::vector<jvalue> args;
-  BuildQuickArgumentVisitor local_ref_visitor(sp, proxy_mh.IsStatic(), proxy_mh.GetShorty(),
-                                              proxy_mh.GetShortyLength(), &soa, &args);
+  uint32_t shorty_len = 0;
+  const char* shorty = proxy_method->GetShorty(&shorty_len);
+  BuildQuickArgumentVisitor local_ref_visitor(sp, false, shorty, shorty_len, &soa, &args);
 
   local_ref_visitor.VisitArguments();
   DCHECK_GT(args.size(), 0U) << PrettyMethod(proxy_method);
@@ -623,8 +627,7 @@
   // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
   // that performs allocations.
   self->EndAssertNoThreadSuspension(old_cause);
-  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
-                                               rcvr_jobj, interface_method_jobj, args);
+  JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
   // Restore references which might have moved.
   local_ref_visitor.FixupReferences();
   return result.GetJ();
@@ -691,11 +694,8 @@
   if (called->IsRuntimeMethod()) {
     uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
     const DexFile::CodeItem* code;
-    {
-      MethodHelper mh(caller);
-      dex_file = &mh.GetDexFile();
-      code = mh.GetCodeItem();
-    }
+    dex_file = caller->GetDexFile();
+    code = 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();
@@ -751,7 +751,7 @@
 
   } else {
     invoke_type = kStatic;
-    dex_file = &MethodHelper(called).GetDexFile();
+    dex_file = called->GetDexFile();
     dex_method_idx = called->GetDexMethodIndex();
   }
   uint32_t shorty_len;
@@ -797,9 +797,10 @@
         // Calling from one dex file to another, need to compute the method index appropriate to
         // the caller's dex file. Since we get here only if the original called was a runtime
         // method, we've got the correct dex_file and a dex_method_idx from above.
-        DCHECK(&MethodHelper(caller).GetDexFile() == dex_file);
-        uint32_t method_index =
-            MethodHelper(called).FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
+        DCHECK_EQ(caller->GetDexFile(), dex_file);
+        StackHandleScope<1> hs(self);
+        MethodHelper mh(hs.NewHandle(called));
+        uint32_t method_index = mh.FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
         if (method_index != DexFile::kDexNoIndex) {
           caller->GetDexCacheResolvedMethods()->Set<false>(method_index, called);
         }
@@ -1511,10 +1512,9 @@
   DCHECK(called->IsNative()) << PrettyMethod(called, true);
 
   // run the visitor
-  MethodHelper mh(called);
-
-  BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), mh.GetShorty(), mh.GetShortyLength(),
-                                      self);
+  uint32_t shorty_len = 0;
+  const char* shorty = called->GetShorty(&shorty_len);
+  BuildGenericJniFrameVisitor visitor(&sp, called->IsStatic(), shorty, shorty_len, self);
   visitor.VisitArguments();
   visitor.FinalizeHandleScope(self);
 
@@ -1555,7 +1555,7 @@
 
       // End JNI, as the assembly will move to deliver the exception.
       jobject lock = called->IsSynchronized() ? visitor.GetFirstHandleScopeJObject() : nullptr;
-      if (mh.GetShorty()[0] == 'L') {
+      if (shorty[0] == 'L') {
         artQuickGenericJniEndJNIRef(self, cookie, nullptr, lock);
       } else {
         artQuickGenericJniEndJNINonRef(self, cookie, lock);
@@ -1594,8 +1594,7 @@
     lock = table->GetHandle(0).ToJObject();
   }
 
-  MethodHelper mh(called);
-  char return_shorty_char = mh.GetShorty()[0];
+  char return_shorty_char = called->GetShorty()[0];
 
   if (return_shorty_char == 'L') {
     return artQuickGenericJniEndJNIRef(self, cookie, result.l, lock);
@@ -1721,7 +1720,7 @@
 
   // When we return, the caller will branch to this address, so it had better not be 0!
   DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method) << " location: "
-      << MethodHelper(method).GetDexFile().GetLocation();
+      << method->GetDexFile()->GetLocation();
 
   return GetSuccessValue(code, method);
 }
@@ -1870,7 +1869,7 @@
     uintptr_t caller_pc = 0;
 #endif
     uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
-    const DexFile::CodeItem* code = MethodHelper(caller_method).GetCodeItem();
+    const DexFile::CodeItem* code = caller_method->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();
@@ -1908,7 +1907,7 @@
 
   // When we return, the caller will branch to this address, so it had better not be 0!
   DCHECK(code != nullptr) << "Code was NULL in method: " << PrettyMethod(method) << " location: "
-      << MethodHelper(method).GetDexFile().GetLocation();
+      << method->GetDexFile()->GetLocation();
 
   return GetSuccessValue(code, method);
 }
diff --git a/runtime/handle.h b/runtime/handle.h
index b70f651..7e13601 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -26,18 +26,20 @@
 
 class Thread;
 
+template<class T> class Handle;
+
 template<class T>
-class Handle {
+class ConstHandle {
  public:
-  Handle() : reference_(nullptr) {
+  ConstHandle() : reference_(nullptr) {
   }
-  Handle(const Handle<T>& handle) ALWAYS_INLINE : reference_(handle.reference_) {
+  ConstHandle(const ConstHandle<T>& handle) ALWAYS_INLINE : reference_(handle.reference_) {
   }
-  Handle<T>& operator=(const Handle<T>& handle) ALWAYS_INLINE {
+  ConstHandle<T>& operator=(const ConstHandle<T>& handle) ALWAYS_INLINE {
     reference_ = handle.reference_;
     return *this;
   }
-  explicit Handle(StackReference<T>* reference) ALWAYS_INLINE : reference_(reference) {
+  explicit ConstHandle(StackReference<T>* reference) ALWAYS_INLINE : reference_(reference) {
   }
   T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
     return *Get();
@@ -48,11 +50,6 @@
   T* Get() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
     return reference_->AsMirrorPtr();
   }
-  T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
-    T* old = reference_->AsMirrorPtr();
-    reference_->Assign(reference);
-    return old;
-  }
   jobject ToJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
     if (UNLIKELY(reference_->AsMirrorPtr() == nullptr)) {
       // Special case so that we work with NullHandles.
@@ -65,17 +62,62 @@
   StackReference<T>* reference_;
 
   template<typename S>
-  explicit Handle(StackReference<S>* reference)
+  explicit ConstHandle(StackReference<S>* reference)
       : reference_(reinterpret_cast<StackReference<T>*>(reference)) {
   }
   template<typename S>
-  explicit Handle(const Handle<S>& handle)
+  explicit ConstHandle(const ConstHandle<S>& handle)
       : reference_(reinterpret_cast<StackReference<T>*>(handle.reference_)) {
   }
 
   StackReference<T>* GetReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
     return reference_;
   }
+  const StackReference<T>* GetReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE {
+    return reference_;
+  }
+
+ private:
+  friend class BuildGenericJniFrameVisitor;
+  template<class S> friend class ConstHandle;
+  friend class HandleScope;
+  template<class S> friend class HandleWrapper;
+  template<size_t kNumReferences> friend class StackHandleScope;
+};
+
+template<class T>
+class Handle : public ConstHandle<T> {
+ public:
+  Handle() {
+  }
+  Handle(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE
+      : ConstHandle<T>(handle.reference_) {
+  }
+  Handle<T>& operator=(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE {
+    ConstHandle<T>::operator=(handle);
+    return *this;
+  }
+  explicit Handle(StackReference<T>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      ALWAYS_INLINE : ConstHandle<T>(reference) {
+  }
+  T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    StackReference<T>* ref = ConstHandle<T>::GetReference();
+    T* const old = ref->AsMirrorPtr();
+    ref->Assign(reference);
+    return old;
+  }
+
+ protected:
+  template<typename S>
+  explicit Handle(StackReference<S>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : ConstHandle<T>(reference) {
+  }
+  template<typename S>
+  explicit Handle(const Handle<S>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : ConstHandle<T>(handle) {
+  }
 
  private:
   friend class BuildGenericJniFrameVisitor;
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 194cb18..8e23d1b 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -859,7 +859,8 @@
   CheckStackDepth(self, instrumentation_frame, 0);
 
   mirror::ArtMethod* method = instrumentation_frame.method_;
-  char return_shorty = MethodHelper(method).GetShorty()[0];
+  uint32_t length;
+  char return_shorty = method->GetShorty(&length)[0];
   JValue return_value;
   if (return_shorty == 'V') {
     return_value.SetJ(0);
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 9cfba8d..6dbc6a0 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -400,8 +400,7 @@
   }
 
   const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = method->GetCodeItem();
   uint16_t num_regs;
   uint16_t num_ins;
   if (code_item != NULL) {
@@ -413,7 +412,7 @@
     return;
   } else {
     DCHECK(method->IsNative());
-    num_regs = num_ins = ArtMethod::NumArgRegisters(mh.GetShorty());
+    num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty());
     if (!method->IsStatic()) {
       num_regs++;
       num_ins++;
@@ -431,9 +430,10 @@
     shadow_frame->SetVRegReference(cur_reg, receiver);
     ++cur_reg;
   }
-  const char* shorty = mh.GetShorty();
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
   for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) {
-    DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
+    DCHECK_LT(shorty_pos + 1, shorty_len);
     switch (shorty[shorty_pos + 1]) {
       case 'L': {
         Object* o = reinterpret_cast<StackReference<Object>*>(&args[arg_pos])->AsMirrorPtr();
@@ -465,6 +465,8 @@
     }
   }
   if (LIKELY(!method->IsNative())) {
+    StackHandleScope<1> hs(self);
+    MethodHelper mh(hs.NewHandle(method));
     JValue r = Execute(self, mh, code_item, *shadow_frame, JValue());
     if (result != NULL) {
       *result = r;
@@ -488,11 +490,11 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   JValue value;
   value.SetJ(ret_val->GetJ());  // Set value to last known result in case the shadow frame chain is empty.
-  MethodHelper mh;
   while (shadow_frame != NULL) {
     self->SetTopOfShadowStack(shadow_frame);
-    mh.ChangeMethod(shadow_frame->GetMethod());
-    const DexFile::CodeItem* code_item = mh.GetCodeItem();
+    StackHandleScope<1> hs(self);
+    MethodHelper mh(hs.NewHandle(shadow_frame->GetMethod()));
+    const DexFile::CodeItem* code_item = mh.GetMethod()->GetCodeItem();
     value = Execute(self, mh, code_item, *shadow_frame, value);
     ShadowFrame* old_frame = shadow_frame;
     shadow_frame = shadow_frame->GetLink();
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index a66bd94..c6e05ae 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -54,8 +54,7 @@
 bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
             const Instruction* inst, uint16_t inst_data, JValue* result) {
   // Compute method information.
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = method->GetCodeItem();
   const uint16_t num_ins = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
   uint16_t num_regs;
   if (LIKELY(code_item != NULL)) {
@@ -73,6 +72,8 @@
 
   // Initialize new shadow frame.
   const size_t first_dest_reg = num_regs - num_ins;
+  StackHandleScope<1> hs(self);
+  MethodHelper mh(hs.NewHandle(method));
   if (do_assignability_check) {
     // Slow path.
     // We might need to do class loading, which incurs a thread state change to kNative. So
@@ -82,8 +83,9 @@
 
     // We need to do runtime check on reference assignment. We need to load the shorty
     // to get the exact type of each reference argument.
-    const DexFile::TypeList* params = mh.GetParameterTypeList();
-    const char* shorty = mh.GetShorty();
+    const DexFile::TypeList* params = method->GetParameterTypeList();
+    uint32_t shorty_len = 0;
+    const char* shorty = method->GetShorty(&shorty_len);
 
     // TODO: find a cleaner way to separate non-range and range information without duplicating code.
     uint32_t arg[5];  // only used in invoke-XXX.
@@ -98,13 +100,13 @@
     size_t dest_reg = first_dest_reg;
     size_t arg_offset = 0;
     if (!method->IsStatic()) {
-      size_t receiver_reg = (is_range) ? vregC : arg[0];
+      size_t receiver_reg = is_range ? vregC : arg[0];
       new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
       ++dest_reg;
       ++arg_offset;
     }
     for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) {
-      DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
+      DCHECK_LT(shorty_pos + 1, shorty_len);
       const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset];
       switch (shorty[shorty_pos + 1]) {
         case 'L': {
@@ -120,7 +122,7 @@
               self->ThrowNewExceptionF(self->GetCurrentLocationForThrow(),
                                        "Ljava/lang/VirtualMachineError;",
                                        "Invoking %s with bad arg %d, type '%s' not instance of '%s'",
-                                       mh.GetName(), shorty_pos,
+                                       method->GetName(), shorty_pos,
                                        o->GetClass()->GetDescriptor().c_str(),
                                        arg_type->GetDescriptor().c_str());
               return false;
@@ -368,8 +370,9 @@
     Object* obj = shadow_frame->GetVRegReference(arg_offset);
     result->SetI(obj->IdentityHashCode());
   } else if (name == "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") {
-    ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
-    result->SetL(MethodHelper(method).GetNameAsString());
+    StackHandleScope<1> hs(self);
+    MethodHelper mh(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsArtMethod()));
+    result->SetL(mh.GetNameAsString(self));
   } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)" ||
              name == "void java.lang.System.arraycopy(char[], int, char[], int, int)") {
     // Special case array copying without initializing System.
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 6e136d6..88a8468 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -604,10 +604,15 @@
   ThrowLocation throw_location;
   mirror::Throwable* exception = self->GetException(&throw_location);
   bool clear_exception = false;
-  StackHandleScope<3> hs(self);
-  Handle<mirror::Class> exception_class(hs.NewHandle(exception->GetClass()));
-  uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(exception_class, dex_pc,
-                                                                   &clear_exception);
+  uint32_t found_dex_pc;
+  {
+    StackHandleScope<3> hs(self);
+    Handle<mirror::Class> exception_class(hs.NewHandle(exception->GetClass()));
+    Handle<mirror::ArtMethod> h_method(hs.NewHandle(shadow_frame.GetMethod()));
+    HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&this_object));
+    found_dex_pc = mirror::ArtMethod::FindCatchBlock(h_method, exception_class, dex_pc,
+                                                     &clear_exception);
+  }
   if (found_dex_pc == DexFile::kDexNoIndex) {
     instrumentation->MethodUnwindEvent(self, this_object,
                                        shadow_frame.GetMethod(), dex_pc);
@@ -627,7 +632,7 @@
   SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 static inline void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
-  LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
+  LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(mh.GetMethod()->GetDexFile());
   exit(0);  // Unreachable, keep GCC happy.
 }
 
@@ -640,7 +645,7 @@
     std::ostringstream oss;
     oss << PrettyMethod(shadow_frame.GetMethod())
         << StringPrintf("\n0x%x: ", dex_pc)
-        << inst->DumpString(&mh.GetDexFile()) << "\n";
+        << inst->DumpString(mh.GetMethod()->GetDexFile()) << "\n";
     for (uint32_t i = 0; i < shadow_frame.NumberOfVRegs(); ++i) {
       uint32_t raw_value = shadow_frame.GetVReg(i);
       Object* ref_value = shadow_frame.GetVRegReference(i);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 623d9c3..19673ac 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -328,11 +328,13 @@
     if (UNLIKELY(self->TestAllFlags())) {
       CheckSuspend(self);
     }
-    Object* obj_result = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-    result.SetJ(0);
-    result.SetL(obj_result);
+    const uint8_t vreg_index = inst->VRegA_11x(inst_data);
+    Object* obj_result = shadow_frame.GetVRegReference(vreg_index);
     if (do_assignability_check && obj_result != NULL) {
-      Class* return_type = MethodHelper(shadow_frame.GetMethod()).GetReturnType();
+      StackHandleScope<1> hs(self);
+      MethodHelper mh(hs.NewHandle(shadow_frame.GetMethod()));
+      Class* return_type = mh.GetReturnType();
+      obj_result = shadow_frame.GetVRegReference(vreg_index);
       if (return_type == NULL) {
         // Return the pending exception.
         HANDLE_PENDING_EXCEPTION();
@@ -347,6 +349,7 @@
         HANDLE_PENDING_EXCEPTION();
       }
     }
+    result.SetL(obj_result);
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
     if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
       instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index d592a53..a43fad3 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -244,11 +244,14 @@
         if (UNLIKELY(self->TestAllFlags())) {
           CheckSuspend(self);
         }
-        Object* obj_result = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-        result.SetJ(0);
-        result.SetL(obj_result);
+        const size_t ref_idx = inst->VRegA_11x(inst_data);
+        Object* obj_result = shadow_frame.GetVRegReference(ref_idx);
         if (do_assignability_check && obj_result != NULL) {
-          Class* return_type = MethodHelper(shadow_frame.GetMethod()).GetReturnType();
+          StackHandleScope<1> hs(self);
+          MethodHelper mhs(hs.NewHandle(shadow_frame.GetMethod()));
+          Class* return_type = mhs.GetReturnType();
+          // Re-load since it might have moved.
+          obj_result = shadow_frame.GetVRegReference(ref_idx);
           if (return_type == NULL) {
             // Return the pending exception.
             HANDLE_PENDING_EXCEPTION();
@@ -263,6 +266,7 @@
             HANDLE_PENDING_EXCEPTION();
           }
         }
+        result.SetL(obj_result);
         if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
           instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
                                            shadow_frame.GetMethod(), inst->GetDexPc(insns),
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 5f4619b..8fcacc2 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -295,7 +295,9 @@
   if (UNLIKELY(entry_point == runtime->GetClassLinker()->GetQuickGenericJniTrampoline())) {
     // Generic JNI frame.
     DCHECK(IsNative());
-    uint32_t handle_refs = MethodHelper(this).GetNumberOfReferenceArgsWithoutReceiver() + 1;
+    StackHandleScope<1> hs(Thread::Current());
+    uint32_t handle_refs =
+        MethodHelper(hs.NewHandle(this)).GetNumberOfReferenceArgsWithoutReceiver() + 1;
     size_t scope_size = HandleScope::SizeOf(handle_refs);
     QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
 
@@ -314,10 +316,143 @@
 
 inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo(const void* code_pointer) {
   DCHECK(code_pointer != nullptr);
-  DCHECK(code_pointer == GetQuickOatCodePointer());
+  DCHECK_EQ(code_pointer, GetQuickOatCodePointer());
   return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
 }
 
+inline const DexFile* ArtMethod::GetDexFile() {
+  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetDexCache()->GetDexFile();
+}
+
+inline const char* ArtMethod::GetDeclaringClassDescriptor() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  uint32_t dex_method_idx = method->GetDexMethodIndex();
+  if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
+    return "<runtime method>";
+  }
+  const DexFile* dex_file = method->GetDexFile();
+  return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
+}
+
+inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->GetDexFile();
+  return dex_file->GetMethodShorty(dex_file->GetMethodId(method->GetDexMethodIndex()), out_length);
+}
+
+inline const Signature ArtMethod::GetSignature() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  uint32_t dex_method_idx = method->GetDexMethodIndex();
+  if (dex_method_idx != DexFile::kDexNoIndex) {
+    const DexFile* dex_file = method->GetDexFile();
+    return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
+  }
+  return Signature::NoSignature();
+}
+
+inline const char* ArtMethod::GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  uint32_t dex_method_idx = method->GetDexMethodIndex();
+  if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
+    const DexFile* dex_file = method->GetDexFile();
+    return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
+  }
+  Runtime* runtime = Runtime::Current();
+  if (method == runtime->GetResolutionMethod()) {
+    return "<runtime internal resolution method>";
+  } else if (method == runtime->GetImtConflictMethod()) {
+    return "<runtime internal imt conflict method>";
+  } else if (method == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
+    return "<runtime internal callee-save all registers method>";
+  } else if (method == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
+    return "<runtime internal callee-save reference registers method>";
+  } else if (method == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
+    return "<runtime internal callee-save reference and argument registers method>";
+  } else {
+    return "<unknown runtime internal method>";
+  }
+}
+
+inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  return method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset());
+}
+
+inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  return method->GetDexCacheResolvedTypes()->Get(type_idx) != nullptr;
+}
+
+inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  if (dex_pc == DexFile::kDexNoIndex) {
+    return method->IsNative() ? -2 : -1;
+  }
+  return method->GetDexFile()->GetLineNumFromPC(method, dex_pc);
+}
+
+inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->GetDexFile();
+  return dex_file->GetMethodPrototype(dex_file->GetMethodId(method->GetDexMethodIndex()));
+}
+
+inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->GetDexFile();
+  const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
+      dex_file->GetMethodId(method->GetDexMethodIndex()));
+  return dex_file->GetProtoParameters(proto);
+}
+
+inline const char* ArtMethod::GetDeclaringClassSourceFile() {
+  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetSourceFile();
+}
+
+inline uint16_t ArtMethod::GetClassDefIndex() {
+  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetDexClassDefIndex();
+}
+
+inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  return method->GetDexFile()->GetClassDef(GetClassDefIndex());
+}
+
+inline const char* ArtMethod::GetReturnTypeDescriptor() {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->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));
+}
+
+inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
+  mirror::ArtMethod* method = GetInterfaceMethodIfProxy();
+  const DexFile* dex_file = method->GetDexFile();
+  return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
+}
+
+inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
+  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetClassLoader();
+}
+
+inline mirror::DexCache* ArtMethod::GetDexCache() {
+  return GetInterfaceMethodIfProxy()->GetDeclaringClass()->GetDexCache();
+}
+
+inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy() {
+  mirror::Class* klass = GetDeclaringClass();
+  if (LIKELY(!klass->IsProxyClass())) {
+    return this;
+  }
+  mirror::ArtMethod* interface_method = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
+  DCHECK(interface_method != nullptr);
+  DCHECK_EQ(interface_method,
+            Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
+  return interface_method;
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index c01fc72..3db4be3 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -142,16 +142,16 @@
       CHECK_EQ(result,
                Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
     } else {
-      MethodHelper mh(this);
-      MethodHelper interface_mh;
+      StackHandleScope<2> hs(Thread::Current());
+      MethodHelper mh(hs.NewHandle(this));
+      MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
       IfTable* iftable = GetDeclaringClass()->GetIfTable();
       for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
         Class* interface = iftable->GetInterface(i);
         for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
-          ArtMethod* interface_method = interface->GetVirtualMethod(j);
-          interface_mh.ChangeMethod(interface_method);
+          interface_mh.ChangeMethod(interface->GetVirtualMethod(j));
           if (mh.HasSameNameAndSignature(&interface_mh)) {
-            result = interface_method;
+            result = interface_mh.GetMethod();
             break;
           }
         }
@@ -159,8 +159,10 @@
     }
   }
 #ifndef NDEBUG
-  MethodHelper result_mh(result);
-  DCHECK(result == NULL || MethodHelper(this).HasSameNameAndSignature(&result_mh));
+  StackHandleScope<2> hs(Thread::Current());
+  MethodHelper result_mh(hs.NewHandle(result));
+  MethodHelper this_mh(hs.NewHandle(this));
+  DCHECK(result == NULL || this_mh.HasSameNameAndSignature(&result_mh));
 #endif
   return result;
 }
@@ -229,10 +231,10 @@
   return 0;
 }
 
-uint32_t ArtMethod::FindCatchBlock(Handle<Class> exception_type, uint32_t dex_pc,
-                                   bool* has_no_move_exception) {
-  MethodHelper mh(this);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
+                                   uint32_t dex_pc, bool* has_no_move_exception) {
+  MethodHelper mh(h_this);
+  const DexFile::CodeItem* code_item = h_this->GetCodeItem();
   // Set aside the exception while we resolve its type.
   Thread* self = Thread::Current();
   ThrowLocation throw_location;
@@ -260,7 +262,7 @@
       // release its in use context at the end.
       delete self->GetLongJumpContext();
       LOG(WARNING) << "Unresolved exception class when finding catch block: "
-        << DescriptorToDot(mh.GetTypeDescriptorFromTypeIdx(iter_type_idx));
+        << DescriptorToDot(h_this->GetTypeDescriptorFromTypeIdx(iter_type_idx));
     } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) {
       found_dex_pc = it.GetHandlerAddress();
       break;
@@ -283,7 +285,7 @@
   if (kIsDebugBuild) {
     self->AssertThreadSuspensionIsAllowable();
     CHECK_EQ(kRunnable, self->GetState());
-    CHECK_STREQ(MethodHelper(this).GetShorty(), shorty);
+    CHECK_STREQ(GetShorty(), shorty);
   }
 
   // Push a transition back into managed code onto the linked list in thread.
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f901512..1c21b81 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -88,6 +88,11 @@
     return (GetAccessFlags() & kAccConstructor) != 0;
   }
 
+  // Returns true if the method is a class initializer.
+  bool IsClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return IsConstructor() && IsStatic();
+  }
+
   // Returns true if the method is static, private, or a constructor.
   bool IsDirect() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return IsDirect(GetAccessFlags());
@@ -216,14 +221,14 @@
   // Find the method that this method overrides
   ArtMethod* FindOverriddenMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
-              const char* shorty) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   EntryPointFromInterpreter* GetEntryPointFromInterpreter()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFieldPtr<EntryPointFromInterpreter*, kVerifyFlags>(
-               OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_));
+        OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_));
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -281,7 +286,7 @@
      *
      * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
      */
-    return (code <= pc && pc <= code + GetCodeSize());
+    return code <= pc && pc <= code + GetCodeSize();
   }
 
   void AssertPcIsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -398,8 +403,8 @@
   // Find the catch block for the given exception type and dex_pc. When a catch block is found,
   // indicates whether the found catch block is responsible for clearing the exception or whether
   // a move-exception instruction is present.
-  uint32_t FindCatchBlock(Handle<Class> exception_type, uint32_t dex_pc,
-                          bool* has_no_move_exception)
+  static uint32_t FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
+                                 uint32_t dex_pc, bool* has_no_move_exception)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetClass(Class* java_lang_reflect_ArtMethod);
@@ -414,6 +419,30 @@
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  const DexFile* GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    uint32_t unused_length;
+    return GetShorty(&unused_length);
+  }
+  const char* GetShorty(uint32_t* out_length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile::CodeItem* GetCodeItem() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool IsResolvedTypeIdx(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  protected:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class we are a part of.
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a409093..7b31a82 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -366,11 +366,9 @@
 }
 
 ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) {
-  MethodHelper mh;
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     ArtMethod* method = GetDirectMethod(i);
-    mh.ChangeMethod(method);
-    if (name == mh.GetName() && mh.GetSignature() == signature) {
+    if (name == method->GetName() && method->GetSignature() == signature) {
       return method;
     }
   }
@@ -378,11 +376,9 @@
 }
 
 ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) {
-  MethodHelper mh;
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     ArtMethod* method = GetDirectMethod(i);
-    mh.ChangeMethod(method);
-    if (name == mh.GetName() && signature == mh.GetSignature()) {
+    if (name == method->GetName() && signature == method->GetSignature()) {
       return method;
     }
   }
@@ -432,24 +428,19 @@
 }
 
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) {
-  MethodHelper mh;
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     ArtMethod* method = GetVirtualMethod(i);
-    mh.ChangeMethod(method);
-    if (name == mh.GetName() && mh.GetSignature() == signature) {
+    if (name == method->GetName() && method->GetSignature() == signature) {
       return method;
     }
   }
   return NULL;
 }
 
-ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name,
-                                            const Signature& signature) {
-  MethodHelper mh;
+ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) {
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     ArtMethod* method = GetVirtualMethod(i);
-    mh.ChangeMethod(method);
-    if (name == mh.GetName() && signature == mh.GetSignature()) {
+    if (name == method->GetName() && signature == method->GetSignature()) {
       return method;
     }
   }
@@ -501,13 +492,9 @@
 ArtMethod* Class::FindClassInitializer() {
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     ArtMethod* method = GetDirectMethod(i);
-    if (method->IsConstructor() && method->IsStatic()) {
-      if (kIsDebugBuild) {
-        MethodHelper mh(method);
-        CHECK(mh.IsClassInitializer());
-        CHECK_STREQ(mh.GetName(), "<clinit>");
-        CHECK_STREQ(mh.GetSignature().ToString().c_str(), "()V");
-      }
+    if (method->IsClassInitializer()) {
+      DCHECK_STREQ(method->GetName(), "<clinit>");
+      DCHECK_STREQ(method->GetSignature().ToString().c_str(), "()V");
       return method;
     }
   }
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 18e50ce..f85fb27 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -451,7 +451,7 @@
 
   jobject jclass_loader_1 = LoadDex("ProtoCompare");
   jobject jclass_loader_2 = LoadDex("ProtoCompare2");
-  StackHandleScope<2> hs(soa.Self());
+  StackHandleScope<4> hs(soa.Self());
   Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_1)));
   Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_2)));
 
@@ -461,33 +461,25 @@
   ASSERT_TRUE(klass2 != NULL);
 
   ArtMethod* m1_1 = klass1->GetVirtualMethod(0);
-  MethodHelper mh(m1_1);
-  EXPECT_STREQ(mh.GetName(), "m1");
+  EXPECT_STREQ(m1_1->GetName(), "m1");
   ArtMethod* m2_1 = klass1->GetVirtualMethod(1);
-  mh.ChangeMethod(m2_1);
-  EXPECT_STREQ(mh.GetName(), "m2");
+  EXPECT_STREQ(m2_1->GetName(), "m2");
   ArtMethod* m3_1 = klass1->GetVirtualMethod(2);
-  mh.ChangeMethod(m3_1);
-  EXPECT_STREQ(mh.GetName(), "m3");
+  EXPECT_STREQ(m3_1->GetName(), "m3");
   ArtMethod* m4_1 = klass1->GetVirtualMethod(3);
-  mh.ChangeMethod(m4_1);
-  EXPECT_STREQ(mh.GetName(), "m4");
+  EXPECT_STREQ(m4_1->GetName(), "m4");
 
   ArtMethod* m1_2 = klass2->GetVirtualMethod(0);
-  mh.ChangeMethod(m1_2);
-  EXPECT_STREQ(mh.GetName(), "m1");
+  EXPECT_STREQ(m1_2->GetName(), "m1");
   ArtMethod* m2_2 = klass2->GetVirtualMethod(1);
-  mh.ChangeMethod(m2_2);
-  EXPECT_STREQ(mh.GetName(), "m2");
+  EXPECT_STREQ(m2_2->GetName(), "m2");
   ArtMethod* m3_2 = klass2->GetVirtualMethod(2);
-  mh.ChangeMethod(m3_2);
-  EXPECT_STREQ(mh.GetName(), "m3");
+  EXPECT_STREQ(m3_2->GetName(), "m3");
   ArtMethod* m4_2 = klass2->GetVirtualMethod(3);
-  mh.ChangeMethod(m4_2);
-  EXPECT_STREQ(mh.GetName(), "m4");
+  EXPECT_STREQ(m4_2->GetName(), "m4");
 
-  mh.ChangeMethod(m1_1);
-  MethodHelper mh2(m1_2);
+  MethodHelper mh(hs.NewHandle(m1_1));
+  MethodHelper mh2(hs.NewHandle(m1_2));
   EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
   EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 6874fe5..6efc9e2 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -85,16 +85,14 @@
     ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
     int32_t depth = method_trace->GetLength() - 1;
     IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
-    MethodHelper mh;
     if (depth == 0) {
       result += "(Throwable with empty stack trace)";
     } else {
       for (int32_t i = 0; i < depth; ++i) {
-        ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
-        mh.ChangeMethod(method);
+        mirror::ArtMethod* method = down_cast<ArtMethod*>(method_trace->Get(i));
         uint32_t dex_pc = pc_trace->Get(i);
-        int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
-        const char* source_file = mh.GetDeclaringClassSourceFile();
+        int32_t line_number = method->GetLineNumFromDexPC(dex_pc);
+        const char* source_file = method->GetDeclaringClassSourceFile();
         result += StringPrintf("  at %s (%s:%d)\n", PrettyMethod(method, true).c_str(),
                                source_file, line_number);
       }
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index f73ef1e..a19445b 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -967,14 +967,13 @@
   }
 
   // <clinit> is another special case. The runtime holds the class lock while calling <clinit>.
-  MethodHelper mh(m);
-  if (mh.IsClassInitializer()) {
+  if (m->IsClassInitializer()) {
     callback(m->GetDeclaringClass(), callback_context);
     // Fall through because there might be synchronization in the user code too.
   }
 
   // Is there any reason to believe there's any synchronization in this method?
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  const DexFile::CodeItem* code_item = m->GetCodeItem();
   CHECK(code_item != NULL) << PrettyMethod(m);
   if (code_item->tries_size_ == 0) {
     return;  // No "tries" implies no synchronization, so no held locks to report.
@@ -1048,12 +1047,11 @@
     *line_number = 0;
     return;
   }
-  MethodHelper mh(method);
-  *source_file = mh.GetDeclaringClassSourceFile();
+  *source_file = method->GetDeclaringClassSourceFile();
   if (*source_file == NULL) {
     *source_file = "";
   }
-  *line_number = mh.GetLineNumFromDexPC(dex_pc);
+  *line_number = method->GetLineNumFromDexPC(dex_pc);
 }
 
 uint32_t Monitor::GetOwnerThreadId() {
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index a05ebe6..28ce8f3 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -121,12 +121,9 @@
 
 class MethodHelper {
  public:
-  MethodHelper() : method_(nullptr), shorty_(nullptr), shorty_len_(0) {}
-
-  explicit MethodHelper(mirror::ArtMethod* m)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : method_(nullptr), shorty_(nullptr), shorty_len_(0) {
-    SetMethod(m);
+  explicit MethodHelper(Handle<mirror::ArtMethod> m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : method_(m), shorty_(nullptr), shorty_len_(0) {
+    SetMethod(m.Get());
   }
 
   void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -135,48 +132,25 @@
     shorty_ = nullptr;
   }
 
-  mirror::ArtMethod* GetMethod() const {
-    return method_;
+  mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return method_->GetInterfaceMethodIfProxy();
   }
 
-  const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    uint32_t dex_method_idx = method_->GetDexMethodIndex();
-    if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
-      return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
-    } else {
-      Runtime* runtime = Runtime::Current();
-      if (method_ == runtime->GetResolutionMethod()) {
-        return "<runtime internal resolution method>";
-      } else if (method_ == runtime->GetImtConflictMethod()) {
-        return "<runtime internal imt conflict method>";
-      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
-        return "<runtime internal callee-save all registers method>";
-      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
-        return "<runtime internal callee-save reference registers method>";
-      } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
-        return "<runtime internal callee-save reference and argument registers method>";
-      } else {
-        return "<unknown runtime internal method>";
-      }
-    }
-  }
-
-  mirror::String* GetNameAsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    uint32_t dex_method_idx = method_->GetDexMethodIndex();
-    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
-    StackHandleScope<1> hs(Thread::Current());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
-    return GetClassLinker()->ResolveString(dex_file, method_id.name_idx_, dex_cache);
+  mirror::String* GetNameAsString(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    const DexFile* dex_file = method_->GetDexFile();
+    mirror::ArtMethod* method = method_->GetInterfaceMethodIfProxy();
+    uint32_t dex_method_idx = method->GetDexMethodIndex();
+    const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
+    StackHandleScope<1> hs(self);
+    Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+    return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_,
+                                                               dex_cache);
   }
 
   const char* GetShorty() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const char* result = shorty_;
     if (result == nullptr) {
-      const DexFile& dex_file = GetDexFile();
-      result = dex_file.GetMethodShorty(dex_file.GetMethodId(method_->GetDexMethodIndex()),
-                                        &shorty_len_);
+      result = method_->GetShorty(&shorty_len_);
       shorty_ = result;
     }
     return result;
@@ -203,94 +177,27 @@
     return refs;
   }
 
-  const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    uint32_t dex_method_idx = method_->GetDexMethodIndex();
-    if (dex_method_idx != DexFile::kDexNoIndex) {
-      return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx));
-    } else {
-      return Signature::NoSignature();
-    }
-  }
-
-  const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex()));
-  }
-
-  const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::ProtoId& proto = GetPrototype();
-    return GetDexFile().GetProtoParameters(proto);
-  }
-
+  // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
+  // number of bugs at call sites.
   mirror::Class* GetReturnType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    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);
+    mirror::ArtMethod* method = GetMethod();
+    const DexFile* dex_file = method->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, resolve);
   }
 
-  const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    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 GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (dex_pc == DexFile::kDexNoIndex) {
-      return method_->IsNative() ? -2 : -1;
-    } else {
-      const DexFile& dex_file = GetDexFile();
-      return dex_file.GetLineNumFromPC(method_, dex_pc);
-    }
-  }
-
-  const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    uint32_t dex_method_idx = method_->GetDexMethodIndex();
-    if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
-      return "<runtime method>";
-    }
-    return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx));
-  }
-
-  const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDeclaringClass()->GetSourceFile();
-  }
-
-  uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDeclaringClass()->GetDexClassDefIndex();
-  }
-
-  const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetDexFile().GetClassDef(GetClassDefIndex());
-  }
-
-  mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDeclaringClass()->GetClassLoader();
-  }
-
-  bool IsStatic() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->IsStatic();
-  }
-
-  bool IsClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->IsConstructor() && IsStatic();
-  }
-
   size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // "1 +" because the first in Args is the receiver.
     // "- 1" because we don't count the return type.
-    return (IsStatic() ? 0 : 1) + GetShortyLength() - 1;
+    return (method_->IsStatic() ? 0 : 1) + GetShortyLength() - 1;
   }
 
   // Get the primitive type associated with the given parameter.
   Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK_LT(param, NumArgs());
-    if (IsStatic()) {
+    if (GetMethod()->IsStatic()) {
       param++;  // 0th argument must skip return value at start of the shorty
     } else if (param == 0) {
       return Primitive::kPrimNot;
@@ -310,21 +217,20 @@
   }
 
   bool HasSameNameAndSignature(MethodHelper* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex());
-    if (GetDexCache() == other->GetDexCache()) {
+    const DexFile* dex_file = method_->GetDexFile();
+    const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
+    if (method_->GetDexCache() == other->method_->GetDexCache()) {
       const DexFile::MethodId& other_mid =
-          dex_file.GetMethodId(other->method_->GetDexMethodIndex());
+          dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
       return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_;
     }
-    const DexFile& other_dex_file = other->GetDexFile();
+    const DexFile* other_dex_file = other->method_->GetDexFile();
     const DexFile::MethodId& other_mid =
-        other_dex_file.GetMethodId(other->method_->GetDexMethodIndex());
-    if (!DexFileStringEquals(&dex_file, mid.name_idx_,
-                             &other_dex_file, other_mid.name_idx_)) {
+        other_dex_file->GetMethodId(other->GetMethod()->GetDexMethodIndex());
+    if (!DexFileStringEquals(dex_file, mid.name_idx_, other_dex_file, other_mid.name_idx_)) {
       return false;  // Name mismatch.
     }
-    return dex_file.GetMethodSignature(mid) == other_dex_file.GetMethodSignature(other_mid);
+    return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
   }
 
   bool HasSameSignatureWithDifferentClassLoaders(MethodHelper* other)
@@ -332,8 +238,8 @@
     if (UNLIKELY(GetReturnType() != other->GetReturnType())) {
       return false;
     }
-    const DexFile::TypeList* types = GetParameterTypeList();
-    const DexFile::TypeList* other_types = other->GetParameterTypeList();
+    const DexFile::TypeList* types = method_->GetParameterTypeList();
+    const DexFile::TypeList* other_types = other->method_->GetParameterTypeList();
     if (types == nullptr) {
       return (other_types == nullptr) || (other_types->Size() == 0);
     } else if (UNLIKELY(other_types == nullptr)) {
@@ -354,84 +260,63 @@
     return true;
   }
 
-  const DexFile::CodeItem* GetCodeItem()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetDexFile().GetCodeItem(method_->GetCodeItemOffset());
-  }
-
-  bool IsResolvedTypeIdx(uint16_t type_idx) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDexCacheResolvedTypes()->Get(type_idx) != nullptr;
-  }
-
   mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::Class* type = method_->GetDexCacheResolvedTypes()->Get(type_idx);
+    mirror::ArtMethod* method = GetMethod();
+    mirror::Class* type = method->GetDexCacheResolvedTypes()->Get(type_idx);
     if (type == nullptr && resolve) {
-      type = GetClassLinker()->ResolveType(type_idx, method_);
+      type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
       CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
     }
     return type;
   }
 
-  const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dex_file = GetDexFile();
-    return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
-  }
-
   mirror::Class* GetDexCacheResolvedType(uint16_t type_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDexCacheResolvedTypes()->Get(type_idx);
-  }
-
-  const DexFile& GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return *GetDexCache()->GetDexFile();
-  }
-
-  mirror::DexCache* GetDexCache() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return method_->GetDeclaringClass()->GetDexCache();
+    return GetMethod()->GetDexCacheResolvedTypes()->Get(type_idx);
   }
 
   mirror::String* ResolveString(uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::String* s = method_->GetDexCacheStrings()->Get(string_idx);
+    mirror::ArtMethod* method = GetMethod();
+    mirror::String* s = method->GetDexCacheStrings()->Get(string_idx);
     if (UNLIKELY(s == nullptr)) {
       StackHandleScope<1> hs(Thread::Current());
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
-      s = GetClassLinker()->ResolveString(GetDexFile(), string_idx, dex_cache);
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+      s = Runtime::Current()->GetClassLinker()->ResolveString(*method->GetDexFile(), string_idx,
+                                                              dex_cache);
     }
     return s;
   }
 
   uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dexfile = GetDexFile();
-    if (&dexfile == &other_dexfile) {
-      return method_->GetDexMethodIndex();
+    mirror::ArtMethod* method = GetMethod();
+    const DexFile* dexfile = method->GetDexFile();
+    if (dexfile == &other_dexfile) {
+      return method->GetDexMethodIndex();
     }
-    const DexFile::MethodId& mid = dexfile.GetMethodId(method_->GetDexMethodIndex());
-    const char* mid_declaring_class_descriptor = dexfile.StringByTypeIdx(mid.class_idx_);
+    const DexFile::MethodId& mid = dexfile->GetMethodId(method->GetDexMethodIndex());
+    const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
     const DexFile::StringId* other_descriptor =
         other_dexfile.FindStringId(mid_declaring_class_descriptor);
     if (other_descriptor != nullptr) {
       const DexFile::TypeId* other_type_id =
           other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
       if (other_type_id != nullptr) {
-        const char* mid_name = dexfile.GetMethodName(mid);
+        const char* mid_name = dexfile->GetMethodName(mid);
         const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name);
         if (other_name != nullptr) {
           uint16_t other_return_type_idx;
           std::vector<uint16_t> other_param_type_idxs;
-          bool success = other_dexfile.CreateTypeList(dexfile.GetMethodSignature(mid).ToString(),
-                                                      &other_return_type_idx,
-                                                      &other_param_type_idxs);
+          bool success = other_dexfile.CreateTypeList(
+              dexfile->GetMethodSignature(mid).ToString(), &other_return_type_idx,
+              &other_param_type_idxs);
           if (success) {
             const DexFile::ProtoId* other_sig =
                 other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs);
             if (other_sig != nullptr) {
-              const  DexFile::MethodId* other_mid = other_dexfile.FindMethodId(*other_type_id,
-                                                                               *other_name,
-                                                                               *other_sig);
+              const  DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
+                  *other_type_id, *other_name, *other_sig);
               if (other_mid != nullptr) {
                 return other_dexfile.GetIndexForMethodId(*other_mid);
               }
@@ -448,15 +333,17 @@
   uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
                                             uint32_t name_and_signature_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile& dexfile = GetDexFile();
-    const DexFile::MethodId& mid = dexfile.GetMethodId(method_->GetDexMethodIndex());
+    mirror::ArtMethod* method = GetMethod();
+    const DexFile* dexfile = method->GetDexFile();
+    const uint32_t dex_method_idx = method->GetDexMethodIndex();
+    const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
     const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
-    DCHECK_STREQ(dexfile.GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
-    DCHECK_EQ(dexfile.GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
-    if (&dexfile == &other_dexfile) {
-      return method_->GetDexMethodIndex();
+    DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
+    DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
+    if (dexfile == &other_dexfile) {
+      return dex_method_idx;
     }
-    const char* mid_declaring_class_descriptor = dexfile.StringByTypeIdx(mid.class_idx_);
+    const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
     const DexFile::StringId* other_descriptor =
         other_dexfile.FindStringId(mid_declaring_class_descriptor);
     if (other_descriptor != nullptr) {
@@ -478,24 +365,10 @@
   // Set the method_ field, for proxy methods looking up the interface method via the resolved
   // methods table.
   void SetMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (method != nullptr) {
-      mirror::Class* klass = method->GetDeclaringClass();
-      if (UNLIKELY(klass->IsProxyClass())) {
-        mirror::ArtMethod* interface_method =
-            method->GetDexCacheResolvedMethods()->Get(method->GetDexMethodIndex());
-        DCHECK(interface_method != nullptr);
-        DCHECK(interface_method == GetClassLinker()->FindMethodForProxy(klass, method));
-        method = interface_method;
-      }
-    }
-    method_ = method;
+    method_.Assign(method);
   }
 
-  ClassLinker* GetClassLinker() ALWAYS_INLINE {
-    return Runtime::Current()->GetClassLinker();
-  }
-
-  mirror::ArtMethod* method_;
+  Handle<mirror::ArtMethod> method_;
   const char* shorty_;
   uint32_t shorty_len_;
 
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index bad79b3..00bb501 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -378,8 +378,7 @@
 
   bool is_filtered = false;
 
-  MethodHelper mh(method);
-  if (strcmp(mh.GetName(), "<clinit>") == 0) {
+  if (strcmp(method->GetName(), "<clinit>") == 0) {
     // always filter out class init
     is_filtered = true;
   }
@@ -460,8 +459,7 @@
         mirror::ArtMethod *method = meth_iter.first;
         std::string method_name = PrettyMethod(method);
 
-        MethodHelper mh(method);
-        const DexFile::CodeItem* codeitem = mh.GetCodeItem();
+        const DexFile::CodeItem* codeitem = method->GetCodeItem();
         uint32_t method_size = 0;
         if (codeitem != nullptr) {
           method_size = codeitem->insns_size_in_code_units_;
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index b9cec40..e3f9afc 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -71,11 +71,13 @@
       DCHECK(method->IsCalleeSaveMethod());
       return true;
     }
-    return HandleTryItems(method);
+    StackHandleScope<1> hs(self_);
+    return HandleTryItems(hs.NewHandle(method));
   }
 
  private:
-  bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool HandleTryItems(Handle<mirror::ArtMethod> method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t dex_pc = DexFile::kDexNoIndex;
     if (!method->IsNative()) {
       dex_pc = GetDexPc();
@@ -84,10 +86,11 @@
       bool clear_exception = false;
       StackHandleScope<1> hs(Thread::Current());
       Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass()));
-      uint32_t found_dex_pc = method->FindCatchBlock(to_find, dex_pc, &clear_exception);
+      uint32_t found_dex_pc = mirror::ArtMethod::FindCatchBlock(method, to_find, dex_pc,
+                                                                &clear_exception);
       exception_handler_->SetClearException(clear_exception);
       if (found_dex_pc != DexFile::kDexNoIndex) {
-        exception_handler_->SetHandlerMethod(method);
+        exception_handler_->SetHandlerMethod(method.Get());
         exception_handler_->SetHandlerDexPc(found_dex_pc);
         exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
         exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
@@ -175,8 +178,7 @@
 
  private:
   bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    MethodHelper mh(m);
-    const DexFile::CodeItem* code_item = mh.GetCodeItem();
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
     CHECK(code_item != nullptr);
     uint16_t num_regs = code_item->registers_size_;
     uint32_t dex_pc = GetDexPc();
@@ -184,10 +186,11 @@
     uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
     ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
     StackHandleScope<2> hs(self_);
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
-    Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
-    verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
-                                      &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
+    mirror::Class* declaring_class = m->GetDeclaringClass();
+    Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
+    verifier::MethodVerifier verifier(h_dex_cache->GetDexFile(), &h_dex_cache, &h_class_loader,
+                                      &m->GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                       m->GetAccessFlags(), false, true, true);
     verifier.Verify();
     std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index c08cc30..89cdb4d 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -222,7 +222,7 @@
                                     mirror::Object* receiver,
                                     mirror::ObjectArray<mirror::Object>* args, MethodHelper& mh)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::TypeList* classes = mh.GetParameterTypeList();
+    const DexFile::TypeList* classes = mh.GetMethod()->GetParameterTypeList();
     // Set receiver if non-null (method is not static)
     if (receiver != nullptr) {
       Append(receiver);
@@ -349,7 +349,7 @@
 
 static void CheckMethodArguments(mirror::ArtMethod* m, uint32_t* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  const DexFile::TypeList* params = MethodHelper(m).GetParameterTypeList();
+  const DexFile::TypeList* params = m->GetParameterTypeList();
   if (params == nullptr) {
     return;  // No arguments so nothing to check.
   }
@@ -359,24 +359,31 @@
   if (!m->IsStatic()) {
     offset = 1;
   }
+  // TODO: If args contain object references, it may cause problems
+  Thread* self = Thread::Current();
+  StackHandleScope<1> hs(self);
+  Handle<mirror::ArtMethod> h_m(hs.NewHandle(m));
+  MethodHelper mh(h_m);
   for (uint32_t i = 0; i < num_params; i++) {
     uint16_t type_idx = params->GetTypeItem(i).type_idx_;
-    mirror::Class* param_type = MethodHelper(m).GetClassFromTypeIdx(type_idx);
+    mirror::Class* param_type = mh.GetClassFromTypeIdx(type_idx);
     if (param_type == nullptr) {
-      Thread* self = Thread::Current();
       CHECK(self->IsExceptionPending());
       LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
-          << MethodHelper(m).GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
+          << h_m->GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
           << self->GetException(nullptr)->Dump();
       self->ClearException();
       ++error_count;
     } else if (!param_type->IsPrimitive()) {
       // TODO: check primitives are in range.
+      // TODO: There is a compaction bug here since GetClassFromTypeIdx can cause thread suspension,
+      // this is a hard to fix problem since the args can contain Object*, we need to save and
+      // restore them by using a visitor similar to the ones used in the trampoline entrypoints.
       mirror::Object* argument = reinterpret_cast<mirror::Object*>(args[i + offset]);
       if (argument != nullptr && !argument->InstanceOf(param_type)) {
         LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
                    << PrettyTypeOf(argument) << " as argument " << (i + 1)
-                   << " to " << PrettyMethod(m);
+                   << " to " << PrettyMethod(h_m.Get());
         ++error_count;
       }
     } else if (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble()) {
@@ -387,7 +394,7 @@
     // TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort
     // with an argument.
     JniAbortF(nullptr, "bad arguments passed to %s (see above for details)",
-              PrettyMethod(m).c_str());
+              PrettyMethod(h_m.Get()).c_str());
   }
 }
 
@@ -414,33 +421,36 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtMethod* method = soa.DecodeMethod(mid);
   mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
-  MethodHelper mh(method);
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
   return result;
 }
 
 JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver,
                          jmethodID mid, jvalue* args) {
   mirror::ArtMethod* method = soa.DecodeMethod(mid);
-  MethodHelper mh(method);
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromJValues(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
   return result;
 }
 
 JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
                                            mirror::Object* receiver, jmethodID mid, jvalue* args) {
   mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
-  MethodHelper mh(method);
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromJValues(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
   return result;
 }
 
@@ -448,11 +458,12 @@
                                            jobject obj, jmethodID mid, va_list args) {
   mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
   mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
-  MethodHelper mh(method);
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
   JValue result;
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  ArgArray arg_array(shorty, shorty_len);
   arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
+  InvokeWithArgArray(soa, method, &arg_array, &result, shorty);
   return result;
 }
 
@@ -493,8 +504,7 @@
   // Get our arrays of arguments and their types, and check they're the same size.
   mirror::ObjectArray<mirror::Object>* objects =
       soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
-  MethodHelper mh(m);
-  const DexFile::TypeList* classes = mh.GetParameterTypeList();
+  const DexFile::TypeList* classes = m->GetParameterTypeList();
   uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
   uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0;
   if (arg_count != classes_size) {
@@ -513,13 +523,17 @@
 
   // Invoke the method.
   JValue result;
-  ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
+  uint32_t shorty_len = 0;
+  const char* shorty = m->GetShorty(&shorty_len);
+  ArgArray arg_array(shorty, shorty_len);
+  StackHandleScope<1> hs(soa.Self());
+  MethodHelper mh(hs.NewHandle(m));
   if (!arg_array.BuildArgArrayFromObjectArray(soa, receiver, objects, mh)) {
     CHECK(soa.Self()->IsExceptionPending());
     return nullptr;
   }
 
-  InvokeWithArgArray(soa, m, &arg_array, &result, mh.GetShorty());
+  InvokeWithArgArray(soa, m, &arg_array, &result, shorty);
 
   // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
   if (soa.Self()->IsExceptionPending()) {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index ef09816..7e922c5 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -40,7 +40,7 @@
   } else if (m->IsNative()) {
     return GetVRegReference(0);
   } else {
-    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
     CHECK(code_item != NULL) << PrettyMethod(m);
     uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
     return GetVRegReference(reg);
@@ -125,7 +125,7 @@
       return cur_shadow_frame_->GetVRegReference(0);
     }
   } else {
-    const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+    const DexFile::CodeItem* code_item = m->GetCodeItem();
     if (code_item == NULL) {
       UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
           << PrettyMethod(m);
@@ -157,7 +157,7 @@
       uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask();
       return GetGPR(vmap_table.ComputeRegister(spill_mask, vmap_offset, kind));
     } else {
-      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+      const DexFile::CodeItem* code_item = m->GetCodeItem();
       DCHECK(code_item != NULL) << PrettyMethod(m);  // Can't be NULL or how would we compile its instructions?
       return *GetVRegAddr(cur_quick_frame_, code_item, frame_info.CoreSpillMask(),
                           frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg);
@@ -184,7 +184,7 @@
       const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kReferenceVReg);
       SetGPR(reg, new_value);
     } else {
-      const DexFile::CodeItem* code_item = MethodHelper(m).GetCodeItem();
+      const DexFile::CodeItem* code_item = m->GetCodeItem();
       DCHECK(code_item != NULL) << PrettyMethod(m);  // Can't be NULL or how would we compile its instructions?
       int offset = GetVRegOffset(code_item, frame_info.CoreSpillMask(), frame_info.FpSpillMask(),
                                  frame_info.FrameSizeInBytes(), vreg, kRuntimeISA);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3bfdc3f..22f0e80 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -892,8 +892,7 @@
       if (m->IsNative()) {
         os << "(Native method)";
       } else {
-        mh.ChangeMethod(m);
-        const char* source_file(mh.GetDeclaringClassSourceFile());
+        const char* source_file(m->GetDeclaringClassSourceFile());
         os << "(" << (source_file != nullptr ? source_file : "unavailable")
            << ":" << line_number << ")";
       }
@@ -933,7 +932,7 @@
   std::ostream& os;
   const Thread* thread;
   const bool can_allocate;
-  MethodHelper mh;
+  mirror::ArtMethod* method;
   mirror::ArtMethod* last_method;
   int last_line_number;
   int repetition_count;
@@ -1530,7 +1529,6 @@
           soa.Decode<mirror::ObjectArray<mirror::Object>*>(internal);
     // Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
     mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i));
-    MethodHelper mh(method);
     int32_t line_number;
     StackHandleScope<3> hs(soa.Self());
     auto class_name_object(hs.NewHandle<mirror::String>(nullptr));
@@ -1542,17 +1540,17 @@
     } else {
       mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
       uint32_t dex_pc = pc_trace->Get(i);
-      line_number = mh.GetLineNumFromDexPC(dex_pc);
+      line_number = method->GetLineNumFromDexPC(dex_pc);
       // Allocate element, potentially triggering GC
       // TODO: reuse class_name_object via Class::name_?
-      const char* descriptor = mh.GetDeclaringClassDescriptor();
+      const char* descriptor = method->GetDeclaringClassDescriptor();
       CHECK(descriptor != nullptr);
       std::string class_name(PrettyDescriptor(descriptor));
       class_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
       if (class_name_object.Get() == nullptr) {
         return nullptr;
       }
-      const char* source_file = mh.GetDeclaringClassSourceFile();
+      const char* source_file = method->GetDeclaringClassSourceFile();
       if (source_file != nullptr) {
         source_name_object.Assign(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
         if (source_name_object.Get() == nullptr) {
@@ -1560,7 +1558,7 @@
         }
       }
     }
-    const char* method_name = mh.GetName();
+    const char* method_name = method->GetName();
     CHECK(method_name != nullptr);
     Handle<mirror::String> method_name_object(
         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), method_name)));
@@ -2044,8 +2042,7 @@
     if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) {
       const uint8_t* native_gc_map = m->GetNativeGcMap();
       CHECK(native_gc_map != nullptr) << PrettyMethod(m);
-      mh_.ChangeMethod(m);
-      const DexFile::CodeItem* code_item = mh_.GetCodeItem();
+      const DexFile::CodeItem* code_item = m->GetCodeItem();
       DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be nullptr or how would we compile its instructions?
       NativePcOffsetToReferenceMap map(native_gc_map);
       size_t num_regs = std::min(map.RegWidth() * 8,
@@ -2100,9 +2097,6 @@
 
   // Visitor for when we visit a root.
   const RootVisitor& visitor_;
-
-  // A method helper we keep around to avoid dex file/cache re-computations.
-  MethodHelper mh_;
 };
 
 class RootCallbackVisitor {
diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc
index 06b6e8d..a1347a4 100644
--- a/runtime/throw_location.cc
+++ b/runtime/throw_location.cc
@@ -27,7 +27,7 @@
 std::string ThrowLocation::Dump() const {
   if (method_ != nullptr) {
     return StringPrintf("%s:%d", PrettyMethod(method_).c_str(),
-                        MethodHelper(method_).GetLineNumFromDexPC(dex_pc_));
+                        method_->GetLineNumFromDexPC(dex_pc_));
   } else {
     return "unknown throw location";
   }
diff --git a/runtime/trace.cc b/runtime/trace.cc
index d53b369..032a566 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -677,12 +677,10 @@
 }
 
 void Trace::DumpMethodList(std::ostream& os, const std::set<mirror::ArtMethod*>& visited_methods) {
-  MethodHelper mh;
   for (const auto& method : visited_methods) {
-    mh.ChangeMethod(method);
     os << StringPrintf("%p\t%s\t%s\t%s\t%s\n", method,
-        PrettyDescriptor(mh.GetDeclaringClassDescriptor()).c_str(), mh.GetName(),
-        mh.GetSignature().ToString().c_str(), mh.GetDeclaringClassSourceFile());
+        PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(), method->GetName(),
+        method->GetSignature().ToString().c_str(), method->GetDeclaringClassSourceFile());
   }
 }
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index ef2047b..7700658 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -365,15 +365,14 @@
   if (m == nullptr) {
     return "null";
   }
-  MethodHelper mh(m);
-  std::string result(PrettyDescriptor(mh.GetDeclaringClassDescriptor()));
+  std::string result(PrettyDescriptor(m->GetDeclaringClassDescriptor()));
   result += '.';
-  result += mh.GetName();
+  result += m->GetName();
   if (UNLIKELY(m->IsFastNative())) {
     result += "!";
   }
   if (with_signature) {
-    const Signature signature = mh.GetSignature();
+    const Signature signature = m->GetSignature();
     std::string sig_as_string(signature.ToString());
     if (signature == Signature::NoSignature()) {
       return result + sig_as_string;
@@ -642,15 +641,14 @@
 }
 
 std::string JniShortName(mirror::ArtMethod* m) {
-  MethodHelper mh(m);
-  std::string class_name(mh.GetDeclaringClassDescriptor());
+  std::string class_name(m->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(mh.GetName());
+  std::string method_name(m->GetName());
 
   std::string short_name;
   short_name += "Java_";
@@ -665,7 +663,7 @@
   long_name += JniShortName(m);
   long_name += "__";
 
-  std::string signature(MethodHelper(m).GetSignature().ToString());
+  std::string signature(m->GetSignature().ToString());
   signature.erase(0, 1);
   signature.erase(signature.begin() + signature.find(')'), signature.end());
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c7bb20c..e5dcbb0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -338,12 +338,11 @@
 
 void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
                                       std::vector<uint32_t>* monitor_enter_dex_pcs) {
-  MethodHelper mh(m);
   StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
-  MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
-                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
+  MethodVerifier verifier(m->GetDexFile(), &dex_cache, &class_loader, &m->GetClassDef(),
+                          m->GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
                           true, false);
   verifier.interesting_dex_pc_ = dex_pc;
   verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs;
@@ -363,12 +362,11 @@
 
 mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m,
                                                            uint32_t dex_pc) {
-  MethodHelper mh(m);
   StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
-  MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
-                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
+  MethodVerifier verifier(m->GetDexFile(), &dex_cache, &class_loader, &m->GetClassDef(),
+                          m->GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true, false);
   return verifier.FindAccessedFieldAtDexPc(dex_pc);
 }
@@ -394,12 +392,11 @@
 
 mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m,
                                                             uint32_t dex_pc) {
-  MethodHelper mh(m);
   StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
-  MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
-                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
+  MethodVerifier verifier(m->GetDexFile(), &dex_cache, &class_loader, &m->GetClassDef(),
+                          m->GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true, false);
   return verifier.FindInvokedMethodAtDexPc(dex_pc);
 }
@@ -2136,19 +2133,22 @@
     case Instruction::INVOKE_SUPER_RANGE: {
       bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
                        inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
-      bool is_super =  (inst->Opcode() == Instruction::INVOKE_SUPER ||
-                        inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+      bool is_super = (inst->Opcode() == Instruction::INVOKE_SUPER ||
+                       inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
       mirror::ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL,
                                                                    is_range, is_super);
       const RegType* return_type = nullptr;
       if (called_method != nullptr) {
-        MethodHelper mh(called_method);
+        Thread* self = Thread::Current();
+        StackHandleScope<1> hs(self);
+        Handle<mirror::ArtMethod> h_called_method(hs.NewHandle(called_method));
+        MethodHelper mh(h_called_method);
         mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
         if (return_type_class != nullptr) {
-          return_type = &reg_types_.FromClass(mh.GetReturnTypeDescriptor(), return_type_class,
+          return_type = &reg_types_.FromClass(h_called_method->GetReturnTypeDescriptor(),
+                                              return_type_class,
                                               return_type_class->CannotBeAssignedFromOtherTypes());
         } else {
-          Thread* self = Thread::Current();
           DCHECK(!can_load_classes_ || self->IsExceptionPending());
           self->ClearException();
         }
@@ -2183,7 +2183,7 @@
         return_type_descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
       } else {
         is_constructor = called_method->IsConstructor();
-        return_type_descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
+        return_type_descriptor = called_method->GetReturnTypeDescriptor();
       }
       if (is_constructor) {
         /*
@@ -2249,10 +2249,10 @@
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor = dex_file_->StringByTypeIdx(return_type_idx);
         } else {
-          descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
+          descriptor = called_method->GetReturnTypeDescriptor();
         }
-        const RegType& return_type =  reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
-                                                                false);
+        const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
+                                                               false);
         if (!return_type.IsLowHalf()) {
           work_line_->SetResultRegisterType(return_type);
         } else {
@@ -2307,7 +2307,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 = MethodHelper(abs_method).GetReturnTypeDescriptor();
+        descriptor = abs_method->GetReturnTypeDescriptor();
       }
       const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
                                                              false);
@@ -2574,7 +2574,7 @@
       bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
       mirror::ArtMethod* called_method = VerifyInvokeVirtualQuickArgs(inst, is_range);
       if (called_method != NULL) {
-        const char* descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
+        const char* descriptor = called_method->GetReturnTypeDescriptor();
         const RegType& return_type = reg_types_.FromDescriptor(class_loader_->Get(), descriptor,
                                                                false);
         if (!return_type.IsLowHalf()) {
@@ -2962,7 +2962,7 @@
     return NULL;
   }
   // Disallow any calls to class initializers.
-  if (MethodHelper(res_method).IsClassInitializer()) {
+  if (res_method->IsClassInitializer()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "rejecting call to class initializer "
                                       << PrettyMethod(res_method);
     return NULL;
@@ -3027,12 +3027,11 @@
     }
     mirror::Class* super_klass = super.GetClass();
     if (res_method->GetMethodIndex() >= super_klass->GetVTable()->GetLength()) {
-      MethodHelper mh(res_method);
       Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
                                    << PrettyMethod(dex_method_idx_, *dex_file_)
                                    << " to super " << super
-                                   << "." << mh.GetName()
-                                   << mh.GetSignature();
+                                   << "." << res_method->GetName()
+                                   << res_method->GetSignature();
       return NULL;
     }
   }
@@ -3081,8 +3080,7 @@
    * Process the target method's signature. This signature may or may not
    * have been verified, so we can't assume it's properly formed.
    */
-  MethodHelper mh(res_method);
-  const DexFile::TypeList* params = mh.GetParameterTypeList();
+  const DexFile::TypeList* params = res_method->GetParameterTypeList();
   size_t params_size = params == NULL ? 0 : params->Size();
   uint32_t arg[5];
   if (!is_range) {
@@ -3096,7 +3094,7 @@
       return NULL;
     }
     const char* descriptor =
-        mh.GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
+        res_method->GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
     if (descriptor == NULL) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
           << " missing signature component";
@@ -3204,8 +3202,7 @@
    * Process the target method's signature. This signature may or may not
    * have been verified, so we can't assume it's properly formed.
    */
-  MethodHelper mh(res_method);
-  const DexFile::TypeList* params = mh.GetParameterTypeList();
+  const DexFile::TypeList* params = res_method->GetParameterTypeList();
   size_t params_size = params == NULL ? 0 : params->Size();
   uint32_t arg[5];
   if (!is_range) {
@@ -3221,7 +3218,7 @@
       return NULL;
     }
     const char* descriptor =
-        mh.GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
+        res_method->GetTypeDescriptorFromTypeIdx(params->GetTypeItem(param_index).type_idx_);
     if (descriptor == NULL) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation of " << PrettyMethod(res_method)
                                         << " missing signature component";
@@ -3849,13 +3846,18 @@
 const RegType& MethodVerifier::GetMethodReturnType() {
   if (return_type_ == nullptr) {
     if (mirror_method_ != NULL) {
-      MethodHelper mh(mirror_method_);
-      mirror::Class* return_type_class = mh.GetReturnType(can_load_classes_);
+      Thread* self = Thread::Current();
+      StackHandleScope<1> hs(self);
+      mirror::Class* return_type_class;
+      {
+        HandleWrapper<mirror::ArtMethod> h_mirror_method(hs.NewHandleWrapper(&mirror_method_));
+        return_type_class = MethodHelper(h_mirror_method).GetReturnType(can_load_classes_);
+      }
       if (return_type_class != nullptr) {
-        return_type_ = &reg_types_.FromClass(mh.GetReturnTypeDescriptor(), return_type_class,
+        return_type_ = &reg_types_.FromClass(mirror_method_->GetReturnTypeDescriptor(),
+                                             return_type_class,
                                              return_type_class->CannotBeAssignedFromOtherTypes());
       } else {
-        Thread* self = Thread::Current();
         DCHECK(!can_load_classes_ || self->IsExceptionPending());
         self->ClearException();
       }