diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index aaab1f43967..58be18475ce 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -542,17 +542,23 @@ public static VarHandle dropCoordinates(VarHandle target, int pos, Class... v private static void noCheckedExceptions(MethodHandle handle) { if (handle instanceof DirectMethodHandle) { DirectMethodHandle directHandle = (DirectMethodHandle)handle; - MethodHandleInfo info = MethodHandles.Lookup.IMPL_LOOKUP.revealDirect(directHandle); - Class[] exceptionTypes = switch (info.getReferenceKind()) { - case MethodHandleInfo.REF_invokeInterface, MethodHandleInfo.REF_invokeSpecial, - MethodHandleInfo.REF_invokeStatic, MethodHandleInfo.REF_invokeVirtual -> - info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP).getExceptionTypes(); - case MethodHandleInfo.REF_newInvokeSpecial -> - info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP).getExceptionTypes(); - case MethodHandleInfo.REF_getField, MethodHandleInfo.REF_getStatic, - MethodHandleInfo.REF_putField, MethodHandleInfo.REF_putStatic -> null; - default -> throw new AssertionError("Cannot get here"); - }; + byte refKind = directHandle.member.getReferenceKind(); + MethodHandleInfo info = new InfoFromMemberName( + MethodHandles.Lookup.IMPL_LOOKUP, + directHandle.member, + refKind); + final Class[] exceptionTypes; + if (MethodHandleNatives.refKindIsMethod(refKind)) { + exceptionTypes = info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP) + .getExceptionTypes(); + } else if (MethodHandleNatives.refKindIsField(refKind)) { + exceptionTypes = null; + } else if (MethodHandleNatives.refKindIsConstructor(refKind)) { + exceptionTypes = info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP) + .getExceptionTypes(); + } else { + throw new AssertionError("Cannot get here"); + } if (exceptionTypes != null) { if (Stream.of(exceptionTypes).anyMatch(VarHandles::isCheckedException)) { throw newIllegalArgumentException("Cannot adapt a var handle with a method handle which throws checked exceptions"); diff --git a/test/jdk/java/foreign/TestAdaptVarHandles.java b/test/jdk/java/foreign/TestAdaptVarHandles.java index 5eec649cdff..1847e058181 100644 --- a/test/jdk/java/foreign/TestAdaptVarHandles.java +++ b/test/jdk/java/foreign/TestAdaptVarHandles.java @@ -49,6 +49,8 @@ static MethodHandle S2I; static MethodHandle I2S; + static MethodHandle O2I; + static MethodHandle I2O; static MethodHandle S2L; static MethodHandle S2L_EX; static MethodHandle S2I_EX; @@ -61,6 +63,8 @@ try { S2I = MethodHandles.lookup().findStatic(TestAdaptVarHandles.class, "stringToInt", MethodType.methodType(int.class, String.class)); I2S = MethodHandles.lookup().findStatic(TestAdaptVarHandles.class, "intToString", MethodType.methodType(String.class, int.class)); + O2I = MethodHandles.explicitCastArguments(S2I, MethodType.methodType(int.class, Object.class)); + I2O = MethodHandles.explicitCastArguments(I2S, MethodType.methodType(Object.class, int.class)); S2L = MethodHandles.lookup().findStatic(TestAdaptVarHandles.class, "stringToLong", MethodType.methodType(long.class, String.class)); S2L_EX = MethodHandles.lookup().findStatic(TestAdaptVarHandles.class, "stringToLongException", MethodType.methodType(long.class, String.class)); BASE_ADDR = MethodHandles.lookup().findStatic(TestAdaptVarHandles.class, "baseAddress", MethodType.methodType(MemoryAddress.class, MemorySegment.class)); @@ -98,6 +102,25 @@ public void testFilterValue() throws Throwable { assertEquals(value, "42"); } + @Test + public void testFilterValueLoose() throws Throwable { + ValueLayout layout = MemoryLayouts.JAVA_INT; + MemorySegment segment = MemorySegment.allocateNative(layout); + VarHandle intHandle = layout.varHandle(int.class); + VarHandle i2SHandle = MemoryHandles.filterValue(intHandle, O2I, I2O); + i2SHandle.set(segment.baseAddress(), "1"); + String oldValue = (String)i2SHandle.getAndAdd(segment.baseAddress(), "42"); + assertEquals(oldValue, "1"); + String value = (String)i2SHandle.get(segment.baseAddress()); + assertEquals(value, "43"); + boolean swapped = (boolean)i2SHandle.compareAndSet(segment.baseAddress(), "43", "12"); + assertTrue(swapped); + oldValue = (String)i2SHandle.compareAndExchange(segment.baseAddress(), "12", "42"); + assertEquals(oldValue, "12"); + value = (String)(Object)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment.baseAddress()); + assertEquals(value, "42"); + } + @Test(expectedExceptions = NullPointerException.class) public void testBadFilterNullTarget() { MemoryHandles.filterValue(null, S2I, I2S);