interpreter: support for non-exact invokes.

Performs primitive argument conversions as well as boxing and unboxing
operations. Support for return value conversions will be added in a
follow up change.

Test: make test-art-host

Change-Id: I2e3348ff64a5826e477f87c12a7d5c390eb3a653
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 7fa8cf9..6140e79 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -28,6 +28,7 @@
 #include "dex_instruction-inl.h"
 #include "invoke_type.h"
 #include "mirror/class-inl.h"
+#include "mirror/method_type.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "thread.h"
@@ -791,4 +792,17 @@
   va_end(args);
 }
 
+// WrongMethodTypeException
+
+void ThrowWrongMethodTypeException(mirror::MethodType* callee_type,
+                                   mirror::MethodType* callsite_type) {
+  // TODO(narayan): Should we provide more detail here ? The RI doesn't bother.
+  UNUSED(callee_type);
+  UNUSED(callsite_type);
+
+  ThrowException("Ljava/lang/invoke/WrongMethodTypeException;",
+                 nullptr,
+                 "Invalid method type for signature polymorphic call");
+}
+
 }  // namespace art
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 945dc2d..ee36fb7 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -24,6 +24,7 @@
 namespace mirror {
   class Class;
   class Object;
+  class MethodType;
 }  // namespace mirror
 class ArtField;
 class ArtMethod;
@@ -219,6 +220,11 @@
     __attribute__((__format__(__printf__, 2, 3)))
     REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
 
+// WrontMethodTypeException
+void ThrowWrongMethodTypeException(mirror::MethodType* callee_type,
+                                   mirror::MethodType* callsite_type)
+    REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_COMMON_THROWS_H_
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index db7ebb4..191ffcc 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -24,6 +24,7 @@
 #include "jit/jit.h"
 #include "jvalue.h"
 #include "method_handles.h"
+#include "method_handles-inl.h"
 #include "mirror/array-inl.h"
 #include "mirror/class.h"
 #include "mirror/method_handle_impl.h"
@@ -474,24 +475,6 @@
   UNREACHABLE();
 }
 
-// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
-static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
-                                  size_t dest_reg, size_t src_reg)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  // Uint required, so that sign extension does not make this wrong on 64b systems
-  uint32_t src_value = shadow_frame.GetVReg(src_reg);
-  mirror::Object* o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
-
-  // If both register locations contains the same value, the register probably holds a reference.
-  // Note: As an optimization, non-moving collectors leave a stale reference value
-  // in the references array even after the original vreg was overwritten to a non-reference.
-  if (src_value == reinterpret_cast<uintptr_t>(o)) {
-    new_shadow_frame->SetVRegReference(dest_reg, o);
-  } else {
-    new_shadow_frame->SetVReg(dest_reg, src_value);
-  }
-}
-
 void AbortTransactionF(Thread* self, const char* fmt, ...) {
   va_list args;
   va_start(args, fmt);
@@ -519,6 +502,17 @@
                                 uint32_t (&arg)[Instruction::kMaxVarArgRegs],
                                 uint32_t vregC) ALWAYS_INLINE;
 
+// Separate declaration is required solely for the attributes.
+template <bool is_range> REQUIRES_SHARED(Locks::mutator_lock_)
+static inline bool DoCallPolymorphic(ArtMethod* called_method,
+                                     Handle<mirror::MethodType> callsite_type,
+                                     Handle<mirror::MethodType> target_type,
+                                     Thread* self,
+                                     ShadowFrame& shadow_frame,
+                                     JValue* result,
+                                     uint32_t (&arg)[Instruction::kMaxVarArgRegs],
+                                     uint32_t vregC) ALWAYS_INLINE;
+
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                         ArtMethod* caller,
                                         const DexFile::CodeItem* code_item,
@@ -597,9 +591,10 @@
   // signature polymorphic method so that we disallow calls via invoke-polymorphic
   // to non sig-poly methods. This would also have the side effect of verifying
   // that vRegC really is a reference type.
