Work in the direction of hard float quick ABIs.

Pass a shorty to ArtMethod::Invoke so that register setup can use it.
Document x86-64 ABI.
Add extra debug output for one JNI native method registration fails, namely a
dump of the Class and its dex file's location.
Add hack to get testing of OatMethod's without GC maps working in 64bit.

Change-Id: Ic06b68e18eac33637df2caf5e7e775ff95ae70f3
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index c49f627..8c385a1 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -22,54 +22,53 @@
 namespace art {
 
 /*
- * Runtime register conventions. We consider both x86, x86-64 and x32 (32bit mode x86-64), although
- * we currently only target x86. The ABI has different conventions and we hope to have a single
- * convention to simplify code generation. Changing something that is callee save and making it
- * caller save places a burden on up-calls to save/restore the callee save register, however, there
- * are few registers that are callee save in the ABI. Changing something that is caller save and
- * making it callee save places a burden on down-calls to save/restore the callee save register.
- * For these reasons we aim to match native conventions for caller and callee save. The first 4
- * registers can be used for byte operations, for this reason they are preferred for temporary
- * scratch registers.
+ * Runtime register conventions. We consider both x86, x86-64 and x32 (32bit mode x86-64). The ABI
+ * has different conventions and we capture those here. Changing something that is callee save and
+ * making it caller save places a burden on up-calls to save/restore the callee save register,
+ * however, there are few registers that are callee save in the ABI. Changing something that is
+ * caller save and making it callee save places a burden on down-calls to save/restore the callee
+ * save register. For these reasons we aim to match native conventions for caller and callee save.
+ * On x86 only the first 4 registers can be used for byte operations, for this reason they are
+ * preferred for temporary scratch registers.
  *
  * General Purpose Register:
- *  Native: x86         | x86-64 / x32      | ART
- *  r0/eax: caller save | caller save       | caller, Method*, scratch, return value
- *  r1/ecx: caller save | caller save, arg4 | caller, arg1, scratch
- *  r2/edx: caller save | caller save, arg3 | caller, arg2, scratch, high half of long return
- *  r3/ebx: callEE save | callEE save       | callER, arg3, scratch
+ *  Native: x86    | x86-64 / x32 | ART x86                                         | ART x86-64
+ *  r0/eax: caller | caller       | caller, Method*, scratch, return value          | caller, scratch, return value
+ *  r1/ecx: caller | caller, arg4 | caller, arg1, scratch                           | caller, arg3, scratch
+ *  r2/edx: caller | caller, arg3 | caller, arg2, scratch, high half of long return | caller, arg2, scratch
+ *  r3/ebx: callEE | callEE       | callER, arg3, scratch                           | callee, promotable
  *  r4/esp: stack pointer
- *  r5/ebp: callee save | callee save       | callee, available for dalvik register promotion
- *  r6/esi: callEE save | callER save, arg2 | callee, available for dalvik register promotion
- *  r7/edi: callEE save | callER save, arg1 | callee, available for dalvik register promotion
+ *  r5/ebp: callee | callee       | callee, promotable                              | callee, promotable
+ *  r6/esi: callEE | callER, arg2 | callee, promotable                              | caller, arg1, scratch
+ *  r7/edi: callEE | callER, arg1 | callee, promotable                              | caller, Method*, scratch
  *  ---  x86-64/x32 registers
  *  Native: x86-64 / x32      | ART
- *  r8:     caller save, arg5 | caller, scratch
- *  r9:     caller save, arg6 | caller, scratch
+ *  r8:     caller save, arg5 | caller, arg4, scratch
+ *  r9:     caller save, arg6 | caller, arg5, scratch
  *  r10:    caller save       | caller, scratch
  *  r11:    caller save       | caller, scratch
- *  r12:    callee save       | callee, available for dalvik register promotion
- *  r13:    callee save       | callee, available for dalvik register promotion
- *  r14:    callee save       | callee, available for dalvik register promotion
- *  r15:    callee save       | callee, available for dalvik register promotion
+ *  r12:    callee save       | callee, available for register promotion (promotable)
+ *  r13:    callee save       | callee, available for register promotion (promotable)
+ *  r14:    callee save       | callee, available for register promotion (promotable)
+ *  r15:    callee save       | callee, available for register promotion (promotable)
  *
  * There is no rSELF, instead on x86 fs: has a base address of Thread::Current, whereas on
  * x86-64/x32 gs: holds it.
  *
  * For floating point we don't support CPUs without SSE2 support (ie newer than PIII):
- *  Native: x86       | x86-64 / x32     | ART
- *  XMM0: caller save |caller save, arg1 | caller, float/double return value (except for native x86 code)
- *  XMM1: caller save |caller save, arg2 | caller, scratch
- *  XMM2: caller save |caller save, arg3 | caller, scratch
- *  XMM3: caller save |caller save, arg4 | caller, scratch
- *  XMM4: caller save |caller save, arg5 | caller, scratch
- *  XMM5: caller save |caller save, arg6 | caller, scratch
- *  XMM6: caller save |caller save, arg7 | caller, scratch
- *  XMM7: caller save |caller save, arg8 | caller, scratch
+ *  Native: x86  | x86-64 / x32 | ART x86                    | ART x86-64
+ *  XMM0: caller | caller, arg1 | caller, float return value | caller, arg1, float return value
+ *  XMM1: caller | caller, arg2 | caller, scratch            | caller, arg2, scratch
+ *  XMM2: caller | caller, arg3 | caller, scratch            | caller, arg3, scratch
+ *  XMM3: caller | caller, arg4 | caller, scratch            | caller, arg4, scratch
+ *  XMM4: caller | caller, arg5 | caller, scratch            | caller, arg5, scratch
+ *  XMM5: caller | caller, arg6 | caller, scratch            | caller, arg6, scratch
+ *  XMM6: caller | caller, arg7 | caller, scratch            | caller, arg7, scratch
+ *  XMM7: caller | caller, arg8 | caller, scratch            | caller, arg8, scratch
  *  ---  x86-64/x32 registers
- *  XMM8 .. 15: caller save
+ *  XMM8 .. 15: caller save available as scratch registers for ART.
  *
- * X87 is a necessary evil outside of ART code:
+ * X87 is a necessary evil outside of ART code for x86:
  *  ST0:  x86 float/double native return value, caller save
  *  ST1 .. ST7: caller save
  *
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 0e5c60a..cf3f72e 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -274,7 +274,7 @@
      *   r2 = size of argument array in bytes
      *   r3 = (managed) thread pointer
      *   [sp] = JValue* result
-     *   [sp + 4] = result type char
+     *   [sp + 4] = shorty
      */
 ENTRY art_quick_invoke_stub
     push   {r0, r4, r5, r9, r11, lr}       @ spill regs
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index c60bca0..f9a200a 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -456,7 +456,7 @@
      *   a2 = size of argument array in bytes
      *   a3 = (managed) thread pointer
      *   [sp + 16] = JValue* result
-     *   [sp + 20] = result type char
+     *   [sp + 20] = shorty
      */
 ENTRY art_quick_invoke_stub
     GENERATE_GLOBAL_POINTER
@@ -502,7 +502,8 @@
     addiu $sp, $sp, 16
     .cfi_adjust_cfa_offset -16
     lw    $t0, 16($sp)          # get result pointer
-    lw    $t1, 20($sp)          # get result type char
+    lw    $t1, 20($sp)          # get shorty
+    lb    $t1, 0($t1)           # get result type char
     li    $t2, 68               # put char 'D' into t2
     beq   $t1, $t2, 1f          # branch if result type char == 'D'
     li    $t3, 70               # put char 'F' into t3
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 9c3eb30..c76c6b2 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -251,7 +251,7 @@
      *   [sp + 12] = size of argument array in bytes
      *   [sp + 16] = (managed) thread pointer
      *   [sp + 20] = JValue* result
-     *   [sp + 24] = result type char
+     *   [sp + 24] = shorty
      */
 DEFINE_FUNCTION art_quick_invoke_stub
     PUSH ebp                      // save ebp
@@ -281,17 +281,20 @@
     POP ebx                       // pop ebx
     POP ebp                       // pop ebp
     mov 20(%esp), %ecx            // get result pointer
-    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
-    je return_double_quick
-    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
-    je return_float_quick
-    mov %eax, (%ecx)              // store the result
+    mov %eax, (%ecx)              // store the result assuming its a long, int or Object*
     mov %edx, 4(%ecx)             // store the other half of the result
+    mov 24(%esp), %edx            // get the shorty
+    cmpb LITERAL(68), (%edx)      // test if result type char == 'D'
+    je return_double_quick
+    cmpb LITERAL(70), (%edx)      // test if result type char == 'F'
+    je return_float_quick
     ret
 return_double_quick:
-return_float_quick:
     movsd %xmm0, (%ecx)           // store the floating point result
     ret
+return_float_quick:
+    movss %xmm0, (%ecx)           // store the floating point result
+    ret
 END_FUNCTION art_quick_invoke_stub
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index e01a31b..44bc7a2 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -149,6 +149,14 @@
 
     /*
      * Quick invocation stub.
+     * On entry:
+     *   [sp] = return address
+     *   rdi = method pointer
+     *   rsi = argument array or NULL for no argument methods
+     *   rdx = size of argument array in bytes
+     *   rcx = (managed) thread pointer
+     *   r8 = JValue* result
+     *   r9 = char* shorty
      */
 DEFINE_FUNCTION art_quick_invoke_stub
     int3
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 978c99b..707082d 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3152,7 +3152,7 @@
     CHECK(can_init_statics);
     if (LIKELY(Runtime::Current()->IsStarted())) {
       JValue result;
-      clinit->Invoke(self, NULL, 0, &result, 'V');
+      clinit->Invoke(self, NULL, 0, &result, "V");
     } else {
       art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
     }
diff --git a/runtime/common_test.h b/runtime/common_test.h
index af7e8ae..f7859ea 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -268,7 +268,7 @@
     MakeExecutable(&code[0], code.size());
   }
 
