Merge "Prune away extraneous ART_USE_PORTABLE_COMPILER ifdefs." into dalvik-dev
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 9d41e01..d7d8365 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -408,7 +408,6 @@
 	AllFields \
 	CreateMethodSignature \
 	ExceptionHandle \
-	IntMath \
 	Interfaces \
 	Main \
 	MyClass \
@@ -428,7 +427,6 @@
 	Main \
 	HelloWorld \
 	\
-	IntMath \
 	ParallelGC \
 	ReferenceMap \
 	StackWalk \
diff --git a/src/base/mutex.h b/src/base/mutex.h
index 5cc021f..190e779 100644
--- a/src/base/mutex.h
+++ b/src/base/mutex.h
@@ -31,7 +31,7 @@
 #if defined(__APPLE__)
 #define ART_USE_FUTEXES 0
 #else
-#define ART_USE_FUTEXES 1
+#define ART_USE_FUTEXES !defined(__mips__)
 #endif
 
 // Currently Darwin doesn't support locks with timeouts.
diff --git a/src/compiler/codegen/mips/fp_mips.cc b/src/compiler/codegen/mips/fp_mips.cc
index e718c5c..6ffc5e0 100644
--- a/src/compiler/codegen/mips/fp_mips.cc
+++ b/src/compiler/codegen/mips/fp_mips.cc
@@ -49,6 +49,8 @@
     case Instruction::MUL_FLOAT:
       op = kMipsFmuls;
       break;
+    case Instruction::REM_FLOAT_2ADDR:
+    case Instruction::REM_FLOAT:
       FlushAllRegs(cu);   // Send everything to home location
       CallRuntimeHelperRegLocationRegLocation(cu, ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false);
       rl_result = GetReturn(cu, true);
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 7d73249..2dcfba5 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -730,8 +730,9 @@
   }
 }
 
-// Handler for invocation on proxy methods. We create a boxed argument array. And we invoke
-// the invocation handler which is a field within the proxy object receiver.
+// Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation
+// handler which is a field within the proxy object receiver. The var args encode the arguments
+// with the last argument being a pointer to a JValue to store the result in.
 void art_proxy_invoke_handler_from_code(AbstractMethod* proxy_method, ...)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   va_list ap;
@@ -740,141 +741,59 @@
   Object* receiver = va_arg(ap, Object*);
   Thread* self = va_arg(ap, Thread*);
   MethodHelper proxy_mh(proxy_method);
-  const size_t num_params = proxy_mh.NumArgs();
 
-  // Start new JNI local reference state
+  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
+  const char* old_cause =
+      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
+  self->VerifyStack();
+
+  // Start new JNI local reference state.
   JNIEnvExt* env = self->GetJniEnv();
   ScopedObjectAccessUnchecked soa(env);
   ScopedJniEnvLocalRefState env_state(env);
 
-  // Create local ref. copies of the receiver
+  // Create local ref. copies of the receiver.
   jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
 
-  // Convert proxy method into expected interface method
+  // Convert proxy method into expected interface method.
   AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
   DCHECK(interface_method != NULL);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
+  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
 