-  mirror::MethodHandleImpl* const method_handle =
-      reinterpret_cast<mirror::MethodHandleImpl*>(shadow_frame.GetVRegReference(vRegC));
-  if (UNLIKELY(method_handle == nullptr)) {
+  StackHandleScope<6> hs(self);
+  Handle<mirror::MethodHandleImpl> method_handle(hs.NewHandle(
+      reinterpret_cast<mirror::MethodHandleImpl*>(shadow_frame.GetVRegReference(vRegC))));
+  if (UNLIKELY(method_handle.Get() == nullptr)) {
     const int method_idx = (is_range) ? inst->VRegB_4rcc() : inst->VRegB_45cc();
     // Note that the invoke type is kVirtual here because a call to a signature
     // polymorphic method is shaped like a virtual call at the bytecode level.
@@ -616,32 +611,29 @@
   // Call through to the classlinker and ask it to resolve the static type associated
   // with the callsite. This information is stored in the dex cache so it's
   // guaranteed to be fast after the first resolution.
-  StackHandleScope<2> hs(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  mirror::Class* caller_class = shadow_frame.GetMethod()->GetDeclaringClass();
-  mirror::MethodType* callsite_type = class_linker->ResolveMethodType(
+  Handle<mirror::Class> caller_class(hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass()));
+  Handle<mirror::MethodType> callsite_type(hs.NewHandle(class_linker->ResolveMethodType(
       caller_class->GetDexFile(), callsite_proto_id,
       hs.NewHandle<mirror::DexCache>(caller_class->GetDexCache()),
-      hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader()));
+      hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader()))));
 
   // This implies we couldn't resolve one or more types in this method handle.
-  if (UNLIKELY(callsite_type == nullptr)) {
+  if (UNLIKELY(callsite_type.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
     return false;
   }
 
-  const char* old_cause = self->StartAssertNoThreadSuspension("DoInvokePolymorphic");
-
   // Get the method we're actually invoking along with the kind of
   // invoke that is desired. We don't need to perform access checks at this
   // point because they would have been performed on our behalf at the point
   // of creation of the method handle.
   ArtMethod* called_method = method_handle->GetTargetMethod();
   const MethodHandleKind handle_kind = method_handle->GetHandleKind();
-  mirror::MethodType* const handle_type = method_handle->GetMethodType();
+  Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
   CHECK(called_method != nullptr);
-  CHECK(handle_type != nullptr);
+  CHECK(handle_type.Get() != nullptr);
 
   // We now have to massage the number of inputs to the target function.
   // It's always one less than the number of inputs to the signature polymorphic
@@ -672,14 +664,12 @@
       called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
           called_method, kRuntimePointerSize);
       if (!VerifyObjectIsClass(receiver, declaring_class)) {
-        self->EndAssertNoThreadSuspension(old_cause);
         return false;
       }
     } else if (handle_kind == kInvokeDirect) {
       // TODO(narayan) : We need to handle the case where the target method is a
       // constructor here. Also the case where we don't want to dynamically
       // dispatch based on the type of the receiver.
-      self->EndAssertNoThreadSuspension(old_cause);
       UNIMPLEMENTED(FATAL) << "Direct invokes are not implemented yet.";
       return false;
     }
@@ -687,24 +677,123 @@
     // NOTE: handle_kind == kInvokeStatic needs no special treatment here. We
     // can directly make the call. handle_kind == kInvokeSuper doesn't have any
     // particular use and can probably be dropped.
-    if (callsite_type->IsExactMatch(handle_type)) {
-      self->EndAssertNoThreadSuspension(old_cause);
+
+    if (callsite_type->IsExactMatch(handle_type.Get())) {
       return DoCallCommon<is_range, do_access_check>(
           called_method, self, shadow_frame, result, number_of_inputs,
           arg, receiver_vregC);
+    } else {
+      return DoCallPolymorphic<is_range>(
+          called_method, callsite_type, handle_type, self, shadow_frame,
+          result, arg, receiver_vregC);
     }
-
-    self->EndAssertNoThreadSuspension(old_cause);
-    UNIMPLEMENTED(FATAL) << "Non exact invokes are not implemented yet.";
-    return false;
   } else {
     // TODO(narayan): Implement field getters and setters.
-    self->EndAssertNoThreadSuspension(old_cause);
     UNIMPLEMENTED(FATAL) << "Field references in method handles are not implemented yet.";
     return false;
   }
 }
 
