Use correct type for GetValueFromShadowFrame

The field type is not necessarily the input type for boxed
primitives. If the field type is < 32 bits, it means there will be
partial object pointer in the JValue. If a conversion check is
later needed in GetUnboxedTypeAndValue, it will crash. The fix is
to use the PTypes.

Bug: 37446461
Test: test-art-host
Change-Id: I0c4b405f0c13910523b98a87ef12b9f302a5e241
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index bd7c4ad..b6f8a17 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -925,8 +925,17 @@
     case mirror::MethodHandle::kInstancePut: {
       size_t obj_reg = is_range ? first_arg : args[0];
       size_t value_reg = is_range ? (first_arg + 1) : args[1];
-      JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
-      if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 1, &value)) {
+      const size_t kPTypeIndex = 1;
+      // Use ptypes instead of field type since we may be unboxing a reference for a primitive
+      // field. The field type is incorrect for this case.
+      JValue value = GetValueFromShadowFrame(
+          shadow_frame,
+          callsite_type->GetPTypes()->Get(kPTypeIndex)->GetPrimitiveType(),
+          value_reg);
+      if (do_conversions && !ConvertArgumentValue(callsite_type,
+                                                  handle_type,
+                                                  kPTypeIndex,
+                                                  &value)) {
         DCHECK(self->IsExceptionPending());
         return false;
       }
@@ -940,8 +949,17 @@
         return false;
       }
       size_t value_reg = is_range ? first_arg : args[0];
-      JValue value = GetValueFromShadowFrame(shadow_frame, field_type, value_reg);
-      if (do_conversions && !ConvertArgumentValue(callsite_type, handle_type, 0, &value)) {
+      const size_t kPTypeIndex = 0;
+      // Use ptypes instead of field type since we may be unboxing a reference for a primitive
+      // field. The field type is incorrect for this case.
+      JValue value = GetValueFromShadowFrame(
+          shadow_frame,
+          callsite_type->GetPTypes()->Get(kPTypeIndex)->GetPrimitiveType(),
+          value_reg);
+      if (do_conversions && !ConvertArgumentValue(callsite_type,
+                                                  handle_type,
+                                                  kPTypeIndex,
+                                                  &value)) {
         DCHECK(self->IsExceptionPending());
         return false;
       }
diff --git a/test/959-invoke-polymorphic-accessors/src/Main.java b/test/959-invoke-polymorphic-accessors/src/Main.java
index b7ecf8e..59db807 100644
--- a/test/959-invoke-polymorphic-accessors/src/Main.java
+++ b/test/959-invoke-polymorphic-accessors/src/Main.java
@@ -794,6 +794,7 @@
             ValueHolder valueHolder = new ValueHolder();
             MethodHandles.Lookup lookup = MethodHandles.lookup();
             MethodHandle h0 = lookup.findSetter(ValueHolder.class, "m_f", float.class);
+            MethodHandle s0 = lookup.findSetter(ValueHolder.class, "m_s", short.class);
             h0.invoke(valueHolder, 0.22f);
             h0.invoke(valueHolder, new Float(1.11f));
             Number floatNumber = getFloatAsNumber();
@@ -807,6 +808,11 @@
               unreachable();
             } catch (NullPointerException e) {}
 
+            // Test that type conversion checks work on small field types.
+            short temp = (short)s0.invoke(valueHolder, new Byte((byte)45));
+            assertTrue(temp == 0);
+            assertTrue(valueHolder.m_s == 45);
+
             h0.invoke(valueHolder, (byte)1);
             h0.invoke(valueHolder, (short)2);
             h0.invoke(valueHolder, 3);
@@ -848,6 +854,7 @@
 
         private static void testStaticSetter() throws Throwable {
             MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodHandle s0 = lookup.findStaticSetter(ValueHolder.class, "s_s", short.class);
             MethodHandle h0 = lookup.findStaticSetter(ValueHolder.class, "s_f", float.class);
             h0.invoke(0.22f);
             h0.invoke(new Float(1.11f));
@@ -860,6 +867,11 @@
               unreachable();
             } catch (NullPointerException e) {}
 
+            // Test that type conversion checks work on small field types.
+            short temp = (short)s0.invoke(new Byte((byte)45));
+            assertTrue(temp == 0);
+            assertTrue(ValueHolder.s_s == 45);
+
             h0.invoke((byte)1);
             h0.invoke((short)2);
             h0.invoke(3);