-  // Create an OatMethod based on pointers (for unit tests)
+  // Create an OatMethod based on pointers (for unit tests).
   OatFile::OatMethod CreateOatMethod(const void* code,
                                      const size_t frame_size_in_bytes,
                                      const uint32_t core_spill_mask,
@@ -276,11 +276,23 @@
                                      const uint8_t* mapping_table,
                                      const uint8_t* vmap_table,
                                      const uint8_t* gc_map) {
-    const byte* base = nullptr;  // Base of data in oat file, ie 0.
-    uint32_t code_offset = PointerToLowMemUInt32(code);
-    uint32_t mapping_table_offset = PointerToLowMemUInt32(mapping_table);
-    uint32_t vmap_table_offset = PointerToLowMemUInt32(vmap_table);
-    uint32_t gc_map_offset = PointerToLowMemUInt32(gc_map);
+    const byte* base;
+    uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset;
+    if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) {
+      base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
+      base -= kPointerSize;  // Move backward so that code_offset != 0.
+      code_offset = kPointerSize;
+      mapping_table_offset = 0;
+      vmap_table_offset = 0;
+      gc_map_offset = 0;
+    } else {
+      // TODO: 64bit support.
+      base = nullptr;  // Base of data in oat file, ie 0.
+      code_offset = PointerToLowMemUInt32(code);
+      mapping_table_offset = PointerToLowMemUInt32(mapping_table);
+      vmap_table_offset = PointerToLowMemUInt32(vmap_table);
+      gc_map_offset = PointerToLowMemUInt32(gc_map);
+    }
     return OatFile::OatMethod(base,
                               code_offset,
                               frame_size_in_bytes,
@@ -470,6 +482,8 @@
       instruction_set = kX86;
 #elif defined(__x86_64__)
       instruction_set = kX86_64;
+      // TODO: x86_64 compilation support.
+      runtime_->SetCompilerFilter(Runtime::kInterpretOnly);
 #endif
 
       for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 8280c7c..53ac5cc 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3019,7 +3019,7 @@
   MethodHelper mh(m.get());
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values));
-  InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty());
 
   mirror::Throwable* exception = soa.Self()->GetException(NULL);
   soa.Self()->ClearException();
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 8a2ce51..2067a45 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -48,11 +48,11 @@
   if (kUsePortableCompiler) {
     ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
     arg_array.BuildArgArrayFromFrame(shadow_frame, arg_offset);
-    method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty()[0]);
+    method->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), result, mh.GetShorty());
   } else {
     method->Invoke(self, shadow_frame->GetVRegArgs(arg_offset),
                    (shadow_frame->NumberOfVRegs() - arg_offset) * sizeof(uint32_t),
-                   result, mh.GetShorty()[0]);
+                   result, mh.GetShorty());
   }
 }
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 62567d7..39521b3 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2316,10 +2316,10 @@
 void Heap::AddFinalizerReference(Thread* self, mirror::Object* object) {
   ScopedObjectAccess soa(self);
   JValue result;
-  ArgArray arg_array(NULL, 0);
+  ArgArray arg_array("VL", 2);
   arg_array.Append(object);
   soa.DecodeMethod(WellKnownClasses::java_lang_ref_FinalizerReference_add)->Invoke(self,
-      arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+      arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
 }
 
 void Heap::EnqueueClearedReferences() {
@@ -2330,10 +2330,10 @@
     if (LIKELY(Runtime::Current()->IsStarted())) {
       ScopedObjectAccess soa(self);
       JValue result;
-      ArgArray arg_array(NULL, 0);
+      ArgArray arg_array("VL", 2);
       arg_array.Append(cleared_references_.GetList());
       soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(),
-          arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+          arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
     }
     cleared_references_.Clear();
   }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index deea5f6..cb13f27 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -139,13 +139,13 @@
 }
 
 void InvokeWithArgArray(const ScopedObjectAccess& soa, ArtMethod* method,
-                        ArgArray* arg_array, JValue* result, char result_type)
+                        ArgArray* arg_array, JValue* result, const char* shorty)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   uint32_t* args = arg_array->GetArray();
   if (UNLIKELY(soa.Env()->check_jni)) {
     CheckMethodArguments(method, args);
   }