-  // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
-  jvalue args_jobj[3];
-  args_jobj[0].l = rcvr_jobj;
-  args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
-  // Args array, if no arguments then NULL (don't include receiver in argument count)
-  args_jobj[2].l = NULL;
-  ObjectArray<Object>* args = NULL;
-  if ((num_params - 1) > 0) {
-    args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
-    if (args == NULL) {
-      CHECK(self->IsExceptionPending());
-      return;
-    }
-    args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
-  }
-
-  // Get parameter types.
-  const char* shorty = proxy_mh.GetShorty();
-  ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
-  if (param_types == NULL) {
-    CHECK(self->IsExceptionPending());
-    return;
-  }
-
-  // Box arguments.
-  for (size_t i = 0; i < (num_params - 1);++i) {
-    JValue val;
-    switch (shorty[i+1]) {
-      case 'Z':
-        val.SetZ(va_arg(ap, jint));
+  // Record arguments and turn Object* arguments into jobject to survive GC.
+  std::vector<jvalue> args;
+  const size_t num_params = proxy_mh.NumArgs();
+  for (size_t i = 1; i < num_params; ++i) {
+    jvalue val;
+    switch (proxy_mh.GetParamPrimitiveType(i)) {
+      case Primitive::kPrimNot:
+        val.l = soa.AddLocalReference<jobject>(va_arg(ap, Object*));
         break;
-      case 'B':
-        val.SetB(va_arg(ap, jint));
+      case Primitive::kPrimBoolean:  // Fall-through.
+      case Primitive::kPrimByte:     // Fall-through.
+      case Primitive::kPrimChar:     // Fall-through.
+      case Primitive::kPrimShort:    // Fall-through.
+      case Primitive::kPrimInt:      // Fall-through.
+        val.i = va_arg(ap, jint);
         break;
-      case 'C':
-        val.SetC(va_arg(ap, jint));
-        break;
-      case 'S':
-        val.SetS(va_arg(ap, jint));
-        break;
-      case 'I':
-        val.SetI(va_arg(ap, jint));
-        break;
-      case 'F':
-        val.SetI(va_arg(ap, jint)); // TODO: is this right?
-        break;
-      case 'L':
-        val.SetL(va_arg(ap, Object*));
+      case Primitive::kPrimFloat:
+        val.f = va_arg(ap, jfloat);
         break;
       case 'D':
+        val.d(va_arg(ap, jdouble));
+        break;
       case 'J':
-        val.SetJ(va_arg(ap, jlong)); // TODO: is this right for double?
+        val.j(va_arg(ap, jlong));
         break;
     }
-    Class* param_type = param_types->Get(i);
-    if (param_type->IsPrimitive()) {
-      BoxPrimitive(param_type->GetPrimitiveType(), val);
-      if (self->IsExceptionPending()) {
-        return;
-      }
-    }
-    args->Set(i, val.GetL());
+    args.push_back(val);
   }
-
-  DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
-
-  jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
-  // Call InvocationHandler.invoke
-  jobject result = env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke, args_jobj);
-
-  // Place result in stack args
-  if (!self->IsExceptionPending()) {
-    if (shorty[0] == 'V') {
-      return;
-    }
-    Object* result_ref = self->DecodeJObject(result);
-    JValue* result_unboxed = va_arg(ap, JValue*);
-    if (result_ref == NULL) {
-      result_unboxed->SetL(NULL);
-    } else {
-      bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(), *result_unboxed);
-      if (!unboxed_okay) {
-        self->ClearException();
-        self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
-                                 "Couldn't convert result of type %s to %s",
-                                 PrettyTypeOf(result_ref).c_str(),
-                                 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
-        return;
-      }
-    }
-  } else {
-    // In the case of checked exceptions that aren't declared, the exception must be wrapped by
-    // a UndeclaredThrowableException.
-    Throwable* exception = self->GetException();
-    if (exception->IsCheckedException()) {
-      SynthesizedProxyClass* proxy_class =
-          down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
-      int throws_index = -1;
-      size_t num_virt_methods = proxy_class->NumVirtualMethods();
-      for (size_t i = 0; i < num_virt_methods; i++) {
-        if (proxy_class->GetVirtualMethod(i) == proxy_method) {
-          throws_index = i;
-          break;
-        }
-      }
-      CHECK_NE(throws_index, -1);
-      ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
-      Class* exception_class = exception->GetClass();
-      bool declares_exception = false;
-      for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
-        Class* declared_exception = declared_exceptions->Get(i);
-        declares_exception = declared_exception->IsAssignableFrom(exception_class);
-      }
-      if (!declares_exception) {
-        self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
-      }
-    }
-  }
-
+  self->EndAssertNoThreadSuspension(old_cause);
+  JValue* result_unboxed = va_arg(ap, JValue*);
   va_end(ap);
