Rewrite the invoke stubs to use JValue[]s.

The tests were only testing the static stubs, so extend the tests to include
non-static stubs too.

Also add just enough of an ARM disassembler to disassemble the invoke stubs.

Change-Id: If71dfb66b8b8188f9d871914f0eaf1013c9993b9
diff --git a/build/Android.common.mk b/build/Android.common.mk
index df4c5a9..20a73b5 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -280,6 +280,7 @@
 	MyClass \
 	MyClassNatives \
 	Nested \
+	NonStaticLeafMethods \
 	ProtoCompare \
 	ProtoCompare2 \
 	StaticLeafMethods \
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index b2ddc2c..bbdc37e 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -42,7 +42,7 @@
   }
 }
 
-static const char* ConditionCodeNames[] = {
+static const char* kConditionCodeNames[] = {
     "EQ",  // 0000 - equal
     "NE",  // 0001 - not-equal
     "CS",  // 0010 - carry-set, greater than, equal or unordered
@@ -57,12 +57,12 @@
     "LT",  // 1011 - signed less than
     "GT",  // 1100 - signed greater than
     "LE",  // 1101 - signed less than or equal
-    "AL",  // 1110 - always
+    "",    // 1110 - always
 };
 
 void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) {
   if (cond < 15) {
-    os << ConditionCodeNames[cond];
+    os << kConditionCodeNames[cond];
   } else {
     os << "Unexpected condition: " << cond;
   }
@@ -73,30 +73,10 @@
     case 13: os << "SP"; break;
     case 14: os << "LR"; break;
     case 15: os << "PC"; break;
-    default: os << "r" << reg; break;
+    default: os << "R" << reg; break;
   }
 }
 
-void DisassemblerArm::DumpRegList(std::ostream& os, uint32_t reg_list) {
-  if (reg_list == 0) {
-    os << "<no register list?>";
-    return;
-  }
-  bool first = true;
-  for (size_t i = 0; i < 16; i++) {
-    if ((reg_list & (1 << i)) != 0) {
-      if (first) {
-        os << "{";
-        first = false;
-      } else {
-        os << ", ";
-      }
-      DumpReg(os, i);
-    }
-  }
-  os << "}";
-}
-
 void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
   os << imm32 << " (" << reinterpret_cast<const void*>(instr_ptr + imm32) << ")";
 }
@@ -109,9 +89,155 @@
   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
 }
 
+static const char* kDataProcessingOperations[] = {
+  "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC",
+  "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN",
+};
+
+struct ArmRegister {
+  ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); }
+  uint32_t r;
+};
+std::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
+  if (r.r == 13) {
+    os << "SP";
+  } else if (r.r == 14) {
+    os << "LR";
+  } else if (r.r == 15) {
+    os << "PC";
+  } else {
+    os << "R" << r.r;
+  }
+  return os;
+}
+
+struct Rd : ArmRegister {
+  Rd(uint32_t instruction) : ArmRegister((instruction >> 12) & 0xf) {}
+};
+typedef Rd Rt;
+struct Rn : ArmRegister {
+  Rn(uint32_t instruction) : ArmRegister((instruction >> 16) & 0xf) {}
+};
+
+struct Rm {
+  Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {}
+  uint32_t shift;
+  ArmRegister rm;
+};
+std::ostream& operator<<(std::ostream& os, const Rm& r) {
+  os << r.rm;
+  if (r.shift != 0) {
+    os << "-shift-" << r.shift; // TODO
+  }
+  return os;
+}
+
+struct Imm12 {
+  Imm12(uint32_t instruction) : rotate((instruction >> 8) & 0xf), imm(instruction & 0xff) {}
+  uint32_t rotate;
+  uint32_t imm;
+};
+std::ostream& operator<<(std::ostream& os, const Imm12& rhs) {
+  uint32_t imm = (rhs.imm >> (2 * rhs.rotate)) | (rhs.imm << (32 - (2 * rhs.rotate)));
+  os << "#" << imm;
+  return os;
+}
+
+struct RegisterList {
+  RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {}
+  uint32_t register_list;
+};
+std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) {
+  if (rhs.register_list == 0) {
+    os << "<no register list?>";
+    return os;
+  }
+  bool first = true;
+  for (size_t i = 0; i < 16; i++) {
+    if ((rhs.register_list & (1 << i)) != 0) {
+      if (first) {
+        os << "{";
+        first = false;
+      } else {
+        os << ", ";
+      }
+      os << ArmRegister(i);
+    }
+  }
+  os << "}";
+  return os;
+}
 
 void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
-  os << StringPrintf("\t\t\t%p: %08x\n", instr_ptr, ReadU32(instr_ptr));
+  uint32_t instruction = ReadU32(instr_ptr);
+  uint32_t cond = (instruction >> 28) & 0xf;
+  uint32_t op1 = (instruction >> 25) & 0x7;
+  os << StringPrintf("\t\t\t%p: %08x: ", instr_ptr, instruction);
+  switch (op1) {
+    case 0:
+    case 1: // Data processing instructions.
+      {
+        if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register)
+          os << (((instruction >> 5) & 1) ? "BLX" : "BX") << " " << ArmRegister(instruction & 0xf);
+          break;
+        }
+        bool i = (instruction & (1 << 25)) != 0;
+        bool s = (instruction & (1 << 20)) != 0;
+        os << kDataProcessingOperations[(instruction >> 21) & 0xf]
+           << kConditionCodeNames[cond]
+           << (s ? "S" : "")
+           << " "
+           << Rd(instruction) << ", ";
+        if (i) {
+          os << Rn(instruction) << ", " << Imm12(instruction);
+        } else {
+          os << Rm(instruction);
+        }
+      }
+      break;
+    case 2: // Load/store word and unsigned byte.
+      {
+        bool p = (instruction & (1 << 24)) != 0;
+        bool b = (instruction & (1 << 22)) != 0;
+        bool w = (instruction & (1 << 21)) != 0;
+        bool l = (instruction & (1 << 20)) != 0;
+        os << (l ? "LDR" : "STR") << (b ? "B" : "") << kConditionCodeNames[cond] << " ";
+        os << Rt(instruction) << ", ";
+        if (Rn(instruction).r == 0xf) {
+          UNIMPLEMENTED(FATAL) << "literals";
+        } else {
+          bool wback = !p || w;
+          if (p && !wback) {
+            os << "[" << Rn(instruction) << ", " << Imm12(instruction) << "]";
+          } else if (p && wback) {
+            os << "[" << Rn(instruction) << ", " << Imm12(instruction) << "]!";
+          } else if (!p && wback) {
+            os << "[" << Rn(instruction) << "], " << Imm12(instruction);
+          } else {
+            LOG(FATAL) << p << " " << w;
+          }
+        }
+      }
+      break;
+    case 4: // Load/store multiple.
+      {
+        bool p = (instruction & (1 << 24)) != 0;
+        bool u = (instruction & (1 << 23)) != 0;
+        bool w = (instruction & (1 << 21)) != 0;
+        bool l = (instruction & (1 << 20)) != 0;
+        os << StringPrintf("%s%c%c%s ",
+                           l ? "LDM" : "STM",
+                           u ? 'I' : 'D',
+                           p ? 'B' : 'A',
+                           kConditionCodeNames[cond]);
+        os << Rn(instruction) << (w ? "!" : "") << ", " << RegisterList(instruction);
+      }
+      break;
+    default:
+      os << "???";
+      break;
+    }
+    os << '\n';
 }
 
 size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) {
@@ -124,11 +250,14 @@
   // |---|---|-------|----|----------------|
   // |111|op1| op2   |    |                |
   uint32_t op1 = (instr >> 27) & 3;
+  if (op1 == 0) {
+    return DumpThumb16(os, instr_ptr);
+  }
+
   uint32_t op2 = (instr >> 20) & 0x7F;
-  os << StringPrintf("\t\t\t%p: ", instr_ptr);
+  os << StringPrintf("\t\t\t%p: %08x: ", instr_ptr, instr);
   switch (op1) {
     case 0:
-      return DumpThumb16(os, instr_ptr);
       break;
     case 1:
       switch (op2) {
@@ -150,7 +279,6 @@
           uint32_t W = (instr >> 21) & 1;
           uint32_t L = (instr >> 20) & 1;
           uint32_t Rn = (instr >> 16) & 0xF;
-          uint32_t reg_list = instr & 0xFFFF;
           if (op == 1 || op == 2) {
             if (op == 1) {
               if (L == 0) {
@@ -197,8 +325,7 @@
                 }
               }
             }
-            DumpRegList(os, reg_list);
-            os << "  // ";
+            os << RegisterList(instr);
           }
           break;
         }
@@ -247,7 +374,7 @@
         DumpReg(os, Rd);
         os << ", ";
         DumpReg(os, Rn);
-        os << ", ThumbExpand(" << imm32 << ")  // ";
+        os << ", ThumbExpand(" << imm32 << ")";
       } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) {
         // Data-processing (plain binary immediate)
         // |111|11|10|00000|0000|1|111110000000000|
@@ -269,7 +396,7 @@
             uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8;
             os << "MOVW ";
             DumpReg(os, Rd);
-            os << ", #" << imm16 << "  // ";
+            os << ", #" << imm16;
             break;
           }
           case 0x0A: {
@@ -283,7 +410,7 @@
             DumpReg(os, Rd);
             os << ", ";
             DumpReg(os, Rn);
-            os << ", #" << imm12 << "  // ";
+            os << ", #" << imm12;
             break;
           }
           default:
@@ -324,7 +451,6 @@
               DumpCond(os, cond);
               os << ".W ";
               DumpBranchTarget(os, instr_ptr + 4, imm32);
-              os << "  // ";
             }
             break;
           case 2:
@@ -390,7 +516,6 @@
                 if (Rn == 13 && P == 1 && U == 0 && W == 1) {
                   os << "PUSH ";
                   DumpReg(os, Rt);
-                  os << "  // ";
                 } else if (Rn == 15 || (P == 0 && W == 0)) {
                   os << "UNDEFINED ";
                 } else {
@@ -410,7 +535,6 @@
                       os << "!";
                     }
                   }
-                  os << "  // ";
                 }
               } else if (op3 == 6) {
                 uint32_t imm12 = instr & 0xFFF;
@@ -418,7 +542,7 @@
                 DumpReg(os, Rt);
                 os << ", [";
                 DumpReg(os, Rn);
-                os << ", #" << imm12 << "]  // ";
+                os << ", #" << imm12 << "]";
               }
               break;
             }
@@ -448,21 +572,21 @@
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
-            os << ", #" << imm12 << "]  // ";
+            os << ", #" << imm12 << "]";
           } else if (op4 == 0) {
             // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm
             uint32_t imm2 = (instr >> 4) & 0xF;
-            uint32_t Rm = instr & 0xF;
+            uint32_t rm = instr & 0xF;
             os << "LDR.W ";
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
             os << ", ";
-            DumpReg(os, Rm);
+            DumpReg(os, rm);
             if (imm2 != 0) {
               os << ", LSL #" << imm2;
             }
-            os << "]  // ";
+            os << "]";
           } else {
             // LDRT Rt, [Rn, #imm8]            - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
             uint32_t imm8 = instr & 0xFF;
@@ -470,7 +594,7 @@
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
-            os << ", #" << imm8 << "]  // ";
+            os << ", #" << imm8 << "]";
           }
           break;
         }
@@ -478,7 +602,7 @@
     default:
       break;
   }
-  os << StringPrintf("%08x\n", instr);
+  os << '\n';
   return 4;
 }
 
@@ -488,7 +612,7 @@
   if (is_32bit) {
     return DumpThumb32(os, instr_ptr);
   } else {
-    os << StringPrintf("\t\t\t%p: ", instr_ptr);
+    os << StringPrintf("\t\t\t%p: %04x    : ", instr_ptr, instr);
     uint16_t opcode1 = instr >> 10;
     if (opcode1 < 0x10) {
       // shift (immediate), add, subtract, move, and compare
@@ -500,7 +624,7 @@
           // Logical shift right    - 00 001xx xxxxxxxxx
           // Arithmetic shift right - 00 010xx xxxxxxxxx
           uint16_t imm5 = (instr >> 6) & 0x1F;
-          uint16_t Rm = (instr >> 3) & 7;
+          uint16_t rm = (instr >> 3) & 7;
           uint16_t Rd = instr & 7;
           if (opcode2 <= 3) {
             os << "LSLS ";
@@ -511,8 +635,8 @@
           }
           DumpReg(os, Rd);
           os << ", ";
-          DumpReg(os, Rm);
-          os << ", #" << imm5 << "  // ";
+          DumpReg(os, rm);
+          os << ", #" << imm5;
           break;
         }
         case 0xC: case 0xD: case 0xE: case 0xF: {
@@ -541,7 +665,6 @@
           } else if (imm3_or_Rm != 0) {
             os << ", #" << imm3_or_Rm;
           }
-          os << "  // ";
           break;
         }
         case 0x10: case 0x11: case 0x12: case 0x13:
@@ -561,7 +684,7 @@
             case 7: os << "SUBS "; break;
           }
           DumpReg(os, Rn);
-          os << ", #" << imm8 << "  // ";
+          os << ", #" << imm8;
           break;
         }
         default:
@@ -575,54 +698,50 @@
           // Add low registers  - 010001 0000 xxxxxx
           // Add high registers - 010001 0001/001x xxxxxx
           uint16_t DN = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rdn = instr & 7;
           uint16_t DN_Rdn = (DN << 3) | Rdn;
           os << "ADD ";
           DumpReg(os, DN_Rdn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0x8: case 0x9: case 0xA: case 0xB: {
           // Move low registers  - 010001 1000 xxxxxx
           // Move high registers - 010001 1001/101x xxxxxx
           uint16_t DN = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rdn = instr & 7;
           uint16_t DN_Rdn = (DN << 3) | Rdn;
           os << "MOV ";
           DumpReg(os, DN_Rdn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0x5: case 0x6: case 0x7: {
           // Compare high registers - 010001 0101/011x xxxxxx
           uint16_t N = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rn = instr & 7;
           uint16_t N_Rn = (N << 3) | Rn;
           os << "CMP ";
           DumpReg(os, N_Rn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0xC: case 0xD: case 0xE: case 0xF: {
           // Branch and exchange           - 010001 110x xxxxxx
           // Branch with link and exchange - 010001 111x xxxxxx
-          uint16_t Rm = instr >> 3 & 0xF;
+          uint16_t rm = instr >> 3 & 0xF;
           if ((opcode2 & 0x2) == 0) {
             os << "BX ";
           } else {
             os << "BLX ";
           }
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         default:
@@ -641,7 +760,7 @@
           } else {
             os << "SUB SP, SP, #";
           }
-          os << (imm7 << 2) << "  // ";
+          os << (imm7 << 2);
           break;
         }
         case 0x78: case 0x79: case 0x7A: case 0x7B:  // 1111xxx
@@ -660,7 +779,6 @@
           } else {
             os << "IT " << reinterpret_cast<void*>(opB) << " ";
             DumpCond(os, opA);
-            os << "  // ";
           }
           break;
         }
@@ -687,7 +805,7 @@
           DumpReg(os, Rt);
           os << ", [";
           DumpReg(os, Rn);
-          os << ", #" << (imm5 << 2) << "]  // ";
+          os << ", #" << (imm5 << 2) << "]";
           break;
         }
         case 0x9: {
@@ -701,7 +819,7 @@
             os << "LDR ";
           }
           DumpReg(os, Rt);
-          os << ", [SP, #" << (imm8 << 2) << "]  // ";
+          os << ", [SP, #" << (imm8 << 2) << "]";
           break;
         }
         default:
@@ -713,9 +831,8 @@
       imm32 = (imm32 << 20) >> 20;  // sign extend 12 bit immediate
       os << "B ";
       DumpBranchTarget(os, instr_ptr + 4, imm32);
-      os << "  // ";
     }
-    os << StringPrintf("%04x\n", instr);
+    os << '\n';
   }
   return 2;
 }
diff --git a/src/disassembler_arm.h b/src/disassembler_arm.h
index c9e7f32..81b1b8e 100644
--- a/src/disassembler_arm.h
+++ b/src/disassembler_arm.h
@@ -37,7 +37,6 @@
   void DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32);
   void DumpCond(std::ostream& os, uint32_t cond);
   void DumpReg(std::ostream& os, uint32_t reg);
-  void DumpRegList(std::ostream& os, uint32_t reg_list);
 };
 
 }  // namespace arm
diff --git a/src/heap.cc b/src/heap.cc
index b9e41c0..f4f2996 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -790,8 +790,9 @@
   static Method* FinalizerReference_add =
       java_lang_ref_FinalizerReference_->FindDirectMethod("add", "(Ljava/lang/Object;)V");
   DCHECK(FinalizerReference_add != NULL);
-  Object* args[] = { object };
-  FinalizerReference_add->Invoke(self, NULL, reinterpret_cast<byte*>(&args), NULL);
+  JValue args[1];
+  args[0].l = object;
+  FinalizerReference_add->Invoke(self, NULL, args, NULL);
 }
 
 void Heap::EnqueueClearedReferences(Object** cleared) {
@@ -803,8 +804,9 @@
 
     Thread* self = Thread::Current();
     ScopedThreadStateChange tsc(self, Thread::kRunnable);
-    Object* args[] = { *cleared };
-    ReferenceQueue_add->Invoke(self, NULL, reinterpret_cast<byte*>(&args), NULL);
+    JValue args[1];
+    args[0].l = *cleared;
+    ReferenceQueue_add->Invoke(self, NULL, args, NULL);
     *cleared = NULL;
   }
 }
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index c447de8..eb33a5c 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -163,48 +163,40 @@
     MethodHelper mh(method);
     shorty_ = mh.GetShorty();
     shorty_len_ = mh.GetShortyLength();
-    size_t num_bytes = NumArgArrayBytes(shorty_, shorty_len_);
-    if (num_bytes < kSmallArgArraySizeInBytes) {
+    if (shorty_len_ - 1 < kSmallArgArraySize) {
       arg_array_ = small_arg_array_;
     } else {
-      large_arg_array_.reset(new byte[num_bytes]);
+      large_arg_array_.reset(new JValue[shorty_len_ - 1]);
       arg_array_ = large_arg_array_.get();
     }
   }
 
-  byte* get() {
+  JValue* get() {
     return arg_array_;
   }
 
   void BuildArgArray(JNIEnv* public_env, va_list ap) {
     JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
+    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
       switch (shorty_[i]) {
         case 'Z':
         case 'B':
         case 'C':
         case 'S':
         case 'I':
-          *reinterpret_cast<int32_t*>(&arg_array_[offset]) = va_arg(ap, jint);
-          offset += 4;
+          arg_array_[offset].i = va_arg(ap, jint);
           break;
         case 'F':
-          *reinterpret_cast<float*>(&arg_array_[offset]) = va_arg(ap, jdouble);
-          offset += 4;
+          arg_array_[offset].f = va_arg(ap, jdouble);
           break;
-        case 'L': {
-          Object* obj = DecodeObj(env, va_arg(ap, jobject));
-          *reinterpret_cast<Object**>(&arg_array_[offset]) = obj;
-          offset += sizeof(Object*);
+        case 'L':
+          arg_array_[offset].l = DecodeObj(env, va_arg(ap, jobject));
           break;
-        }
         case 'D':
-          *reinterpret_cast<double*>(&arg_array_[offset]) = va_arg(ap, jdouble);
-          offset += 8;
+          arg_array_[offset].d = va_arg(ap, jdouble);
           break;
         case 'J':
-          *reinterpret_cast<int64_t*>(&arg_array_[offset]) = va_arg(ap, jlong);
-          offset += 8;
+          arg_array_[offset].j = va_arg(ap, jlong);
           break;
       }
     }
@@ -212,76 +204,38 @@
 
   void BuildArgArray(JNIEnv* public_env, jvalue* args) {
     JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
+    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
       switch (shorty_[i]) {
         case 'Z':
         case 'B':
         case 'C':
         case 'S':
         case 'I':
-          *reinterpret_cast<uint32_t*>(&arg_array_[offset]) = args[i - 1].i;
-          offset += 4;
+          arg_array_[offset].i = args[offset].i;
           break;
         case 'F':
-          *reinterpret_cast<float*>(&arg_array_[offset]) = args[i - 1].f;
-          offset += 4;
+          arg_array_[offset].f = args[offset].f;
           break;
-        case 'L': {
-          Object* obj = DecodeObj(env, args[i - 1].l);
-          *reinterpret_cast<Object**>(&arg_array_[offset]) = obj;
-          offset += sizeof(Object*);
+        case 'L':
+          arg_array_[offset].l = DecodeObj(env, args[offset].l);
           break;
-        }
         case 'D':
-          *reinterpret_cast<double*>(&arg_array_[offset]) = args[i - 1].d;
-          offset += 8;
+          arg_array_[offset].d = args[offset].d;
           break;
         case 'J':
-          *reinterpret_cast<uint64_t*>(&arg_array_[offset]) = args[i - 1].j;
-          offset += 8;
+          arg_array_[offset].j = args[offset].j;
           break;
       }
     }
   }
 
-  void BuildArgArray(JValue* args) {
-    for (size_t i = 1, offset = 0; i < shorty_len_; ++i) {
-      switch (shorty_[i]) {
-      case 'Z':
-      case 'B':
-      case 'C':
-      case 'S':
-      case 'I':
-        *reinterpret_cast<uint32_t*>(&arg_array_[offset]) = args[i - 1].i;
-        offset += 4;
-        break;
-      case 'F':
-        *reinterpret_cast<float*>(&arg_array_[offset]) = args[i - 1].f;
-        offset += 4;
-        break;
-      case 'L':
-        *reinterpret_cast<Object**>(&arg_array_[offset]) = args[i - 1].l;
-        offset += sizeof(Object*);
-        break;
-      case 'D':
-        *reinterpret_cast<double*>(&arg_array_[offset]) = args[i - 1].d;
-        offset += 8;
-        break;
-      case 'J':
-        *reinterpret_cast<uint64_t*>(&arg_array_[offset]) = args[i - 1].j;
-        offset += 8;
-        break;
-      }
-    }
-  }
-
  private:
-  enum { kSmallArgArraySizeInBytes = 48 };
+  enum { kSmallArgArraySize = 16 };
   const char* shorty_;
   uint32_t shorty_len_;
-  byte* arg_array_;
-  byte small_arg_array_[kSmallArgArraySizeInBytes];
-  UniquePtr<byte[]> large_arg_array_;
+  JValue* arg_array_;
+  JValue small_arg_array_[kSmallArgArraySize];
+  UniquePtr<JValue[]> large_arg_array_;
 };
 
 namespace {
@@ -303,7 +257,7 @@
   return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
 }
 
-static JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, byte* args) {
+static JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, JValue* args) {
   JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
   JValue result;
   method->Invoke(env->self, receiver, args, &result);
@@ -723,9 +677,7 @@
 }
 
 JValue InvokeWithJValues(Thread* self, Object* receiver, Method* m, JValue* args) {
-  ArgArray arg_array(m);
-  arg_array.BuildArgArray(args);
-  return InvokeWithArgArray(self->GetJniEnv(), receiver, m, arg_array.get());
+  return InvokeWithArgArray(self->GetJniEnv(), receiver, m, args);
 }
 
 class JNI {
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index 6197f15..476c623 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
+#include <stdint.h>
 
 #include <algorithm>
 
@@ -83,34 +83,51 @@
   __ LoadImmediate(IP, 0, AL);
   __ StoreToOffset(kStoreWord, IP, SP, 0);
 
-  // Copy values by stack
-  for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
-    // we're displaced off of r3 by bytes that'll go in registers
-    int r3_offset = reg_bytes + off;
-    __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
+  // Copy values onto the stack.
+  size_t src_offset = 0;
+  size_t dst_offset = (is_static ? 1 : 2) * kPointerSize;
+  for (size_t i = 1; i < shorty_len; ++i) {
+    switch (shorty[i]) {
+      case 'D':
+      case 'J':
+        // Move both pointers 64 bits.
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += kPointerSize;
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
 
-    // we're displaced off of the arguments by the spill space for the incoming
-    // arguments, the Method* and possibly the receiver
-    int sp_offset = reg_bytes + (is_static ? 1 : 2) * kPointerSize + off;
-    __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += kPointerSize;
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
+        break;
+      default:
+        // Move the source pointer sizeof(JValue) and the destination pointer 32 bits.
+        __ LoadFromOffset(kLoadWord, IP, R3, src_offset);
+        src_offset += sizeof(JValue);
+        __ StoreToOffset(kStoreWord, IP, SP, dst_offset);
+        dst_offset += kPointerSize;
+        break;
+    }
   }
 
   // Move all the register arguments into place.
+  dst_offset = (is_static ? 1 : 2) * kPointerSize;
   if (is_static) {
-    if (reg_bytes > 0) {
-      __ LoadFromOffset(kLoadWord, R1, R3, 0);
-      if (reg_bytes > 4) {
-        __ LoadFromOffset(kLoadWord, R2, R3, 4);
-        if (reg_bytes > 8) {
-          __ LoadFromOffset(kLoadWord, R3, R3, 8);
+    if (reg_bytes > 0 && num_arg_array_bytes > 0) {
+      __ LoadFromOffset(kLoadWord, R1, SP, dst_offset + 0);
+      if (reg_bytes > 4 && num_arg_array_bytes > 4) {
+        __ LoadFromOffset(kLoadWord, R2, SP, dst_offset + 4);
+        if (reg_bytes > 8 && num_arg_array_bytes > 8) {
+          __ LoadFromOffset(kLoadWord, R3, SP, dst_offset + 8);
         }
       }
     }
   } else {
-    if (reg_bytes > 0) {
-      __ LoadFromOffset(kLoadWord, R2, R3, 0);
-      if (reg_bytes > 4) {
-        __ LoadFromOffset(kLoadWord, R3, R3, 4);
+    if (reg_bytes > 0 && num_arg_array_bytes > 0) {
+      __ LoadFromOffset(kLoadWord, R2, SP, dst_offset + 0);
+      if (reg_bytes > 4 && num_arg_array_bytes > 4) {
+        __ LoadFromOffset(kLoadWord, R3, SP, dst_offset + 4);
       }
     }
   }
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index a67bec1..e1f62fc 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -52,6 +52,517 @@
     CommonTest::TearDown();
   }
 
+  Method::InvokeStub* DoCompile(Method*& method, Object*& receiver, bool is_static, const char* method_name, const char* method_signature) {
+    const char* class_name = is_static ? "StaticLeafMethods" : "NonStaticLeafMethods";
+    SirtRef<ClassLoader> class_loader(LoadDex(class_name));
+    if (is_static) {
+      CompileDirectMethod(class_loader.get(), class_name, method_name, method_signature);
+    } else {
+      CompileVirtualMethod(NULL, "java.lang.Class", "isFinalizable", "()Z");
+      CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+      CompileVirtualMethod(class_loader.get(), class_name, method_name, method_signature);
+    }
+
+    Class* c = class_linker_->FindClass(DotToDescriptor(class_name).c_str(), class_loader.get());
+    CHECK(c != NULL);
+
+    method = is_static ? c->FindDirectMethod(method_name, method_signature) : c->FindVirtualMethod(method_name, method_signature);
+    CHECK(method != NULL);
+
+    receiver = (is_static ? NULL : c->AllocObject());
+
+    Method::InvokeStub* stub = method->GetInvokeStub();
+    CHECK(stub != NULL);
+
+    return stub;
+  }
+
+  void InvokeNopMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "nop", "()V");
+    (*stub)(method, receiver, Thread::Current(), NULL, NULL);
+  }
+
+  void InvokeIdentityByteMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "identity", "(B)B");
+
+    JValue args[1];
+    JValue result;
+
+    args[0].i = 0;
+    result.b = -1;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.b);
+
+    args[0].i = -1;
+    result.b = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(-1, result.b);
+
+    args[0].i = SCHAR_MAX;
+    result.b = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(SCHAR_MAX, result.b);
+
+    args[0].i = SCHAR_MIN;
+    result.b = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(SCHAR_MIN, result.b);
+  }
+
+  void InvokeIdentityIntMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "identity", "(I)I");
+
+    JValue args[1];
+    JValue result;
+
+    args[0].i = 0;
+    result.i = -1;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.i);
+
+    args[0].i = -1;
+    result.i = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(-1, result.i);
+
+    args[0].i = INT_MAX;
+    result.i = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(INT_MAX, result.i);
+
+    args[0].i = INT_MIN;
+    result.i = 0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(INT_MIN, result.i);
+  }
+
+  void InvokeIdentityDoubleMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "identity", "(D)D");
+
+    JValue args[1];
+    JValue result;
+
+    args[0].d = 0.0;
+    result.d = -1.0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(0.0, result.d);
+
+    args[0].d = -1.0;
+    result.d = 0.0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(-1.0, result.d);
+
+    args[0].d = DBL_MAX;
+    result.d = 0.0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(DBL_MAX, result.d);
+
+    args[0].d = DBL_MIN;
+    result.d = 0.0;
+    (*stub)(method, receiver, Thread::Current(), args, &result);
+    EXPECT_EQ(DBL_MIN, result.d);
+  }
+
+  void InvokeSumIntIntMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(II)I");
+
+    JValue result;
+    result.i = -1;
+    JValue args[2];
+    args[0].i = 0;
+    args[1].i = 0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.i);
+
+    result.i = 0;
+    args[0].i = 1;
+    args[1].i = 2;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(3, result.i);
+
+    result.i = 0;
+    args[0].i = -2;
+    args[1].i = 5;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(3, result.i);
+
+    result.i = 1234;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MIN;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-1, result.i);
+
+    result.i = INT_MIN;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-2, result.i);
+  }
+
+  void InvokeSumIntIntIntMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(III)I");
+
+    JValue result;
+    result.i = -1;
+    JValue args[3];
+    args[0].i = 0;
+    args[1].i = 0;
+    args[2].i = 0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.i);
+
+    result.i = 0;
+    args[0].i = 1;
+    args[1].i = 2;
+    args[2].i = 3;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(6, result.i);
+
+    result.i = 0;
+    args[0].i = -1;
+    args[1].i = 2;
+    args[2].i = -3;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-2, result.i);
+
+    result.i = 1234;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MIN;
+    args[2].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2147483646, result.i);
+
+    result.i = INT_MIN;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MAX;
+    args[2].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2147483645, result.i);
+  }
+
+  void InvokeSumIntIntIntIntMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(IIII)I");
+
+    JValue result;
+    result.i = -1;
+    JValue args[4];
+    args[0].i = 0;
+    args[1].i = 0;
+    args[2].i = 0;
+    args[3].i = 0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.i);
+
+    result.i = 0;
+    args[0].i = 1;
+    args[1].i = 2;
+    args[2].i = 3;
+    args[3].i = 4;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(10, result.i);
+
+    result.i = 0;
+    args[0].i = -1;
+    args[1].i = 2;
+    args[2].i = -3;
+    args[3].i = 4;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2, result.i);
+
+    result.i = 1234;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MIN;
+    args[2].i = INT_MAX;
+    args[3].i = INT_MIN;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-2, result.i);
+
+    result.i = INT_MIN;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MAX;
+    args[2].i = INT_MAX;
+    args[3].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-4, result.i);
+  }
+
+  void InvokeSumIntIntIntIntIntMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(IIIII)I");
+
+    JValue result;
+    result.i = -1.0;
+    JValue args[5];
+    args[0].i = 0;
+    args[1].i = 0;
+    args[2].i = 0;
+    args[3].i = 0;
+    args[4].i = 0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0, result.i);
+
+    result.i = 0;
+    args[0].i = 1;
+    args[1].i = 2;
+    args[2].i = 3;
+    args[3].i = 4;
+    args[4].i = 5;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(15, result.i);
+
+    result.i = 0;
+    args[0].i = -1;
+    args[1].i = 2;
+    args[2].i = -3;
+    args[3].i = 4;
+    args[4].i = -5;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-3, result.i);
+
+    result.i = 1234;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MIN;
+    args[2].i = INT_MAX;
+    args[3].i = INT_MIN;
+    args[4].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2147483645, result.i);
+
+    result.i = INT_MIN;
+    args[0].i = INT_MAX;
+    args[1].i = INT_MAX;
+    args[2].i = INT_MAX;
+    args[3].i = INT_MAX;
+    args[4].i = INT_MAX;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2147483643, result.i);
+  }
+
+  void InvokeSumDoubleDoubleMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(DD)D");
+
+    JValue args[2];
+    JValue result;
+
+    args[0].d = 0.0;
+    args[1].d = 0.0;
+    result.d = -1.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = 2.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(3.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = -2.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-1.0, result.d);
+
+    args[0].d = DBL_MAX;
+    args[1].d = DBL_MIN;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(1.7976931348623157e308, result.d);
+
+    args[0].d = DBL_MAX;
+    args[1].d = DBL_MAX;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(INFINITY, result.d);
+  }
+
+  void InvokeSumDoubleDoubleDoubleMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(DDD)D");
+
+    JValue args[3];
+    JValue result;
+
+    args[0].d = 0.0;
+    args[1].d = 0.0;
+    args[2].d = 0.0;
+    result.d = -1.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = 2.0;
+    args[2].d = 3.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(6.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = -2.0;
+    args[2].d = 3.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(2.0, result.d);
+  }
+
+  void InvokeSumDoubleDoubleDoubleDoubleMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(DDDD)D");
+
+    JValue args[4];
+    JValue result;
+
+    args[0].d = 0.0;
+    args[1].d = 0.0;
+    args[2].d = 0.0;
+    args[3].d = 0.0;
+    result.d = -1.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = 2.0;
+    args[2].d = 3.0;
+    args[3].d = 4.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(10.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = -2.0;
+    args[2].d = 3.0;
+    args[3].d = -4.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(-2.0, result.d);
+  }
+
+  void InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(bool is_static) {
+    // TODO: remove this when we have a working x86 compiler.
+#if !defined(__arm__)
+    if (!is_static) {
+      return;
+    }
+#endif
+    Method* method;
+    Object* receiver;
+    Method::InvokeStub* stub = DoCompile(method, receiver, is_static, "sum", "(DDDDD)D");
+
+    JValue args[5];
+    JValue result;
+
+    args[0].d = 0.0;
+    args[1].d = 0.0;
+    args[2].d = 0.0;
+    args[3].d = 0.0;
+    args[4].d = 0.0;
+    result.d = -1.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(0.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = 2.0;
+    args[2].d = 3.0;
+    args[3].d = 4.0;
+    args[4].d = 5.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(15.0, result.d);
+
+    args[0].d = 1.0;
+    args[1].d = -2.0;
+    args[2].d = 3.0;
+    args[3].d = -4.0;
+    args[4].d = 5.0;
+    result.d = 0.0;
+    (*stub)(method, NULL, Thread::Current(), args, &result);
+    EXPECT_EQ(3.0, result.d);
+  }
+
   JavaVMExt* vm_;
   JNIEnvExt* env_;
   jclass aioobe_;
@@ -903,695 +1414,106 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  Object* arg = NULL;
+  JValue args[1];
+  args[0].l = NULL;
 
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), NULL);
+  (*stub)(method, NULL, Thread::Current(), args, NULL);
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "nop", "()V");
+  InvokeNopMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("nop", "()V");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  (*stub)(method, NULL, Thread::Current(), NULL, NULL);
+TEST_F(JniInternalTest, NonStaticNopMethod) {
+  InvokeNopMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityByteMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "identity", "(B)B");
+  InvokeIdentityByteMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("identity", "(B)B");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  int arg;
-  JValue result;
-
-  arg = 0;
-  result.b = -1;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(0, result.b);
-
-  arg = -1;
-  result.b = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(-1, result.b);
-
-  arg = SCHAR_MAX;
-  result.b = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(SCHAR_MAX, result.b);
-
-  arg = SCHAR_MIN;
-  result.b = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(SCHAR_MIN, result.b);
+TEST_F(JniInternalTest, NonStaticIdentityByteMethod) {
+  InvokeIdentityByteMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityIntMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "identity", "(I)I");
+  InvokeIdentityIntMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("identity", "(I)I");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  int arg;
-  JValue result;
-
-  arg = 0;
-  result.i = -1;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(0, result.i);
-
-  arg = -1;
-  result.i = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(-1, result.i);
-
-  arg = INT_MAX;
-  result.i = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(INT_MAX, result.i);
-
-  arg = INT_MIN;
-  result.i = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(INT_MIN, result.i);
+TEST_F(JniInternalTest, NonStaticIdentityIntMethod) {
+  InvokeIdentityIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "identity", "(D)D");
-
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("identity", "(D)D");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  double arg;
-  JValue result;
-
-  arg = 0.0;
-  result.d = -1.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(0.0, result.d);
-
-  arg = -1.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(-1.0, result.d);
-
-  arg = DBL_MAX;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(DBL_MAX, result.d);
-
-  arg = DBL_MIN;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
-  EXPECT_EQ(DBL_MIN, result.d);
+  InvokeIdentityDoubleMethod(true);
 }
 