+// Calculate the number of ins for a proxy or native method, where we
+// can't just look at the code item.
+static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(method->IsNative() || method->IsProxyMethod());
+
+  method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+  size_t num_ins = 0;
+  // Separate accounting for the receiver, which isn't a part of the
+  // shorty.
+  if (!method->IsStatic()) {
+    ++num_ins;
+  }
+
+  uint32_t shorty_len = 0;
+  const char* shorty = method->GetShorty(&shorty_len);
+  for (size_t i = 1; i < shorty_len; ++i) {
+    const char c = shorty[i];
+    ++num_ins;
+    if (c == 'J' || c == 'D') {
+      ++num_ins;
+    }
+  }
+
+  return num_ins;
+}
+
+template <bool is_range>
+static inline bool DoCallPolymorphic(ArtMethod* called_method,
+                                     Handle<mirror::MethodType> callsite_type,
+                                     Handle<mirror::MethodType> target_type,
+                                     Thread* self,
+                                     ShadowFrame& shadow_frame,
+                                     JValue* result,
+                                     uint32_t (&arg)[Instruction::kMaxVarArgRegs],
+                                     uint32_t vregC) {
+  // TODO(narayan): Wire in the String.init hacks.
+
+  // Compute method information.
+  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+
+  // Number of registers for the callee's call frame. Note that for non-exact
+  // invokes, we always derive this information from the callee method. We
+  // cannot guarantee during verification that the number of registers encoded
+  // in the invoke is equal to the number of ins for the callee. This is because
+  // some transformations (such as boxing a long -> Long or wideining an
+  // int -> long will change that number.
+  uint16_t num_regs;
+  size_t first_dest_reg;
+  if (LIKELY(code_item != nullptr)) {
+    num_regs = code_item->registers_size_;
+    first_dest_reg = num_regs - code_item->ins_size_;
+    // Parameter registers go at the end of the shadow frame.
+    DCHECK_NE(first_dest_reg, (size_t)-1);
+  } else {
+    // No local regs for proxy and native methods.
+    DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
+    num_regs = GetInsForProxyOrNativeMethod(called_method);
+    first_dest_reg = 0;
+  }
+
+  // Allocate shadow frame on the stack.
+  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
+      CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
+  ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
+
+  // Thread might be suspended during PerformArgumentConversions due to the
+  // allocations performed during boxing.
+  {
+    ScopedStackedShadowFramePusher pusher(
+        self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
+    if (!PerformArgumentConversions<is_range>(self, callsite_type, target_type,
+                                              shadow_frame, vregC, first_dest_reg,
+                                              arg, new_shadow_frame, result)) {
+      DCHECK(self->IsExceptionPending());
+      result->SetL(0);
+      return false;
+    }
+  }
+
+  // Do the call now.
+  if (LIKELY(Runtime::Current()->IsStarted())) {
+    ArtMethod* target = new_shadow_frame->GetMethod();
+    if (ClassLinker::ShouldUseInterpreterEntrypoint(
+        target,
+        target->GetEntryPointFromQuickCompiledCode())) {
+      ArtInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
+    } else {
+      ArtInterpreterToCompiledCodeBridge(
+          self, shadow_frame.GetMethod(), code_item, new_shadow_frame, result);
+    }
+  } else {
+    UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
+  }
+
+  // TODO(narayan): Perform return value conversions.
+
+  return !self->IsExceptionPending();
+}
+
 template <bool is_range,
           bool do_assignability_check>
 static inline bool DoCallCommon(ArtMethod* called_method,
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 7d54d0a..bdb6bd3 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -463,6 +463,24 @@
   return branch_offset <= 0;
 }
 
+// Assign register 'src_reg' from shadow_frame to register 'dest_reg' into new_shadow_frame.
+static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
+                                  size_t dest_reg, size_t src_reg)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // Uint required, so that sign extension does not make this wrong on 64b systems
+  uint32_t src_value = shadow_frame.GetVReg(src_reg);
+  mirror::Object* o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
+
+  // If both register locations contains the same value, the register probably holds a reference.
+  // Note: As an optimization, non-moving collectors leave a stale reference value
+  // in the references array even after the original vreg was overwritten to a non-reference.
+  if (src_value == reinterpret_cast<uintptr_t>(o)) {
+    new_shadow_frame->SetVRegReference(dest_reg, o);
+  } else {
+    new_shadow_frame->SetVReg(dest_reg, src_value);
+  }
+}
+
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                         ArtMethod* caller,
                                         const DexFile::CodeItem* code_item,
diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h
new file mode 100644
index 0000000..5f9824c
--- /dev/null
+++ b/runtime/method_handles-inl.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2016 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_RUNTIME_METHOD_HANDLES_INL_H_
+#define ART_RUNTIME_METHOD_HANDLES_INL_H_
+
+#include "method_handles.h"
+
+#include "common_throws.h"
+#include "dex_instruction.h"
+#include "interpreter/interpreter_common.h"
+#include "jvalue.h"
+#include "mirror/class.h"
+#include "mirror/method_type.h"
+#include "mirror/object.h"
+#include "reflection.h"
+#include "stack.h"
+
+namespace art {
+
+// Assigns |type| to the primitive type associated with |dst_class|. Returns
+// true iff. |dst_class| was a boxed type (Integer, Long etc.), false otherwise.
+REQUIRES_SHARED(Locks::mutator_lock_)
+static inline bool GetPrimitiveType(ObjPtr<mirror::Class> dst_class, Primitive::Type* type) {
+  if (dst_class->DescriptorEquals("Ljava/lang/Boolean;")) {
+    (*type) = Primitive::kPrimBoolean;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Byte;")) {
+    (*type) = Primitive::kPrimByte;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Character;")) {
+    (*type) = Primitive::kPrimChar;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Float;")) {
+    (*type) = Primitive::kPrimFloat;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Double;")) {
+    (*type) = Primitive::kPrimDouble;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Integer;")) {
+    (*type) = Primitive::kPrimInt;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Long;")) {
+    (*type) = Primitive::kPrimLong;
+    return true;
+  } else if (dst_class->DescriptorEquals("Ljava/lang/Short;")) {
+    (*type) = Primitive::kPrimShort;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// A convenience class that allows for iteration through a list of
+// input argument registers |arg| for non-range invokes or a list of
+// consecutive registers starting with a given based for range
+// invokes.
+template <bool is_range> class ArgIterator {
+ public:
+  ArgIterator(size_t first_src_reg,
+              const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) :
+      first_src_reg_(first_src_reg),
+      arg_(arg),
+      arg_index_(0) {
+  }
+
+  uint32_t Next() {
+    const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
+    ++arg_index_;
+
+    return next;
+  }
+
+  uint32_t NextPair() {
+    const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
+    arg_index_ += 2;
+
+    return next;
+  }
+
+ private:
+  const size_t first_src_reg_;
+  const uint32_t (&arg_)[Instruction::kMaxVarArgRegs];
+  size_t arg_index_;
+};
+
+template <bool is_range>
+bool PerformArgumentConversions(Thread* self,
+                                Handle<mirror::MethodType> callsite_type,
+                                Handle<mirror::MethodType> callee_type,
+                                const ShadowFrame& caller_frame,
+                                uint32_t first_src_reg,
+                                uint32_t first_dest_reg,
+                                const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
+                                ShadowFrame* callee_frame,
+                                JValue* result) {
+  StackHandleScope<4> hs(self);
+  Handle<mirror::ObjectArray<mirror::Class>> from_types(hs.NewHandle(callsite_type->GetPTypes()));
+  Handle<mirror::ObjectArray<mirror::Class>> to_types(hs.NewHandle(callee_type->GetPTypes()));
+
+  const int32_t num_method_params = from_types->GetLength();
+  if (to_types->GetLength() != num_method_params) {
+    ThrowWrongMethodTypeException(callee_type.Get(), callsite_type.Get());
+    result->SetJ(0);
+    return false;
+  }
+
+  ArgIterator<is_range> input_args(first_src_reg, arg);
+  size_t to_arg_index = 0;
+  MutableHandle<mirror::Class> from(hs.NewHandle<mirror::Class>(nullptr));
+  MutableHandle<mirror::Class> to(hs.NewHandle<mirror::Class>(nullptr));
+  for (int32_t i = 0; i < num_method_params; ++i) {
+    from.Assign(from_types->GetWithoutChecks(i));
+    to.Assign(to_types->GetWithoutChecks(i));
+
+    const Primitive::Type from_type = from->GetPrimitiveType();
+    const Primitive::Type to_type = to->GetPrimitiveType();
+
+    // Easy case - the types are identical. Nothing left to do except to pass
+    // the arguments along verbatim.
+    if (from.Get() == to.Get()) {
+      interpreter::AssignRegister(callee_frame,
+                                  caller_frame,
+                                  first_dest_reg + to_arg_index,
+                                  input_args.Next());
+      ++to_arg_index;
+
+      // This is a wide argument, we must use the second half of the register
+      // pair as well.
+      if (Primitive::Is64BitType(from_type)) {
+        interpreter::AssignRegister(callee_frame,
+                                    caller_frame,
+                                    first_dest_reg + to_arg_index,
+                                    input_args.Next());
+        ++to_arg_index;
+      }
+
+      continue;
+    } else if ((from_type != Primitive::kPrimNot) && (to_type != Primitive::kPrimNot)) {
+      // They are both primitive types - we should perform any widening or
+      // narrowing conversions as applicable.
+      JValue from_value;
+      JValue to_value;
+
+      if (Primitive::Is64BitType(from_type)) {
+        from_value.SetJ(caller_frame.GetVRegLong(input_args.NextPair()));
+      } else {
+        from_value.SetI(caller_frame.GetVReg(input_args.Next()));
+      }
+
+      // Throws a ClassCastException if we're unable to convert a primitive value.
+      if (!ConvertPrimitiveValue(false, from_type, to_type, from_value, &to_value)) {
+        DCHECK(self->IsExceptionPending());
+        result->SetL(0);
+        return false;
+      }
+
+      if (Primitive::Is64BitType(to_type)) {
+        callee_frame->SetVRegLong(first_dest_reg + to_arg_index, to_value.GetJ());
+        to_arg_index += 2;
+      } else {
+        callee_frame->SetVReg(first_dest_reg + to_arg_index, to_value.GetI());
+        ++to_arg_index;
+      }
+    } else if ((from_type == Primitive::kPrimNot) && (to_type == Primitive::kPrimNot)) {
+      // They're both reference types. If "from" is null, we can pass it
+      // through unchanged. If not, we must generate a cast exception if
+      // |to| is not assignable from the dynamic type of |ref|.
+      const size_t next_arg_reg = input_args.Next();
+      mirror::Object* const ref = caller_frame.GetVRegReference(next_arg_reg);
+      if (ref == nullptr || to->IsAssignableFrom(ref->GetClass())) {
+        interpreter::AssignRegister(callee_frame,
+                                    caller_frame,
+                                    first_dest_reg + to_arg_index,
+                                    next_arg_reg);
+        ++to_arg_index;
+      } else {
+        ThrowClassCastException(to.Get(), ref->GetClass());
+        result->SetL(0);
+        return false;
+      }
+    } else {
+      // Precisely one of the source or the destination are reference types.
+      // We must box or unbox.
+      if (to_type == Primitive::kPrimNot) {
+        // The target type is a reference, we must box.
+        Primitive::Type type;
+        // TODO(narayan): This is a CHECK for now. There might be a few corner cases
+        // here that we might not have handled yet. For exmple, if |to| is java/lang/Number;,
+        // we will need to box this "naturally".
+        CHECK(GetPrimitiveType(to.Get(), &type));
+
+        JValue from_value;
+        JValue to_value;
+
+        if (Primitive::Is64BitType(from_type)) {
+          from_value.SetJ(caller_frame.GetVRegLong(input_args.NextPair()));
+        } else {
+          from_value.SetI(caller_frame.GetVReg(input_args.Next()));
+        }
+
+        // First perform a primitive conversion to the unboxed equivalent of the target,
+        // if necessary. This should be for the rarer cases like (int->Long) etc.
+        if (UNLIKELY(from_type != type)) {
+          if (!ConvertPrimitiveValue(false, from_type, type, from_value, &to_value)) {
+            DCHECK(self->IsExceptionPending());
+            result->SetL(0);
+            return false;
+          }
+        } else {
+          to_value = from_value;
+        }
+
+        // Then perform the actual boxing, and then set the reference.
+        ObjPtr<mirror::Object> boxed = BoxPrimitive(type, to_value);
+        callee_frame->SetVRegReference(first_dest_reg + to_arg_index, boxed.Ptr());
+        ++to_arg_index;
+      } else {
+        // The target type is a primitive, we must unbox.
+        ObjPtr<mirror::Object> ref(caller_frame.GetVRegReference(input_args.Next()));
+
+        // Note that UnboxPrimitiveForResult already performs all of the type
+        // conversions that we want, based on |to|.
+        JValue unboxed_value;
+        if (!UnboxPrimitiveForResult(ref, to.Get(), &unboxed_value)) {
+          DCHECK(self->IsExceptionPending());
+          result->SetL(0);
+          return false;
+        }
+
+        if (Primitive::Is64BitType(to_type)) {
+          callee_frame->SetVRegLong(first_dest_reg + to_arg_index, unboxed_value.GetJ());
+          to_arg_index += 2;
+        } else {
+          callee_frame->SetVReg(first_dest_reg + to_arg_index, unboxed_value.GetI());
+          ++to_arg_index;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_METHOD_HANDLES_INL_H_
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 5c68a8f..a36b66d 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -19,8 +19,17 @@
 
 #include <ostream>
 
+#include "dex_instruction.h"
+#include "jvalue.h"
+
 namespace art {
 
+namespace mirror {
+  class MethodType;
+}
+
+class ShadowFrame;
+
 // Defines the behaviour of a given method handle. The behaviour
 // of a handle of a given kind is identical to the dex bytecode behaviour
 // of the equivalent instruction.
@@ -46,6 +55,22 @@
   return handle_kind <= kLastInvokeKind;
 }
 
+// Perform argument conversions between |callsite_type| (the type of the
+// incoming arguments) and |callee_type| (the type of the method being
+// invoked). These include widening and narrowing conversions as well as
+// boxing and unboxing. Returns true on success, on false on failure. A
+// pending exception will always be set on failure.
+template <bool is_range> REQUIRES_SHARED(Locks::mutator_lock_)
+bool PerformArgumentConversions(Thread* self,
+                                Handle<mirror::MethodType> callsite_type,
+                                Handle<mirror::MethodType> callee_type,
+                                const ShadowFrame& caller_frame,
+                                uint32_t first_src_reg,
+                                uint32_t first_dest_reg,
+                                const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
+                                ShadowFrame* callee_frame,
+                                JValue* result);
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_METHOD_HANDLES_H_
diff --git a/test/955-methodhandles-smali/expected.txt b/test/955-methodhandles-smali/expected.txt
index 07d2422..047a287 100644
--- a/test/955-methodhandles-smali/expected.txt
+++ b/test/955-methodhandles-smali/expected.txt
@@ -1,2 +1,8 @@
 [String1]+[String2]
 [String1]
+[String1]+[String2]
+42
+40
+43
+44
+0-11
diff --git a/test/955-methodhandles-smali/smali/Main.smali b/test/955-methodhandles-smali/smali/Main.smali
index 2fc92f8..9681d56 100644
--- a/test/955-methodhandles-smali/smali/Main.smali
+++ b/test/955-methodhandles-smali/smali/Main.smali
@@ -66,8 +66,31 @@
     return-object v0
 .end method
 
-# Returns a method handle to static String java.lang.String.valueOf(String);
-.method public static getStringValueOfHandle()Ljava/lang/invoke/MethodHandle;
+# Returns a method handle to boolean java.lang.Long.compareTo(java.lang.Long other).
+.method public static getLongCompareToHandle()Ljava/lang/invoke/MethodHandle;
+.registers 4
+    new-instance v0, Ljava/lang/Long;
+    const-wide v1, 0
+    invoke-direct {v0, v1, v2}, Ljava/lang/Long;-><init>(J)V
+    invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+    move-result-object v0
+
+    # set v0 to Integer.TYPE aka. int.class
+    sget-object v1, Ljava/lang/Integer;->TYPE:Ljava/lang/Class;
+
+    # Call MethodType.methodType(rtype=int.class, ptype[0] = Long.class)
+    invoke-static {v1, v0}, Ljava/lang/invoke/MethodType;->methodType(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
+    move-result-object v2
+
+    const-string v3, "compareTo"
+    # Call Main.getHandleForVirtual(Long.class, "compareTo", methodType);
+    invoke-static {v0, v3, v2}, LMain;->getHandleForVirtual(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+    move-result-object v0
+    return-object v0
+.end method
+
+# Returns a method handle to static String java.lang.String.valueOf(Object);
+.method public static getStringValueOfObjectHandle()Ljava/lang/invoke/MethodHandle;
 .registers 4
     # set v0 to java.lang.Object.class
     new-instance v0, Ljava/lang/Object;
@@ -90,6 +113,26 @@
     return-object v0
 .end method
 
+# Returns a method handle to static String java.lang.String.valueOf(String);
+.method public static getStringValueOfLongHandle()Ljava/lang/invoke/MethodHandle;
+.registers 4
+    # set v0 to Long.TYPE aka. long.class
+    sget-object v0, Ljava/lang/Long;->TYPE:Ljava/lang/Class;
+
+    # set v1 to the name of the method ("valueOf") and v2 to java.lang.String.class;
+    const-string v1, "valueOf"
+    invoke-virtual {v1}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+    move-result-object v2
+
+    # Call MethodType.methodType(rtype=String.class, ptype[0]=Long.class)
+    invoke-static {v2, v0}, Ljava/lang/invoke/MethodType;->methodType(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
+    move-result-object v3
+
+    # Call Main.getHandleForStatic(String.class, "valueOf", methodType);
+    invoke-static {v2, v1, v3}, LMain;->getHandleForStatic(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
+    move-result-object v0
+    return-object v0
+.end method
 
 .method public static main([Ljava/lang/String;)V
 .registers 5
@@ -105,7 +148,7 @@
     invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
 
     # Test case 2: Exercise String.valueOf(Object);
-    invoke-static {}, LMain;->getStringValueOfHandle()Ljava/lang/invoke/MethodHandle;
+    invoke-static {}, LMain;->getStringValueOfObjectHandle()Ljava/lang/invoke/MethodHandle;
     move-result-object v0
     const-string v1, "[String1]"
     invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Object;)Ljava/lang/String;
@@ -113,5 +156,88 @@
     sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
     invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
 
+    # Test case 3: Exercise String.concat(String, String) with an inexact invoke.
+    # Note that the callsite type here is String type(Object, Object); so the runtime
+    # will generate dynamic type checks for the input arguments.
+    invoke-static {}, LMain;->getStringConcatHandle()Ljava/lang/invoke/MethodHandle;
+    move-result-object v0
+    const-string v1, "[String1]"
+    const-string v2, "+[String2]"
+    invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/String;
+    move-result-object v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    # Test case 4: Exercise String.valueOf(long);
+    #
+    # We exercise it with various types of unboxing / widening conversions
+    invoke-static {}, LMain;->getStringValueOfLongHandle()Ljava/lang/invoke/MethodHandle;
+    move-result-object v0
+
+    # First use a long, this is an invokeExact because the callsite type matches
+    # the function type precisely.
+    const-wide v1, 42
+    invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, (J)Ljava/lang/String;
+    move-result-object v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    # Then use an int, should perform a widening conversion.
+    const v1, 40
+    invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (I)Ljava/lang/String;
+    move-result-object v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    # Then use a java/lang/Long; - should perform an unboxing conversion.
+    new-instance v1, Ljava/lang/Long;
+    const-wide v2, 43
+    invoke-direct {v1, v2, v3}, Ljava/lang/Long;-><init>(J)V
+    invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Long;)Ljava/lang/String;
+    move-result-object v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    # Then use a java/lang/Integer; - should perform an unboxing in addition to a widening conversion.
+    new-instance v1, Ljava/lang/Integer;
+    const v2, 44
+    invoke-direct {v1, v2}, Ljava/lang/Integer;-><init>(I)V
+    invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Integer;)Ljava/lang/String;
+    move-result-object v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    # Test case 5: Exercise int Long.compareTo(Long)
+    invoke-static {}, LMain;->getLongCompareToHandle()Ljava/lang/invoke/MethodHandle;
+    move-result-object v0
+    new-instance v1, Ljava/lang/Long;
+    const-wide v2, 43
+    invoke-direct {v1, v2, v3}, Ljava/lang/Long;-><init>(J)V
+
+    # At this point, v0 is our MethodHandle and v1 is the instance we're going to call compareTo on.
+
+    # Call compareTo(Long) - this is invokeExact semantics.
+    invoke-polymorphic {v0, v1, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Long;Ljava/lang/Long;)I
+    move-result v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->print(I)V
+
+    # Call compareTo(long) - this is an implicit box.
+    const-wide v2, 44
+    invoke-polymorphic {v0, v1, v2, v3}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Long;J)I
+    move-result v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->print(I)V
+
+    # Call compareTo(int) - this is an implicit box.
+    const v2, 40
+    invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Long;I)I
+    move-result v3
+    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v4, v3}, Ljava/io/PrintStream;->print(I)V
+
+    # Add a newline at the end of file.
+    invoke-virtual {v4}, Ljava/io/PrintStream;->println()V
+
     return-void
 .end method