+  *result_unboxed = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+                                                 rcvr_jobj, interface_method_jobj, args);
 }
 
 void* art_find_runtime_support_func(void* context, const char* name) {
diff --git a/src/native/java_lang_reflect_Field.cc b/src/native/java_lang_reflect_Field.cc
index d99ccb3..fde8f94 100644
--- a/src/native/java_lang_reflect_Field.cc
+++ b/src/native/java_lang_reflect_Field.cc
@@ -101,9 +101,8 @@
   if (!GetFieldValue(soa, o, f, value, true)) {
     return NULL;
   }
-  BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value);
-
-  return soa.AddLocalReference<jobject>(value.GetL());
+  return
+      soa.AddLocalReference<jobject>(BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value));
 }
 
 static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char dst_descriptor) {
diff --git a/src/oat/runtime/argument_visitor.h b/src/oat/runtime/argument_visitor.h
new file mode 100644
index 0000000..06256ca
--- /dev/null
+++ b/src/oat/runtime/argument_visitor.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+#define ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
+
+#include "object_utils.h"
+
+namespace art {
+
+// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
+class ArgumentVisitor {
+ public:
+// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
+// Size of Runtime::kRefAndArgs callee save frame.
+// Size of Method* and register parameters in out stack arguments.
+#if defined(__arm__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__mips__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define STACK_ARG_SKIP 16
+#elif defined(__i386__)
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
+#define STACK_ARG_SKIP 16
+#else
+#error "Unsupported architecture"
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
+#define CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
+#define STACK_ARG_SKIP 0
+#endif
+
+  ArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+    caller_mh_(caller_mh),
+    args_in_regs_(ComputeArgsInRegs(caller_mh)),
+    num_params_(caller_mh.NumArgs()),
+    reg_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
+    stack_args_(reinterpret_cast<byte*>(sp) + CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+                + STACK_ARG_SKIP),
+    cur_args_(reg_args_),
+    cur_arg_index_(0),
+    param_index_(0),
+    is_split_long_or_double_(false) {
+  }
+
+  virtual ~ArgumentVisitor() {}
+
+  virtual void Visit() = 0;
+
+  bool IsParamAReference() const {
+    return caller_mh_.IsParamAReference(param_index_);
+  }
+
+  bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return caller_mh_.IsParamALongOrDouble(param_index_);
+  }
+
+  Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return caller_mh_.GetParamPrimitiveType(param_index_);
+  }
+
+  byte* GetParamAddress() const {
+    return cur_args_ + (cur_arg_index_ * kPointerSize);
+  }
+
+  bool IsSplitLongOrDouble() const {
+    return is_split_long_or_double_;
+  }
+
+  uint64_t ReadSplitLongParam() const {
+    DCHECK(IsSplitLongOrDouble());
+    uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
+    uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
+    return (low_half & 0xffffffffULL) | (high_half << 32);
+
+  }
+
+  void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    for (cur_arg_index_ = 0;  cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
+      is_split_long_or_double_ = (cur_arg_index_ == 2) && IsParamALongOrDouble();
+      Visit();
+      cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+      param_index_++;
+    }
+    cur_args_ = stack_args_;
+    cur_arg_index_ = is_split_long_or_double_ ? 1 : 0;
+    is_split_long_or_double_ = false;
+    while (param_index_ < num_params_) {
+      Visit();
+      cur_arg_index_ += (caller_mh_.IsParamALongOrDouble(param_index_) ? 2 : 1);
+      param_index_++;
+    }
+  }
+
+ private:
+  static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    size_t args_in_regs = 0;
+    size_t num_params = mh.NumArgs();
+    for (size_t i = 0; i < num_params; i++) {
+      args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
+      if (args_in_regs > 3) {
+        args_in_regs = 3;
+        break;
+      }
+    }
+    return args_in_regs;
+  }
+  MethodHelper& caller_mh_;
+  const size_t args_in_regs_;
+  const size_t num_params_;
+  byte* const reg_args_;
+  byte* const stack_args_;
+  byte* cur_args_;
+  size_t cur_arg_index_;
+  size_t param_index_;
+  // Does a 64bit parameter straddle the register and stack arguments?
+  bool is_split_long_or_double_;
+};
+
+}
+
+#endif  // ART_SRC_OAT_RUNTIME_ARGUMENT_VISITOR_H_
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 7901c5f..dda1222 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -754,18 +754,18 @@
     .extern artProxyInvokeHandler
     /*
      * Called by managed code that is attempting to call a method on a proxy class. On entry
-     * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
+     * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
+     * frame size of the invoked proxy method agrees with a ref and args callee save frame.
      */
     ALIGN_FUNCTION_ENTRY
 art_proxy_invoke_handler:
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     str     r0, [sp, #0]           @ place proxy method at bottom of frame
     mov     r2, r9                 @ pass Thread::Current
-    add     r3, sp, #12            @ pointer to r2/r3/LR/caller's Method**/out-args as second arg
-    blx     artProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, args...)
+    mov     r3, sp                 @ pass SP
+    blx     artProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
     ldr     r12, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
     ldr     lr,  [sp, #44]         @ restore lr
-    ldrd    r0,  [sp, #12]         @ load r0/r1 from r2/r3 that were overwritten with the out args
     add     sp,  #48               @ pop frame
     cmp     r12, #0                @ success if no exception is pending
     bxeq    lr                     @ return on success
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 4484cde..efd3ede 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -853,11 +853,9 @@
     sw      $a0, 0($sp)            # place proxy method at bottom of frame
     move    $a2, rSELF             # pass Thread::Current
     jal     artProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, args...)
-    addiu   $a3, $sp, 8            # pointer to a2/a3/ra/caller's Method**/out-args as second arg
+    move    $a3, $sp               # pass $sp
     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
     lw      $ra, 44($sp)           # restore $ra
-    lw      $v0, 8($sp)
-    lw      $v1, 12($sp)
     bnez    $t0, 1f
     addiu   $sp, $sp, 48           # pop frame
     jr      $ra
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 1fdab2a..5bf3cde 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "argument_visitor.h"
 #include "object.h"
 #include "object_utils.h"
 #include "reflection.h"
@@ -24,42 +25,69 @@
 
 #include "ScopedLocalRef.h"
 
-#if defined(__arm__)
-#define SP_OFFSET_IN_BYTES 12
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 11 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__mips__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 48u
-#define ARG2_OFFSET_IN_WORDS 12 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#elif defined(__i386__)
-#define SP_OFFSET_IN_BYTES 8
-#define FRAME_SIZE_IN_BYTES 32u
-#define ARG2_OFFSET_IN_WORDS 8 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
-#else
-#error "Unsupported architecture"
-#define SP_OFFSET_IN_BYTES 0
-#define FRAME_SIZE_IN_BYTES 0
-#define ARG2_OFFSET_IN_WORDS 0
-#endif
-
 namespace art {
 
+// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
+// to jobjects.
+class BuildArgumentVisitor : public ArgumentVisitor {
+ public:
+  BuildArgumentVisitor(MethodHelper& caller_mh, AbstractMethod** sp,
+                       ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
+    ArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
+
+  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    jvalue val;
+    Primitive::Type type = GetParamPrimitiveType();
+    switch (type) {
+      case Primitive::kPrimNot: {
+        Object* obj = *reinterpret_cast<Object**>(GetParamAddress());
+        val.l = soa_.AddLocalReference<jobject>(obj);
+        break;
+      }
+      case Primitive::kPrimLong:  // Fall-through.
+      case Primitive::kPrimDouble:
+        if (IsSplitLongOrDouble()) {
+          val.j = ReadSplitLongParam();
+        } else {
+          val.j = *reinterpret_cast<jlong*>(GetParamAddress());
+        }
+        break;
+      case Primitive::kPrimBoolean:
+      case Primitive::kPrimByte:
+      case Primitive::kPrimChar:
+      case Primitive::kPrimShort:
+      case Primitive::kPrimInt:
+      case Primitive::kPrimFloat:
+        val.i =  *reinterpret_cast<jint*>(GetParamAddress());
+        break;
+      case Primitive::kPrimVoid:
+        LOG(FATAL) << "UNREACHABLE";
+        val.j = 0;
+        break;
+    }
+    args_.push_back(val);
+  }
+
+ private:
+  ScopedObjectAccessUnchecked& soa_;
+  std::vector<jvalue>& args_;
+};
+
 // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly handlerize incoming
-// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
-// the invocation handler which is a field within the proxy object receiver.
-extern "C" void artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
-                                      Thread* self, byte* stack_args)
+// which is responsible for recording callee save registers. We explicitly place into jobjects the
+// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
+// field within the proxy object, which will box the primitive arguments and deal with error cases.
+extern "C" uint64_t artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
+                                          Thread* self, AbstractMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
   const char* old_cause =
       self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
   // Register the top of the managed stack, making stack crawlable.
-  AbstractMethod** proxy_sp = reinterpret_cast<AbstractMethod**>(stack_args - SP_OFFSET_IN_BYTES);
-  DCHECK_EQ(*proxy_sp, proxy_method);
-  self->SetTopOfStack(proxy_sp, 0);
-  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
+  DCHECK_EQ(*sp, proxy_method);
+  self->SetTopOfStack(sp, 0);
+  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(),
+            Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
   self->VerifyStack();
   // Start new JNI local reference state.
   JNIEnvExt* env = self->GetJniEnv();
@@ -67,173 +95,26 @@
   ScopedJniEnvLocalRefState env_state(env);
   // Create local ref. copies of proxy method and the receiver.
   jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
-  jobject proxy_method_jobj = soa.AddLocalReference<jobject>(proxy_method);
 
-  // Placing into local references incoming arguments from the caller's register arguments,
-  // replacing original Object* with jobject.
+  // Placing arguments into args vector and remove the receiver.
   MethodHelper proxy_mh(proxy_method);
-  const size_t num_params = proxy_mh.NumArgs();
-  size_t args_in_regs = 0;
-  for (size_t i = 1; i < num_params; i++) {  // skip receiver
-    args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
-    if (args_in_regs > 2) {
-      args_in_regs = 2;
-      break;
-    }
-  }
-  size_t cur_arg = 0;  // current stack location to read
-  size_t param_index = 1;  // skip receiver
-  while (cur_arg < args_in_regs && param_index < num_params) {
-    if (proxy_mh.IsParamAReference(param_index)) {
-      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = soa.AddLocalReference<jobject>(obj);
-      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
-    }
-    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
-    param_index++;
-  }
-  // Placing into local references incoming arguments from the caller's stack arguments.
-  cur_arg += ARG2_OFFSET_IN_WORDS;
-  while (param_index < num_params) {
-    if (proxy_mh.IsParamAReference(param_index)) {
-      Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = soa.AddLocalReference<jobject>(obj);
-      *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
-    }
-    cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
-    param_index++;
-  }
-  self->EndAssertNoThreadSuspension(old_cause);
-  // Sanity check writing the jobjects over the Object*s in place didn't damage the stack.
-  self->VerifyStack();
+  std::vector<jvalue> args;
+  BuildArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
+  local_ref_visitor.VisitArguments();
+  args.erase(args.begin());
 
-  // Set up arguments array and place in local IRT during boxing (which may allocate/GC).
-  jvalue args_jobj[3];
-  args_jobj[0].l = rcvr_jobj;
-  args_jobj[1].l = proxy_method_jobj;
-  // Args array, if no arguments then NULL (don't include receiver in argument count).
-  args_jobj[2].l = NULL;
-  ObjectArray<Object>* args = NULL;
-  if ((num_params - 1) > 0) {
-    args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
-    if (args == NULL) {
-      CHECK(self->IsExceptionPending());
-      return;
-    }
-    args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
-  }
   // Convert proxy method into expected interface method.
   AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
   DCHECK(interface_method != NULL);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
-  args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
-  // Box primitive type arguments.
-  cur_arg = 0;  // Stack location to read to start.
-  // Reset index, will index into param type array which doesn't include the receiver.
-  param_index = 0;
-  ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
-  if (param_types == NULL) {
-    CHECK(self->IsExceptionPending());
-    return;
-  }
-  // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
-  DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
-  while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
-    Class* param_type = param_types->Get(param_index);
-    Object* obj;
-    if (!param_type->IsPrimitive()) {
-      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
-    } else {
-      JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
-      if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
-        // long/double split over regs and stack, mask in high half from stack arguments.
-        uint64_t high_half =
-            *reinterpret_cast<uint32_t*>(stack_args + ((ARG2_OFFSET_IN_WORDS + 2) * kPointerSize));
-        val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
-      }
-      BoxPrimitive(param_type->GetPrimitiveType(), val);
-      if (self->IsExceptionPending()) {
-        return;
-      }
-      obj = val.GetL();
-    }
-    args->Set(param_index, obj);
-    cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
-    param_index++;
-  }
-  // Placing into local references incoming arguments from the caller's stack arguments.
-  cur_arg += ARG2_OFFSET_IN_WORDS;
-  while (param_index < (num_params - 1)) {
-    Class* param_type = param_types->Get(param_index);
-    Object* obj;
-    if (!param_type->IsPrimitive()) {
-      obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
-    } else {
-      JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
-      BoxPrimitive(param_type->GetPrimitiveType(), val);
-      if (self->IsExceptionPending()) {
-        return;
-      }
-      obj = val.GetL();
-    }
-    args->Set(param_index, obj);
-    cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
-    param_index++;
-  }
-  // Get the InvocationHandler method and the field that holds it within the Proxy object.
-  DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
-  jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
-  // Call InvocationHandler.invoke.
-  jobject result =
-      env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
-                             args_jobj);
-  // Place result in stack args.
-  if (!self->IsExceptionPending()) {
-    Object* result_ref = self->DecodeJObject(result);
-    if (result_ref != NULL) {
-      JValue result_unboxed;
-      bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(),
-                                                  result_unboxed);
-      if (!unboxed_okay) {
-        self->ClearException();
-        self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
-                                 "Couldn't convert result of type %s to %s",
-                                 PrettyTypeOf(result_ref).c_str(),
-                                 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
-        return;
-      }
-      *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
-    } else {
-      *reinterpret_cast<jobject*>(stack_args) = NULL;
-    }
-  } else {
-    // In the case of checked exceptions that aren't declared, the exception must be wrapped by
-    // a UndeclaredThrowableException.
-    Throwable* exception = self->GetException();
-    if (exception->IsCheckedException()) {
-      SynthesizedProxyClass* proxy_class =
-          down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
-      int throws_index = -1;
-      size_t num_virt_methods = proxy_class->NumVirtualMethods();
-      for (size_t i = 0; i < num_virt_methods; i++) {
-        if (proxy_class->GetVirtualMethod(i) == proxy_method) {
-          throws_index = i;
-          break;
-        }
-      }
-      CHECK_NE(throws_index, -1);
-      ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
-      Class* exception_class = exception->GetClass();
-      bool declares_exception = false;
-      for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
-        Class* declared_exception = declared_exceptions->Get(i);
-        declares_exception = declared_exception->IsAssignableFrom(exception_class);
-      }
-      if (!declares_exception) {
-        self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
-      }
-    }
-  }
+  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
+
+  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
+  // that performs allocations.
+  self->EndAssertNoThreadSuspension(old_cause);
+  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+                                               rcvr_jobj, interface_method_jobj, args);
+  return result.GetJ();
 }
 
 }  // namespace art
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 379fcce..f2f9fa4 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -738,15 +738,14 @@
 
 DEFINE_FUNCTION art_proxy_invoke_handler
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
-    lea 8(%esp), %ebx             // pointer to r2/r3/LR/caller's Method**/out-args as second arg
-    pushl %ebx                    // pass args
+    pushl %esp                    // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     pushl %ecx                    // pass receiver
     pushl %eax                    // pass proxy method