-  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, result_type);
+  method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty);
 }
 
 static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
@@ -157,7 +157,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -175,7 +175,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -188,7 +188,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -637,7 +637,7 @@
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, receiver, args);
-  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, method, &arg_array, &result, mh.GetShorty());
   return result;
 }
 
@@ -2437,8 +2437,10 @@
         m = c->FindVirtualMethod(name, sig);
       }
       if (m == NULL) {
+        c->DumpClass(LOG(ERROR), mirror::Class::kDumpClassFullDetail);
         LOG(return_errors ? ERROR : FATAL) << "Failed to register native method "
-            << PrettyDescriptor(c) << "." << name << sig;
+            << PrettyDescriptor(c) << "." << name << sig << " in "
+            << c->GetDexCache()->GetLocation()->ToModifiedUtf8();
         ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
         return JNI_ERR;
       } else if (!m->IsNative()) {
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index cd3c5cb..6eb1aad 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -57,7 +57,7 @@
 JValue InvokeWithJValues(const ScopedObjectAccess&, jobject obj, jmethodID mid, jvalue* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
-                        ArgArray *arg_array, JValue* result, char result_type)
+                        ArgArray *arg_array, JValue* result, const char* shorty)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause);
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fed734e..4c58c84 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -134,14 +134,14 @@
       arg_array.Append(receiver);
     }
 
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
   }
 
   void InvokeIdentityByteMethod(bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::ArtMethod* method;
     mirror::Object* receiver;
-    JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(I)I");
+    JniInternalTestMakeExecutable(&method, &receiver, is_static, "identity", "(B)B");
 
     ArgArray arg_array(NULL, 0);
     uint32_t* args = arg_array.GetArray();
@@ -154,22 +154,22 @@
 
     arg_array.Append(0U);
     result.SetB(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(0, result.GetB());
 
     args[0] = -1;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(-1, result.GetB());
 
     args[0] = SCHAR_MAX;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(SCHAR_MAX, result.GetB());
 
     args[0] = (SCHAR_MIN << 24) >> 24;
     result.SetB(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'B');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "BB");
     EXPECT_EQ(SCHAR_MIN, result.GetB());
   }
 
