MethodHandles: Enable return value conversions.

Enables return values conversions and simplify the type conversion
logic. Ensures check for WrongMethodTypeExceptions before invoking a
method handle.

Test: m test-art-host-run-test-956-methodhandles
Bug: 30550796

Change-Id: I8add3ad0a19b43010946b4fb9f1c0f0949287860
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5e4bb41..cb775cd 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -827,6 +827,20 @@
   return klass;
 }
 
+// Returns true iff. the callsite type for a polymorphic invoke is transformer
+// like, i.e that it has a single input argument whose type is
+// dalvik.system.EmulatedStackFrame.
+static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes());
+  if (param_types->GetLength() == 1) {
+    ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0));
+    return param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame);
+  }
+
+  return false;
+}
+
 template<bool is_range, bool do_access_check>
 inline bool DoInvokePolymorphic(Thread* self,
                                 ShadowFrame& shadow_frame,
@@ -838,6 +852,11 @@
   const uint32_t vRegC = (is_range) ? inst->VRegC_4rcc() : inst->VRegC_45cc();
   const int invoke_method_idx = (is_range) ? inst->VRegB_4rcc() : inst->VRegB_45cc();
 
+  // Initialize |result| to 0 as this is the default return value for
+  // polymorphic invocations of method handle types with void return
+  // and provides sane return result in error cases.
+  result->SetJ(0);
+
   // Determine if this invocation is MethodHandle.invoke() or
   // MethodHandle.invokeExact().
   bool is_invoke_exact = IsInvokeExact(shadow_frame.GetMethod()->GetDeclaringClass()->GetDexFile(),
@@ -859,7 +878,6 @@
     // 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.
     ThrowNullPointerExceptionForMethodAccess(invoke_method_idx, InvokeType::kVirtual);
-    result->SetJ(0);
     return false;
   }
 
@@ -880,14 +898,13 @@
   // This implies we couldn't resolve one or more types in this method handle.
   if (UNLIKELY(callsite_type.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());
-    result->SetJ(0);
     return false;
   }
 
   const MethodHandleKind handle_kind = method_handle->GetHandleKind();
   Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
   CHECK(handle_type.Get() != nullptr);
-  if (is_invoke_exact) {
+  {
     // We need to check the nominal type of the handle in addition to the
     // real type. The "nominal" type is present when MethodHandle.asType is
     // called any handle, and results in the declared type of the handle
@@ -900,9 +917,17 @@
       check_type.Assign(nominal_type.Ptr());
     }
 
-    if (UNLIKELY(!callsite_type->IsExactMatch(check_type.Ptr()))) {
-      ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
-      return false;
+    if (is_invoke_exact) {
+      if (UNLIKELY(!callsite_type->IsExactMatch(check_type.Ptr()))) {
+        ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
+        return false;
+      }
+    } else {
+      if (UNLIKELY(!IsCallerTransformer(callsite_type) &&
+                   !callsite_type->IsConvertible(check_type.Ptr()))) {
+        ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
+        return false;
+      }
     }
   }
 
@@ -932,7 +957,7 @@
       // TODO: Unfortunately, we have to postpone dynamic receiver based checks
       // because the receiver might be cast or might come from an emulated stack
       // frame, which means that it is unknown at this point. We perform these
-      // checks inside DoCallPolymorphic right before we do the actualy invoke.
+      // checks inside DoCallPolymorphic right before we do the actual invoke.
     } else if (handle_kind == kInvokeDirect) {
       // String constructors are a special case, they are replaced with StringFactory
       // methods.
@@ -965,40 +990,38 @@
       CHECK(called_method != nullptr);
     }
 
+    bool call_success;
     if (handle_kind == kInvokeTransform) {
-      return DoCallTransform<is_range>(called_method,
-                                       callsite_type,
-                                       handle_type,
-                                       self,
-                                       shadow_frame,
-                                       method_handle /* receiver */,
-                                       result,
-                                       arg,
-                                       first_src_reg);
+      call_success = DoCallTransform<is_range>(called_method,
+                                               callsite_type,
+                                               handle_type,
+                                               self,
+                                               shadow_frame,
+                                               method_handle /* receiver */,
+                                               result,
+                                               arg,
+                                               first_src_reg);
     } else {
-      return DoCallPolymorphic<is_range>(called_method,
-                                         callsite_type,
-                                         handle_type,
-                                         self,
-                                         shadow_frame,
-                                         result,
-                                         arg,
-                                         first_src_reg,
-                                         handle_kind);
+      call_success = DoCallPolymorphic<is_range>(called_method,
+                                                 callsite_type,
+                                                 handle_type,
+                                                 self,
+                                                 shadow_frame,
+                                                 result,
+                                                 arg,
+                                                 first_src_reg,
+                                                 handle_kind);
     }
+    if (LIKELY(call_success && ConvertReturnValue(callsite_type, handle_type, result))) {
+      return true;
+    }
+    DCHECK(self->IsExceptionPending());
+    return false;
   } else {
     DCHECK(!is_range);
     ArtField* field = method_handle->GetTargetField();
     Primitive::Type field_type = field->GetTypeAsPrimitiveType();;
 
-    if (!is_invoke_exact) {
-      if (handle_type->GetPTypes()->GetLength() != callsite_type->GetPTypes()->GetLength()) {
-        // Too many arguments to setter or getter.
-        ThrowWrongMethodTypeException(callsite_type.Get(), handle_type.Get());
-        return false;
-      }
-    }
-
     switch (handle_kind) {
       case kInstanceGet: {
         ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg);
@@ -1029,7 +1052,6 @@
           return false;
         }
         ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg);
-        result->SetL(0);
         return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
       }
       case kStaticPut: {
@@ -1039,7 +1061,6 @@
           return false;
         }
         ObjPtr<mirror::Object> obj = field->GetDeclaringClass();
-        result->SetL(0);
         return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
       }
       default:
@@ -1120,20 +1141,6 @@
   }
 }
 
-// Returns true iff. the callsite type for a polymorphic invoke is transformer
-// like, i.e that it has a single input argument whose type is
-// dalvik.system.EmulatedStackFrame.
-static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes());
-  if (param_types->GetLength() == 1) {
-    ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0));
-    return param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame);
-  }
-
-  return false;
-}
-
 template <bool is_range>
 static inline bool DoCallPolymorphic(ArtMethod* called_method,
                                      Handle<mirror::MethodType> callsite_type,
@@ -1245,8 +1252,6 @@
 
   PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
 
-  // TODO(narayan): Perform return value conversions.
-
   // If the caller of this signature polymorphic method was a transformer,
   // we need to copy the result back out to the emulated stack frame.
   if (is_caller_transformer && !self->IsExceptionPending()) {