-    call SYMBOL(artProxyInvokeHandler)     // (proxy method, receiver, Thread*, args...)
-    mov 24(%esp), %eax            // get ret0 which was written into r2 on the stack
-    mov 28(%esp), %edx            // get ret1 which was written into r3 on the stack
-    movsd 24(%esp), %xmm0         // get ret0/ret1 from stack for floating point
+    call SYMBOL(artProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    movd %eax, %xmm0              // place return value also into floating point return value
+    movd %edx, %xmm1
+    punpckldq %xmm1, %xmm0
     addl LITERAL(44), %esp        // pop arguments
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
diff --git a/src/object_utils.h b/src/object_utils.h
index dd5ff05..068dd66 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -566,8 +566,7 @@
     return method_->GetDeclaringClass()->GetClassLoader();
   }
 
-  bool IsStatic()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool IsStatic() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return method_->IsStatic();
   }
 
@@ -581,28 +580,26 @@
     return (IsStatic() ? 0 : 1) + GetShortyLength() - 1;
   }
 
-  // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods
-  bool IsParamALongOrDouble(size_t param)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Get the primitive type associated with the given parameter.
+  Primitive::Type GetParamPrimitiveType(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK_LT(param, NumArgs());
     if (IsStatic()) {
       param++;  // 0th argument must skip return value at start of the shorty
     } else if (param == 0) {
-      return false;  // this argument
+      return Primitive::kPrimNot;
     }
-    char ch = GetShorty()[param];
-    return (ch == 'J' || ch == 'D');
+    return Primitive::GetType(GetShorty()[param]);
   }
 