@@ -190,22 +190,22 @@
 
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = -1;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(-1, result.GetI());
 
     args[0] = INT_MAX;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(INT_MAX, result.GetI());
 
     args[0] = INT_MIN;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "II");
     EXPECT_EQ(INT_MIN, result.GetI());
   }
 
@@ -228,28 +228,28 @@
     value.SetD(0.0);
     arg_array.AppendWide(value.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(-1.0);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(-1.0, result.GetD());
 
     value.SetD(DBL_MAX);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(DBL_MAX, result.GetD());
 
     value.SetD(DBL_MIN);
     args[0] = value.GetJ();
     args[1] = value.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "DD");
     EXPECT_EQ(DBL_MIN, result.GetD());
   }
 
@@ -271,31 +271,31 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
     args[1] = 2;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(3, result.GetI());
 
     args[0] = -2;
     args[1] = 5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(3, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MIN;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(-1, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "III");
     EXPECT_EQ(-2, result.GetI());
   }
 
@@ -318,35 +318,40 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
     args[1] = 2;
     args[2] = 3;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(6, result.GetI());
 
     args[0] = -1;
     args[1] = 2;
     args[2] = -3;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(-2, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MIN;
     args[2] = INT_MAX;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(2147483646, result.GetI());
 
     args[0] = INT_MAX;
     args[1] = INT_MAX;
     args[2] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIII");
     EXPECT_EQ(2147483645, result.GetI());
   }
 
