MethodHandles: fix missing nominal type return value conversion
Fixes missing adaption path when a method handle has a nominal type
set from MH.asType().
Bug: 113855305
Test: art/test/run-test --host 956
Change-Id: Id203e5ab6bd5df03fd728944f52f6e267c3a38f3
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 38bd611..2dc9f67 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -419,6 +419,7 @@
static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> target_type,
+ Handle<mirror::MethodType> nominal_type,
Thread* self,
ShadowFrame& shadow_frame,
const InstructionOperands* const operands,
@@ -543,6 +544,11 @@
return false;
}
+ if (nominal_type != nullptr) {
+ return ConvertReturnValue(nominal_type, target_type, result) &&
+ ConvertReturnValue(callsite_type, nominal_type, result);
+ }
+
return ConvertReturnValue(callsite_type, target_type, result);
}
@@ -714,8 +720,9 @@
const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
- StackHandleScope<1> hs(self);
+ StackHandleScope<2> hs(self);
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
+ Handle<mirror::MethodType> nominal_handle_type(hs.NewHandle(method_handle->GetNominalType()));
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
DCHECK(IsInvoke(handle_kind));
@@ -761,6 +768,7 @@
return MethodHandleInvokeMethod(called_method,
callsite_type,
handle_type,
+ nominal_handle_type,
self,
shadow_frame,
operands,
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index a54b481..e70c83b 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -95,6 +95,11 @@
}
}
+ public static class I {
+ public static void someVoidMethod() {
+ }
+ }
+
public static void main(String[] args) throws Throwable {
testfindSpecial_invokeSuperBehaviour();
testfindSpecial_invokeDirectBehaviour();
@@ -635,6 +640,30 @@
fail();
} catch (WrongMethodTypeException expected) {
}
+
+ // Zero / null introduction
+ MethodHandle voidMH = MethodHandles.lookup().findStatic(I.class, "someVoidMethod",
+ MethodType.methodType(void.class));
+ {
+ MethodHandle booleanMH = voidMH.asType(MethodType.methodType(boolean.class));
+ assertEquals(boolean.class, booleanMH.type().returnType());
+ assertEquals(false, booleanMH.invoke());
+ }
+ {
+ MethodHandle intMH = voidMH.asType(MethodType.methodType(int.class));
+ assertEquals(int.class, intMH.type().returnType());
+ assertEquals(0, intMH.invoke());
+ }
+ {
+ MethodHandle longMH = voidMH.asType(MethodType.methodType(long.class));
+ assertEquals(long.class, longMH.type().returnType());
+ assertEquals(0L, longMH.invoke());
+ }
+ {
+ MethodHandle objMH = voidMH.asType(MethodType.methodType(Object.class));
+ assertEquals(Object.class, objMH.type().returnType());
+ assertEquals(null, objMH.invoke());
+ }
}
public static void assertTrue(boolean value) {