-  // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods
+  // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods.
+  bool IsParamALongOrDouble(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    Primitive::Type type = GetParamPrimitiveType(param);
+    return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
+  }
+
+  // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods.
   bool IsParamAReference(size_t param) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_LT(param, NumArgs());
-    if (IsStatic()) {
-      param++;  // 0th argument must skip return value at start of the shorty
-    } else if (param == 0) {
-      return true;  // this argument
-    }
-    return GetShorty()[param] == 'L';  // An array also has a shorty character of 'L' (not '[')
+    return GetParamPrimitiveType(param) == Primitive::kPrimNot;
   }
 
   bool HasSameNameAndSignature(MethodHelper* other)
diff --git a/src/reflection.cc b/src/reflection.cc
index c793d2c..1ffad3f 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -90,8 +90,7 @@
   }
 
   // Box if necessary and return.
-  BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(), value);
-  return soa.AddLocalReference<jobject>(value.GetL());
+  return soa.AddLocalReference<jobject>(BoxPrimitive(mh.GetReturnType()->GetPrimitiveType(), value));
 }
 
 bool VerifyObjectInClass(Object* o, Class* c) {
@@ -195,9 +194,9 @@
   return false;
 }
 
-void BoxPrimitive(Primitive::Type src_class, JValue& value) {
+Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
   if (src_class == Primitive::kPrimNot) {
-    return;
+    return value.GetL();
   }
 
   jmethodID m = NULL;
@@ -228,8 +227,7 @@
     break;
   case Primitive::kPrimVoid:
     // There's no such thing as a void field, and void methods invoked via reflection return null.
-    value.SetL(NULL);
-    return;
+    return NULL;
   default:
     LOG(FATAL) << static_cast<int>(src_class);
   }