@@ -370,7 +375,8 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
@@ -378,7 +384,8 @@
     args[2] = 3;
     args[3] = 4;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(10, result.GetI());
 
     args[0] = -1;
@@ -386,7 +393,8 @@
     args[2] = -3;
     args[3] = 4;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(2, result.GetI());
 
     args[0] = INT_MAX;
@@ -394,7 +402,8 @@
     args[2] = INT_MAX;
     args[3] = INT_MIN;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(-2, result.GetI());
 
     args[0] = INT_MAX;
@@ -402,7 +411,8 @@
     args[2] = INT_MAX;
     args[3] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIII");
     EXPECT_EQ(-4, result.GetI());
   }
 
@@ -427,7 +437,8 @@
     arg_array.Append(0U);
     arg_array.Append(0U);
     result.SetI(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(0, result.GetI());
 
     args[0] = 1;
@@ -436,7 +447,8 @@
     args[3] = 4;
     args[4] = 5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(15, result.GetI());
 
     args[0] = -1;
@@ -445,7 +457,8 @@
     args[3] = 4;
     args[4] = -5;
     result.SetI(0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(-3, result.GetI());
 
     args[0] = INT_MAX;
@@ -454,7 +467,8 @@
     args[3] = INT_MIN;
     args[4] = INT_MAX;
     result.SetI(1234);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(2147483645, result.GetI());
 
     args[0] = INT_MAX;
@@ -463,7 +477,8 @@
     args[3] = INT_MAX;
     args[4] = INT_MAX;
     result.SetI(INT_MIN);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'I');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "IIIIII");
     EXPECT_EQ(2147483643, result.GetI());
   }
 
@@ -489,7 +504,8 @@
     arg_array.AppendWide(value.GetJ());
     arg_array.AppendWide(value2.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -499,7 +515,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(3.0, result.GetD());
 
     value.SetD(1.0);
@@ -509,7 +526,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(-1.0, result.GetD());
 
     value.SetD(DBL_MAX);
@@ -519,7 +537,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(1.7976931348623157e308, result.GetD());
 
     value.SetD(DBL_MAX);
@@ -529,7 +548,8 @@
     args[2] = value2.GetJ();
     args[3] = value2.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDD");
     EXPECT_EQ(INFINITY, result.GetD());
   }
 
@@ -558,7 +578,8 @@
     arg_array.AppendWide(value2.GetJ());
     arg_array.AppendWide(value3.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -571,7 +592,8 @@
     args[4] = value3.GetJ();
     args[5] = value3.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(6.0, result.GetD());
 
     value.SetD(1.0);
@@ -584,7 +606,8 @@
     args[4] = value3.GetJ();
     args[5] = value3.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDD");
     EXPECT_EQ(2.0, result.GetD());
   }
 
@@ -616,7 +639,8 @@
     arg_array.AppendWide(value3.GetJ());
     arg_array.AppendWide(value4.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -632,7 +656,8 @@
     args[6] = value4.GetJ();
     args[7] = value4.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(10.0, result.GetD());
 
     value.SetD(1.0);
@@ -648,7 +673,8 @@
     args[6] = value4.GetJ();
     args[7] = value4.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDD");
     EXPECT_EQ(-2.0, result.GetD());
   }
 