-#if defined(ART_USE_LLVM_COMPILER)
-static byte* CreateArgArray(Method* method, JValue* args) {
-  const char* shorty = MethodHelper(method).GetShorty();
-  size_t shorty_len = strlen(shorty);
-  UniquePtr<byte[]> arg_array(new byte[shorty_len * 8]);
-  for (size_t i = 1, offset = 0; i < shorty_len; ++i) {
-    switch (shorty[i]) {
-    case 'Z':
-    case 'B':
-    case 'C':
-    case 'S':
-    case 'I':
-      *reinterpret_cast<uint32_t*>(&arg_array[offset]) = args[i - 1].i;
-      break;
-    case 'F':
-      *reinterpret_cast<float*>(&arg_array[offset]) = args[i - 1].f;
-      break;
-    case 'L':
-      *reinterpret_cast<Object**>(&arg_array[offset]) = args[i - 1].l;
-      break;
-    case 'D':
-      *reinterpret_cast<double*>(&arg_array[offset]) = args[i - 1].d;
-      break;
-    case 'J':
-      *reinterpret_cast<uint64_t*>(&arg_array[offset]) = args[i - 1].j;
-      break;
-    }
-    offset += 8;
-  }
-  return arg_array.release();
+TEST_F(JniInternalTest, NonStaticIdentityDoubleMethod) {
+  InvokeIdentityDoubleMethod(false);
 }
-#endif
 
 TEST_F(JniInternalTest, StaticSumIntIntMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(II)I");
+  InvokeSumIntIntMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(II)I");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  JValue result;
-  result.i = -1;
-#if !defined(ART_USE_LLVM_COMPILER)
-  int args[2];
-  args[0] = 0;
-  args[1] = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  JValue args[2];
-  args[0].i = 0;
-  args[1].i = 0;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(0, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = 1;
-  args[1] = 2;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = 1;
-  args[1].i = 2;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(3, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = -2;
-  args[1] = 5;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = -2;
-  args[1].i = 5;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(3, result.i);
-
-  result.i = 1234;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MIN;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MIN;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-1, result.i);
-
-  result.i = INT_MIN;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-2, result.i);
+TEST_F(JniInternalTest, NonStaticSumIntIntMethod) {
+  InvokeSumIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(III)I");
+  InvokeSumIntIntIntMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(III)I");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  JValue result;
-  result.i = -1;
-#if !defined(ART_USE_LLVM_COMPILER)
-  int args[3];
-  args[0] = 0;
-  args[1] = 0;
-  args[2] = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  JValue args[3];
-  args[0].i = 0;
-  args[1].i = 0;
-  args[2].i = 0;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(0, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = 1;
-  args[1] = 2;
-  args[2] = 3;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = 1;
-  args[1].i = 2;
-  args[2].i = 3;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(6, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = -1;
-  args[1] = 2;
-  args[2] = -3;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = -1;
-  args[1].i = 2;
-  args[2].i = -3;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-2, result.i);
-
-  result.i = 1234;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MIN;
-  args[2] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MIN;
-  args[2].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(2147483646, result.i);
-
-  result.i = INT_MIN;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MAX;
-  args[2] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MAX;
-  args[2].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(2147483645, result.i);
+TEST_F(JniInternalTest, NonStaticSumIntIntIntMethod) {
+  InvokeSumIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(IIII)I");
+  InvokeSumIntIntIntIntMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(IIII)I");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  JValue result;
-  result.i = -1;
-#if !defined(ART_USE_LLVM_COMPILER)
-  int args[4];
-  args[0] = 0;
-  args[1] = 0;
-  args[2] = 0;
-  args[3] = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  JValue args[4];
-  args[0].i = 0;
-  args[1].i = 0;
-  args[2].i = 0;
-  args[3].i = 0;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(0, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = 1;
-  args[1] = 2;
-  args[2] = 3;
-  args[3] = 4;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = 1;
-  args[1].i = 2;
-  args[2].i = 3;
-  args[3].i = 4;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(10, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = -1;
-  args[1] = 2;
-  args[2] = -3;
-  args[3] = 4;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = -1;
-  args[1].i = 2;
-  args[2].i = -3;
-  args[3].i = 4;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(2, result.i);
-
-  result.i = 1234;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MIN;
-  args[2] = INT_MAX;
-  args[3] = INT_MIN;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MIN;
-  args[2].i = INT_MAX;
-  args[3].i = INT_MIN;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-2, result.i);
-
-  result.i = INT_MIN;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MAX;
-  args[2] = INT_MAX;
-  args[3] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MAX;
-  args[2].i = INT_MAX;
-  args[3].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-4, result.i);
+TEST_F(JniInternalTest, NonStaticSumIntIntIntIntMethod) {
+  InvokeSumIntIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(IIIII)I");
+  InvokeSumIntIntIntIntIntMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(IIIII)I");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  JValue result;
-  result.i = -1.0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  int args[5];
-  args[0] = 0;
-  args[1] = 0;
-  args[2] = 0;
-  args[3] = 0;
-  args[4] = 0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  JValue args[5];
-  args[0].i = 0;
-  args[1].i = 0;
-  args[2].i = 0;
-  args[3].i = 0;
-  args[4].i = 0;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(0, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = 1;
-  args[1] = 2;
-  args[2] = 3;
-  args[3] = 4;
-  args[4] = 5;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = 1;
-  args[1].i = 2;
-  args[2].i = 3;
-  args[3].i = 4;
-  args[4].i = 5;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(15, result.i);
-
-  result.i = 0;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = -1;
-  args[1] = 2;
-  args[2] = -3;
-  args[3] = 4;
-  args[4] = -5;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = -1;
-  args[1].i = 2;
-  args[2].i = -3;
-  args[3].i = 4;
-  args[4].i = -5;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(-3, result.i);
-
-  result.i = 1234;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MIN;
-  args[2] = INT_MAX;
-  args[3] = INT_MIN;
-  args[4] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MIN;
-  args[2].i = INT_MAX;
-  args[3].i = INT_MIN;
-  args[4].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(2147483645, result.i);
-
-  result.i = INT_MIN;
-#if !defined(ART_USE_LLVM_COMPILER)
-  args[0] = INT_MAX;
-  args[1] = INT_MAX;
-  args[2] = INT_MAX;
-  args[3] = INT_MAX;
-  args[4] = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-#else
-  args[0].i = INT_MAX;
-  args[1].i = INT_MAX;
-  args[2].i = INT_MAX;
-  args[3].i = INT_MAX;
-  args[4].i = INT_MAX;
-  (*stub)(method, NULL, Thread::Current(), CreateArgArray(method, args), &result);
-#endif
-  EXPECT_EQ(2147483643, result.i);
+TEST_F(JniInternalTest, NonStaticSumIntIntIntIntIntMethod) {
+  InvokeSumIntIntIntIntIntMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(DD)D");
+  InvokeSumDoubleDoubleMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(DD)D");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  double args[2];
-  JValue result;
-
-  args[0] = 0.0;
-  args[1] = 0.0;
-  result.d = -1.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(0.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = 2.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(3.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = -2.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(-1.0, result.d);
-
-  args[0] = DBL_MAX;
-  args[1] = DBL_MIN;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(1.7976931348623157e308, result.d);
-
-  args[0] = DBL_MAX;
-  args[1] = DBL_MAX;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(INFINITY, result.d);
+TEST_F(JniInternalTest, NonStaticSumDoubleDoubleMethod) {
+  InvokeSumDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(DDD)D");
+  InvokeSumDoubleDoubleDoubleMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(DDD)D");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  double args[3];
-  JValue result;
-
-  args[0] = 0.0;
-  args[1] = 0.0;
-  args[2] = 0.0;
-  result.d = -1.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(0.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = 2.0;
-  args[2] = 3.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(6.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = -2.0;
-  args[2] = 3.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(2.0, result.d);
+TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleMethod) {
+  InvokeSumDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(DDDD)D");
+  InvokeSumDoubleDoubleDoubleDoubleMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(DDDD)D");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  double args[4];
-  JValue result;
-
-  args[0] = 0.0;
-  args[1] = 0.0;
-  args[2] = 0.0;
-  args[3] = 0.0;
-  result.d = -1.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(0.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = 2.0;
-  args[2] = 3.0;
-  args[3] = 4.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(10.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = -2.0;
-  args[2] = 3.0;
-  args[3] = -4.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(-2.0, result.d);
+TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleMethod) {
+  InvokeSumDoubleDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
-  SirtRef<ClassLoader> class_loader(LoadDex("StaticLeafMethods"));
-  CompileDirectMethod(class_loader.get(), "StaticLeafMethods", "sum", "(DDDDD)D");
+  InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(true);
+}
 
-  Class* klass = class_linker_->FindClass("LStaticLeafMethods;", class_loader.get());
-  ASSERT_TRUE(klass != NULL);
-
-  Method* method = klass->FindDirectMethod("sum", "(DDDDD)D");
-  ASSERT_TRUE(method != NULL);
-
-  Method::InvokeStub* stub = method->GetInvokeStub();
-
-  double args[5];
-  JValue result;
-
-  args[0] = 0.0;
-  args[1] = 0.0;
-  args[2] = 0.0;
-  args[3] = 0.0;
-  args[4] = 0.0;
-  result.d = -1.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(0.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = 2.0;
-  args[2] = 3.0;
-  args[3] = 4.0;
-  args[4] = 5.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(15.0, result.d);
-
-  args[0] = 1.0;
-  args[1] = -2.0;
-  args[2] = 3.0;
-  args[3] = -4.0;
-  args[4] = 5.0;
-  result.d = 0.0;
-  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
-  EXPECT_EQ(3.0, result.d);
+TEST_F(JniInternalTest, NonStaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
+  InvokeSumDoubleDoubleDoubleDoubleDoubleMethod(false);
 }
 
 TEST_F(JniInternalTest, Throw) {
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index e23c87b..361cd70 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "jni_internal.h"
-
 #include "assembler.h"
 #include "compiled_method.h"
 #include "compiler.h"
@@ -63,16 +61,32 @@
   if (pad_size != 0) {
     __ subl(ESP, Immediate(pad_size));
   }
-  // Push/copy arguments
-  for (size_t off = num_arg_array_bytes; off > 0; off -= kPointerSize) {
-    if (off > ((is_static ? 2 : 1) * kPointerSize)) {
-      // Copy argument
-      __ pushl(Address(rArgArray, off - kPointerSize));
-    } else {
-      // Space for argument passed in register
-      __ pushl(Immediate(0));
+
+  // Push/copy arguments.
+  size_t arg_count = (shorty_len - 1);
+  size_t dst_offset = num_arg_array_bytes;
+  size_t src_offset = arg_count * sizeof(JValue);
+  for (size_t i = shorty_len - 1; i > 0; --i) {
+    switch (shorty[i]) {
+      case 'D':
+      case 'J':
+        // Move both pointers 64 bits.
+        dst_offset -= kPointerSize;
+        __ pushl(Address(rArgArray, src_offset));
+        src_offset -= sizeof(JValue);
+        dst_offset -= kPointerSize;
+        __ pushl(Address(rArgArray, src_offset));
+        src_offset -= sizeof(JValue);
+        break;
+      default:
+        // Move the source pointer sizeof(JValue) and the destination pointer 32 bits.
+        dst_offset -= kPointerSize;
+        __ pushl(Address(rArgArray, src_offset));
+        src_offset -= sizeof(JValue);
+        break;
     }
   }
+
   // Backing space for receiver
   if (!is_static) {
     __ pushl(Immediate(0));
@@ -81,16 +95,17 @@
   __ pushl(Immediate(0));
   if (!is_static) {
     if (num_arg_array_bytes >= static_cast<size_t>(kPointerSize)) {
-      // Receiver already in EDX, pass 1st arg in ECX
+      // Receiver already in EDX, pass 1st arg in ECX.
       __ movl(ECX, Address(rArgArray, 0));
     }
   } else {
     if (num_arg_array_bytes >= static_cast<size_t>(kPointerSize)) {
-      // Pass 1st arg in EDX
+      // Pass 1st arg in EDX.
       __ movl(EDX, Address(rArgArray, 0));
       if (num_arg_array_bytes >= static_cast<size_t>(2* kPointerSize)) {
-        // Pass 2nd arg in ECX
-        __ movl(ECX, Address(rArgArray, kPointerSize));
+        // Pass 2nd arg (or second 32-bit chunk of a wide 1st arg) in ECX.
+        bool is_wide = (shorty[1] == 'D' || shorty[1] == 'J');
+        __ movl(ECX, Address(rArgArray, is_wide ? kPointerSize : 2 * kPointerSize));
       }
     }
   }
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 96af3b0..9641390 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -281,8 +281,6 @@
     std::string signature(dex_file.GetMethodSignature(method_id));
     os << StringPrintf("\t%d: %s %s (dex_method_idx=%d)\n",
                        class_method_index, name, signature.c_str(), dex_method_idx);
-    os << StringPrintf("\t\tcode: %p (offset=0x%08x)\n",
-                       oat_method.GetCode(), oat_method.GetCodeOffset());
     os << StringPrintf("\t\tframe_size_in_bytes: %zd\n",
                        oat_method.GetFrameSizeInBytes());
     os << StringPrintf("\t\tcore_spill_mask: 0x%08x",
@@ -301,11 +299,17 @@
     os << StringPrintf("\t\tgc_map: %p (offset=0x%08x)\n",
                        oat_method.GetGcMap(), oat_method.GetGcMapOffset());
     DumpGcMap(os, oat_method.GetGcMap());
-    os << StringPrintf("\t\tinvoke_stub: %p (offset=0x%08x)\n",
-                       oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
-    os << "\t\tCODE: (size=" << oat_method.GetCodeSize() << ")\n";
+    os << StringPrintf("\t\tCODE: %p (offset=0x%08x size=%d)%s\n",
+                       oat_method.GetCode(),
+                       oat_method.GetCodeOffset(),
+                       oat_method.GetCodeSize(),
+                       oat_method.GetCode() != NULL ? "..." : "");
     DumpCode(os, oat_method.GetCode(), oat_method.GetMappingTable(), dex_file, code_item);
-    os << "\t\tINVOKE STUB: (size=" << oat_method.GetInvokeStubSize() << ")\n";
+    os << StringPrintf("\t\tINVOKE STUB: %p (offset=0x%08x size=%d)%s\n",
+                       oat_method.GetInvokeStub(),
+                       oat_method.GetInvokeStubOffset(),
+                       oat_method.GetInvokeStubSize(),
+                       oat_method.GetInvokeStub() != NULL ? "..." : "");
     DumpCode(os, reinterpret_cast<const void*>(oat_method.GetInvokeStub()), NULL, dex_file, NULL);
   }
 
diff --git a/src/object.cc b/src/object.cc
index 2e98f4f..59fa28b 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -556,7 +556,7 @@
   return DexFile::kDexNoIndex;
 }
 
-void Method::Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const {
+void Method::Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) const {
   // Push a transition back into managed code onto the linked list in thread.
   CHECK_EQ(Thread::kRunnable, self->GetState());
   NativeToManagedRecord record;
diff --git a/src/object.h b/src/object.h
index 3a7efa2..ae435c6 100644
--- a/src/object.h
+++ b/src/object.h
@@ -490,7 +490,7 @@
   typedef void InvokeStub(const Method* method,
                           Object* obj,
                           Thread* thread,
-                          byte* args,
+                          JValue* args,
                           JValue* result);
 
   Class* GetDeclaringClass() const;
@@ -623,7 +623,7 @@
   // Find the method that this method overrides
   Method* FindOverriddenMethod() const;
 
-  void Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
+  void Invoke(Thread* self, Object* receiver, JValue* args, JValue* result) const;
 
   const void* GetCode() const {
     return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
diff --git a/src/reflection.cc b/src/reflection.cc
index c317be0..6aa239e 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -235,40 +235,30 @@
   }
 
   Method* m = NULL;
-  UniquePtr<byte[]> args(new byte[8]);
-  memset(&args[0], 0, 8);
   switch (src_class) {
   case Primitive::kPrimBoolean:
     m = gBoolean_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.z;
     break;
   case Primitive::kPrimByte:
     m = gByte_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.b;
     break;
   case Primitive::kPrimChar:
     m = gCharacter_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.c;
     break;
   case Primitive::kPrimDouble:
     m = gDouble_valueOf;
-    *reinterpret_cast<double*>(&args[0]) = value.d;
     break;
   case Primitive::kPrimFloat:
     m = gFloat_valueOf;
-    *reinterpret_cast<float*>(&args[0]) = value.f;
     break;
   case Primitive::kPrimInt:
     m = gInteger_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.i;
     break;
   case Primitive::kPrimLong:
     m = gLong_valueOf;
-    *reinterpret_cast<uint64_t*>(&args[0]) = value.j;
     break;
   case Primitive::kPrimShort:
     m = gShort_valueOf;
-    *reinterpret_cast<uint32_t*>(&args[0]) = value.s;
     break;
   case Primitive::kPrimVoid:
     // There's no such thing as a void field, and void methods invoked via reflection return null.
@@ -280,7 +270,9 @@
 
   Thread* self = Thread::Current();
   ScopedThreadStateChange tsc(self, Thread::kRunnable);
-  m->Invoke(self, NULL, args.get(), &value);
+  JValue args[1];
+  args[0].j = 0;
+  m->Invoke(self, NULL, args, &value);
 }
 
 bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value, const char* what) {
diff --git a/src/thread.cc b/src/thread.cc
index 629cb0f..58ef1fe 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -949,10 +949,10 @@
 
   // Call the handler.
   Method* m = handler->GetClass()->FindVirtualMethodForVirtualOrInterface(gUncaughtExceptionHandler_uncaughtException);
-  Object* args[2];
-  args[0] = peer_;
-  args[1] = exception;
-  m->Invoke(this, handler, reinterpret_cast<byte*>(&args), NULL);
+  JValue args[2];
+  args[0].l = peer_;
+  args[1].l = exception;
+  m->Invoke(this, handler, args, NULL);
 
   // If the handler threw, clear that exception too.
   ClearException();
@@ -968,8 +968,9 @@
   Object* group = GetThreadGroup();
   if (group != NULL) {
     Method* m = group->GetClass()->FindVirtualMethodForVirtualOrInterface(gThreadGroup_removeThread);
-    Object* args = peer_;
-    m->Invoke(this, group, reinterpret_cast<byte*>(&args), NULL);
+    JValue args[1];
+    args[0].l = peer_;
+    m->Invoke(this, group, args, NULL);
   }
 }
 
diff --git a/test/NonStaticLeafMethods/NonStaticLeafMethods.java b/test/NonStaticLeafMethods/NonStaticLeafMethods.java
new file mode 100644
index 0000000..28e03c6
--- /dev/null
+++ b/test/NonStaticLeafMethods/NonStaticLeafMethods.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class NonStaticLeafMethods {
+    NonStaticLeafMethods() {
+    }
+    void nop() {
+    }
+    byte identity(byte x) {
+        return x;
+    }
+    int identity(int x) {
+        return x;
+    }
+    int sum(int a, int b) {
+        return a + b;
+    }
+    int sum(int a, int b, int c) {
+        return a + b + c;
+    }
+    int sum(int a, int b, int c, int d) {
+        return a + b + c + d;
+    }
+    int sum(int a, int b, int c, int d, int e) {
+        return a + b + c + d + e;
+    }
+    double identity(double x) {
+        return x;
+    }
+    double sum(double a, double b) {
+        return a + b;
+    }
+    double sum(double a, double b, double c) {
+        return a + b + c;
+    }
+    double sum(double a, double b, double c, double d) {
+        return a + b + c + d;
+    }
+    double sum(double a, double b, double c, double d, double e) {
+        return a + b + c + d + e;
+    }
+}
diff --git a/test/ReflectionTest/ReflectionTest.java b/test/ReflectionTest/ReflectionTest.java
index 94c02aa..a9dc6e7 100644
--- a/test/ReflectionTest/ReflectionTest.java
+++ b/test/ReflectionTest/ReflectionTest.java
@@ -119,8 +119,8 @@
     try {
       f = ReflectionTest.class.getDeclaredField("s");
       f.set(null, Integer.valueOf(14));
-    } catch (Exception ex) {
-      ex.printStackTrace();
+    } catch (IllegalArgumentException expected) {
+      expected.printStackTrace();
     }
 
     f = ReflectionTest.class.getDeclaredField("z");
@@ -209,8 +209,8 @@
       System.out.println(Arrays.toString(m.getParameterTypes()));
       show(m.invoke(null));
       System.out.println("************* should have thrown!");
-    } catch (Exception ex) {
-      ex.printStackTrace();
+    } catch (Exception expected) {
+      expected.printStackTrace();
     }
   }