@@ -239,7 +237,9 @@
     CHECK_EQ(soa.Self()->GetState(), kRunnable);
   }
   JValue args[1] = { value };
-  soa.DecodeMethod(m)->Invoke(soa.Self(), NULL, args, &value);
+  JValue result;
+  soa.DecodeMethod(m)->Invoke(soa.Self(), NULL, args, &result);
+  return result.GetL();
 }
 
 static std::string UnboxingFailureKind(AbstractMethod* m, int index, Field* f)
diff --git a/src/reflection.h b/src/reflection.h
index b61acda..601543f 100644
--- a/src/reflection.h
+++ b/src/reflection.h
@@ -29,10 +29,10 @@
 class Object;
 class ScopedObjectAccess;
 
-void BoxPrimitive(Primitive::Type src_class, JValue& value)
+Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value, AbstractMethod* m,
-                               size_t index)
+bool UnboxPrimitiveForArgument(Object* o, Class* dst_class, JValue& unboxed_value,
+                               AbstractMethod* m, size_t index)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 bool UnboxPrimitiveForField(Object* o, Class* dst_class, JValue& unboxed_value, Field* f)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 856e877..b276917 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -16,6 +16,8 @@
 
 #include "runtime_support.h"
 
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
 #include "well_known_classes.h"
 