@@ -683,7 +709,8 @@
     arg_array.AppendWide(value4.GetJ());
     arg_array.AppendWide(value5.GetJ());
     result.SetD(-1.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(0.0, result.GetD());
 
     value.SetD(1.0);
@@ -702,7 +729,8 @@
     args[8] = value5.GetJ();
     args[9] = value5.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(15.0, result.GetD());
 
     value.SetD(1.0);
@@ -721,7 +749,8 @@
     args[8] = value5.GetJ();
     args[9] = value5.GetJ() >> 32;
     result.SetD(0.0);
-    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'D');
+    method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result,
+                   "DDDDDD");
     EXPECT_EQ(3.0, result.GetD());
   }
 
@@ -1764,7 +1793,7 @@
   CHECK(started);
   Thread::Current()->TransitionFromSuspendedToRunnable();
 
-  method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+  method->Invoke(Thread::Current(), arg_array.GetArray(), arg_array.GetNumBytes(), &result, "VL");
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 575ea03..8fba66a 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -35,7 +35,8 @@
 namespace mirror {
 
 extern "C" void art_portable_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
-extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
+extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
+                                      const char*);
 
 // TODO: get global references for these
 Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
@@ -245,10 +246,11 @@
 }
 
 void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
-                       char result_type) {
+                       const char* shorty) {
   if (kIsDebugBuild) {
     self->AssertThreadSuspensionIsAllowable();
     CHECK_EQ(kRunnable, self->GetState());
+    CHECK_STREQ(MethodHelper(this).GetShorty(), shorty);
   }
 
   // Push a transition back into managed code onto the linked list in thread.
@@ -274,9 +276,9 @@
                                                   : GetEntryPointFromPortableCompiledCode());
       }
       if (!IsPortableCompiled()) {
-        (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
+        (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
       } else {
-        (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
+        (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
       }
       if (UNLIKELY(reinterpret_cast<intptr_t>(self->GetException(NULL)) == -1)) {
         // Unusual case where we were running LLVM generated code and an
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index bfa7cbe..bf0d416 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -207,8 +207,8 @@
   // 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, char result_type)
-      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_);
 
   EntryPointFromInterpreter* GetEntryPointFromInterpreter() {
     return GetFieldPtr<EntryPointFromInterpreter*>(
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index ac8f5ef..0bfa70f 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -220,36 +220,46 @@
   }
 
   jmethodID m = NULL;
+  const char* shorty;
   switch (src_class) {
   case Primitive::kPrimBoolean:
     m = WellKnownClasses::java_lang_Boolean_valueOf;
+    shorty = "LZ";
     break;
   case Primitive::kPrimByte:
     m = WellKnownClasses::java_lang_Byte_valueOf;
+    shorty = "LB";
     break;
   case Primitive::kPrimChar:
     m = WellKnownClasses::java_lang_Character_valueOf;
+    shorty = "LC";
     break;
   case Primitive::kPrimDouble:
     m = WellKnownClasses::java_lang_Double_valueOf;
+    shorty = "LD";
     break;
   case Primitive::kPrimFloat:
     m = WellKnownClasses::java_lang_Float_valueOf;
+    shorty = "LF";
     break;
   case Primitive::kPrimInt:
     m = WellKnownClasses::java_lang_Integer_valueOf;
+    shorty = "LI";
     break;
   case Primitive::kPrimLong:
     m = WellKnownClasses::java_lang_Long_valueOf;
+    shorty = "LJ";
     break;
   case Primitive::kPrimShort:
     m = WellKnownClasses::java_lang_Short_valueOf;
+    shorty = "LS";
     break;
   case Primitive::kPrimVoid:
     // There's no such thing as a void field, and void methods invoked via reflection return null.
-    return NULL;
+    return nullptr;
   default:
     LOG(FATAL) << static_cast<int>(src_class);
+    shorty = nullptr;
   }
 
   ScopedObjectAccessUnchecked soa(Thread::Current());
@@ -257,7 +267,7 @@
     CHECK_EQ(soa.Self()->GetState(), kRunnable);
   }
 
-  ArgArray arg_array(NULL, 0);
+  ArgArray arg_array(nullptr, 0);
   JValue result;
   if (src_class == Primitive::kPrimDouble || src_class == Primitive::kPrimLong) {
     arg_array.AppendWide(value.GetJ());
@@ -266,7 +276,7 @@
   }
 
   soa.DecodeMethod(m)->Invoke(soa.Self(), arg_array.GetArray(), arg_array.GetNumBytes(),
-                              &result, 'L');
+                              &result, shorty);
   return result.GetL();
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 09d05d1..4f3437f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -807,7 +807,7 @@
 
   JValue result;
   ArgArray arg_array(nullptr, 0);
-  InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, 'L');
+  InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, "L");
   SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
                                             down_cast<mirror::ClassLoader*>(result.GetL()));
   CHECK(class_loader.get() != nullptr);
@@ -1473,12 +1473,11 @@
     method->SetFpSpillMask(0);
   } else if (instruction_set == kX86_64) {
     uint32_t ref_spills =
-        (1 << art::x86_64::RBP) | (1 << art::x86_64::RSI) | (1 << art::x86_64::RDI) |
-        (1 << art::x86_64::R8)  | (1 << art::x86_64::R9)  | (1 << art::x86_64::R10) |
-        (1 << art::x86_64::R11) | (1 << art::x86_64::R12) | (1 << art::x86_64::R13) |
-        (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
+        (1 << art::x86_64::RBX) | (1 << art::x86_64::RBP) | (1 << art::x86_64::R12) |
+        (1 << art::x86_64::R13) | (1 << art::x86_64::R14) | (1 << art::x86_64::R15);
     uint32_t arg_spills =
-        (1 << art::x86_64::RCX) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RBX);
+        (1 << art::x86_64::RSI) | (1 << art::x86_64::RDX) | (1 << art::x86_64::RCX) |
+        (1 << art::x86_64::R8) | (1 << art::x86_64::R9);
     uint32_t core_spills = ref_spills | (type == kRefsAndArgs ? arg_spills : 0) |
                          (1 << art::x86::kNumberOfCpuRegisters);  // fake return address callee save
     size_t frame_size = RoundUp((__builtin_popcount(core_spills) /* gprs */ +
diff --git a/runtime/thread.cc b/runtime/thread.cc
index c649765..cb1a37e 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -179,7 +179,7 @@
     JValue result;
     ArgArray arg_array(nullptr, 0);
     arg_array.Append(receiver);
-    m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
+    m->Invoke(self, arg_array.GetArray(), arg_array.GetNumBytes(), &result, "V");
   }
   // Detach and delete self.
   Runtime::Current()->GetThreadList()->Unregister(self);
@@ -1530,6 +1530,7 @@
 
   // Choose an appropriate constructor and set up the arguments.
   const char* signature;
+  const char* shorty;
   SirtRef<mirror::String> msg_string(this, nullptr);
   if (msg != nullptr) {
     // Ensure we remember this and the method over the String allocation.
@@ -1539,14 +1540,18 @@
       return;
     }
     if (cause.get() == nullptr) {
+      shorty = "VL";
       signature = "(Ljava/lang/String;)V";
     } else {
+      shorty = "VLL";
       signature = "(Ljava/lang/String;Ljava/lang/Throwable;)V";
     }
   } else {
     if (cause.get() == nullptr) {
+      shorty = "V";
       signature = "()V";
     } else {
+      shorty = "VL";
       signature = "(Ljava/lang/Throwable;)V";
     }
   }
@@ -1570,7 +1575,7 @@
                                          throw_location.GetDexPc());
     SetException(gc_safe_throw_location, exception.get());
   } else {
-    ArgArray args("VLL", 3);
+    ArgArray args(shorty, strlen(shorty));
     args.Append(exception.get());
     if (msg != nullptr) {
       args.Append(msg_string.get());
@@ -1579,7 +1584,7 @@
       args.Append(cause.get());
     }
     JValue result;
-    exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, 'V');
+    exception_init_method->Invoke(this, args.GetArray(), args.GetNumBytes(), &result, shorty);
     if (LIKELY(!IsExceptionPending())) {
       ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
                                            throw_location.GetDexPc());