@@ -372,4 +374,103 @@
   self->ResetDefaultStackEnd();  // Return to default stack size.
 }
 
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+                                    jobject rcvr_jobj, jobject interface_method_jobj,
+                                    std::vector<jvalue>& args) {
+  DCHECK(soa.Env()->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
+
+  // Build argument array possibly triggering GC.
+  soa.Self()->AssertThreadSuspensionIsAllowable();
+  jobjectArray args_jobj = NULL;
+  const JValue zero;
+  if (args.size() > 0) {
+    args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, NULL);
+    if (args_jobj == NULL) {
+      CHECK(soa.Self()->IsExceptionPending());
+      return zero;
+    }
+    for (size_t i = 0; i < args.size(); ++i) {
+      if (shorty[i + 1] == 'L') {
+        jobject val = args.at(i).l;
+        soa.Env()->SetObjectArrayElement(args_jobj, i, val);
+      } else {
+        JValue jv;
+        jv.SetJ(args.at(i).j);
+        Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+        if (val == NULL) {
+          CHECK(soa.Self()->IsExceptionPending());
+          return zero;
+        }
+        soa.Decode<ObjectArray<Object>* >(args_jobj)->Set(i, val);
+      }
+    }
+  }
+
+  // Call InvocationHandler.invoke(Object proxy, Method method, Object[] args).
+  jobject inv_hand = soa.Env()->GetObjectField(rcvr_jobj,
+                                               WellKnownClasses::java_lang_reflect_Proxy_h);
+  jvalue invocation_args[3];
+  invocation_args[0].l = rcvr_jobj;
+  invocation_args[1].l = interface_method_jobj;
+  invocation_args[2].l = args_jobj;
+  jobject result =
+      soa.Env()->CallObjectMethodA(inv_hand,
+                                   WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
+                                   invocation_args);
+
+  // Unbox result and handle error conditions.
+  if (!soa.Self()->IsExceptionPending()) {
+    if (shorty[0] == 'V' || result == NULL) {
+      // Do nothing.
+      return zero;
+    } else {
+      JValue result_unboxed;
+      MethodHelper mh(soa.Decode<AbstractMethod*>(interface_method_jobj));
+      Class* result_type = mh.GetReturnType();
+      Object* result_ref = soa.Decode<Object*>(result);
+      bool unboxed_okay = UnboxPrimitiveForResult(result_ref, result_type, result_unboxed);
+      if (!unboxed_okay) {
+        soa.Self()->ThrowNewWrappedException("Ljava/lang/ClassCastException;",
+                                             StringPrintf("Couldn't convert result of type %s to %s",
+                                                          PrettyTypeOf(result_ref).c_str(),
+                                                          PrettyDescriptor(result_type).c_str()
+                                             ).c_str());
+      }
+      return result_unboxed;
+    }
+  } else {
+    // In the case of checked exceptions that aren't declared, the exception must be wrapped by
+    // a UndeclaredThrowableException.
+    Throwable* exception = soa.Self()->GetException();
+    if (exception->IsCheckedException()) {
+      Object* rcvr = soa.Decode<Object*>(rcvr_jobj);
+      SynthesizedProxyClass* proxy_class = down_cast<SynthesizedProxyClass*>(rcvr->GetClass());
+      AbstractMethod* interface_method = soa.Decode<AbstractMethod*>(interface_method_jobj);
+      AbstractMethod* proxy_method =
+          rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+      int throws_index = -1;
+      size_t num_virt_methods = proxy_class->NumVirtualMethods();
+      for (size_t i = 0; i < num_virt_methods; i++) {
+        if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+          throws_index = i;
+          break;
+        }
+      }
+      CHECK_NE(throws_index, -1);
+      ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+      Class* exception_class = exception->GetClass();
+      bool declares_exception = false;
+      for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+        Class* declared_exception = declared_exceptions->Get(i);
+        declares_exception = declared_exception->IsAssignableFrom(exception_class);
+      }
+      if (!declares_exception) {
+        soa.Self()->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;",
+                                             NULL);
+      }
+    }
+    return zero;
+  }
+}
+
 }  // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index adeedb7..1c8d174 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -28,6 +28,7 @@
 #include "thread.h"
 #include "verifier/method_verifier.h"
 
+extern "C" void art_interpreter_invoke_handler();
 extern "C" void art_proxy_invoke_handler();
 extern "C" void art_work_around_app_jni_bugs();
 
@@ -282,8 +283,7 @@
   }
 }
 
-static inline void CheckSuspend(Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   for (;;) {
     if (thread->ReadFlag(kCheckpointRequest)) {
       thread->RunCheckpointFunction();
@@ -296,6 +296,11 @@
   }
 }
 
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+                                    jobject rcvr_jobj, jobject interface_method_jobj,
+                                    std::vector<jvalue>& args)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ;
+
 }  // namespace art
 
 #endif  // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/verifier/method_verifier_test.cc b/src/verifier/method_verifier_test.cc
index 9c9c745..8d4c513 100644
--- a/src/verifier/method_verifier_test.cc
+++ b/src/verifier/method_verifier_test.cc
@@ -55,13 +55,5 @@
   VerifyDexFile(java_lang_dex_file_);
 }
 
-TEST_F(MethodVerifierTest, IntMath) {
-  ScopedObjectAccess soa(Thread::Current());
-  jobject class_loader = LoadDex("IntMath");
-  Class* klass = class_linker_->FindClass("LIntMath;", soa.Decode<ClassLoader*>(class_loader));
-  std::string error_msg;
-  ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg) == MethodVerifier::kNoFailure) << error_msg;
-}
-
 }  // namespace verifier
 }  // namespace art
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index caf42ee..9752c74 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -30,6 +30,7 @@
 jclass WellKnownClasses::java_lang_ClassNotFoundException;
 jclass WellKnownClasses::java_lang_Daemons;
 jclass WellKnownClasses::java_lang_Error;
+jclass WellKnownClasses::java_lang_Object;
 jclass WellKnownClasses::java_lang_reflect_InvocationHandler;
 jclass WellKnownClasses::java_lang_reflect_AbstractMethod;
 jclass WellKnownClasses::java_lang_reflect_Proxy;
@@ -123,6 +124,7 @@
   java_lang_ClassLoader = CacheClass(env, "java/lang/ClassLoader");
   java_lang_ClassNotFoundException = CacheClass(env, "java/lang/ClassNotFoundException");
   java_lang_Daemons = CacheClass(env, "java/lang/Daemons");
+  java_lang_Object = CacheClass(env, "java/lang/Object");
   java_lang_Error = CacheClass(env, "java/lang/Error");
   java_lang_reflect_InvocationHandler = CacheClass(env, "java/lang/reflect/InvocationHandler");
   java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index 3dbf8a1..10afca9 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -42,6 +42,7 @@
   static jclass java_lang_ClassNotFoundException;
   static jclass java_lang_Daemons;
   static jclass java_lang_Error;
+  static jclass java_lang_Object;
   static jclass java_lang_reflect_InvocationHandler;
   static jclass java_lang_reflect_AbstractMethod;
   static jclass java_lang_reflect_Proxy;
diff --git a/test/107-int-math2/expected.txt b/test/107-int-math2/expected.txt
new file mode 100644
index 0000000..b131cc2
--- /dev/null
+++ b/test/107-int-math2/expected.txt
@@ -0,0 +1,35 @@
+divideLongByBillion PASSED
+unopTest PASSED
+shiftTest1 PASSED
+shiftTest2 PASSED
+unsignedShiftTest PASSED
+convTest PASSED
+charSubTest PASSED
+intOperTest PASSED
+lit16Test PASSED
+lit8Test PASSED
+intShiftTest PASSED
+longOperTest PASSED
+longShiftTest PASSED
+switchTest PASSED
+testIntCompare PASSED
+testLongCompare PASSED
+testFloatCompare PASSED
+testDoubleCompare PASSED
+fibonacci PASSED
+throwAndCatch PASSED
+testClassCast PASSED
+testArrayStore PASSED
+testStackOverflow PASSED
+testArrayAllocation PASSED
+manyArgs PASSED
+virtualCall PASSED
+testGetPut PASSED
+staticFieldTest PASSED
+catchBlock(1000) PASSED
+catchBlock(7000) PASSED
+catchBlockNoThrow PASSED
+superTest PASSED
+constClassTest PASSED
+constStringTest PASSED
+instanceTest PASSED
diff --git a/test/107-int-math2/info.txt b/test/107-int-math2/info.txt
new file mode 100644
index 0000000..2b1c485
--- /dev/null
+++ b/test/107-int-math2/info.txt
@@ -0,0 +1,2 @@
+A forked and extended version of IntMath from 003-omnibus-opcodes.
+TODO: fold back into 003-omnibus-opcodes.
diff --git a/test/IntMath/IntMath.java b/test/107-int-math2/src/Main.java
similarity index 98%
rename from test/IntMath/IntMath.java
rename to test/107-int-math2/src/Main.java
index 65894a3..d737ff5 100644
--- a/test/IntMath/IntMath.java
+++ b/test/107-int-math2/src/Main.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-class IntMath extends IntMathBase {
+class Main extends IntMathBase {
 
     public static boolean mBoolean1, mBoolean2;
     public static byte mByte1, mByte2;
@@ -29,12 +29,12 @@
 
     private int foo_;
 
-    public IntMath(int stuff) {
+    public Main(int stuff) {
         super();
         foo_ = stuff;
     }
 
-    public IntMath() {
+    public Main() {
         super();
         foo_ = 123;
     }
@@ -66,7 +66,7 @@
 
     static int instanceTest(int x) {
         IntMathBase a = new IntMathBase();
-        IntMath b = new IntMath();
+        Main b = new Main();
 
         if (!(null instanceof IntMathBase)) {
             x = x + 42;
@@ -76,7 +76,7 @@
             x = x * 2;
         }
 
-        if (a instanceof IntMath) {
+        if (a instanceof Main) {
             x = x + 13;
         }
 
@@ -84,7 +84,7 @@
             x = x -1;
         }
 
-        if (b instanceof IntMath) {
+        if (b instanceof Main) {
             x = x + 1333;
         }
         return x;
@@ -96,8 +96,8 @@
     }
 
     static int superTest(int x) {
-        IntMath instance = new IntMath();
-        IntMath base = instance;
+        Main instance = new Main();
+        Main base = instance;
         int val1 = instance.tryThing();
         int val2 = base.tryThing();
         return val1 + val2 + x;
@@ -770,14 +770,14 @@
 
     static int staticCall(int a)
     {
-        IntMath foo = new IntMath();
+        Main foo = new Main();
         return foo.virtualCall(a);
     }
 
     static int testIGetPut(int a)
     {
-        IntMath foo = new IntMath(99);
-        IntMath foo123 = new IntMath();
+        Main foo = new Main(99);
+        Main foo123 = new Main();
         int z  = foo.getFoo();
         z += a;
         z += foo123.getFoo();