From 69a46c25cc87d9d5495d0bb975c44f38cbb1fe13 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Mon, 17 Jul 2023 14:53:37 +0000 Subject: [PATCH] 8310157: Allow void-returning filters for MethodHandles::collectCoordinates Reviewed-by: mcimadamore --- .../java/lang/invoke/MethodHandles.java | 29 +++++++++---------- .../classes/java/lang/invoke/VarHandles.java | 8 ++--- .../jdk/java/foreign/TestAdaptVarHandles.java | 11 +++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index ee3da58e2dd..7fc31c63b56 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -8188,19 +8188,18 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * filter function and the target var handle is then called on the modified (usually shortened) * coordinate list. *

- * If {@code R} is the return type of the filter (which cannot be void), the target var handle must accept a value of - * type {@code R} as its coordinate in position {@code pos}, preceded and/or followed by - * any coordinate not passed to the filter. - * No coordinates are reordered, and the result returned from the filter - * replaces (in order) the whole subsequence of coordinates originally - * passed to the adapter. - *

- * The argument types (if any) of the filter - * replace zero or one coordinate types of the target var handle, at position {@code pos}, - * in the resulting adapted var handle. - * The return type of the filter must be identical to the - * coordinate type of the target var handle at position {@code pos}, and that target var handle - * coordinate is supplied by the return value of the filter. + * If {@code R} is the return type of the filter, then: + *

*

* If any of the filters throws a checked exception when invoked, the resulting var handle will * throw an {@link IllegalStateException}. @@ -8209,12 +8208,12 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * atomic access guarantees as those featured by the target var handle. * * @param target the var handle to invoke after the coordinates have been filtered - * @param pos the position of the coordinate to be filtered + * @param pos the position in the coordinate list of the target var handle where the filter is to be inserted * @param filter the filter method handle * @return an adapter var handle which filters the incoming coordinate values, * before calling the target var handle * @throws IllegalArgumentException if the return type of {@code filter} - * is void, or it is not the same as the {@code pos} coordinate of the target var handle, + * is not void, and it is not the same as the {@code pos} coordinate of the target var handle, * if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive, * if the resulting var handle's type would have too many coordinates, * or if it's determined that {@code filter} throws any checked exceptions. 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 a8bc817a9e7..13993ca8f10 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -563,14 +563,14 @@ final class VarHandles { List> targetCoordinates = target.coordinateTypes(); if (pos < 0 || pos >= targetCoordinates.size()) { throw newIllegalArgumentException("Invalid position " + pos + " for coordinate types", targetCoordinates); - } else if (filter.type().returnType() == void.class) { - throw newIllegalArgumentException("Invalid filter type " + filter.type() + " ; filter cannot be void"); - } else if (filter.type().returnType() != targetCoordinates.get(pos)) { + } else if (filter.type().returnType() != void.class && filter.type().returnType() != targetCoordinates.get(pos)) { throw newIllegalArgumentException("Invalid filter type " + filter.type() + " for coordinate type " + targetCoordinates.get(pos)); } List> newCoordinates = new ArrayList<>(targetCoordinates); - newCoordinates.remove(pos); + if (filter.type().returnType() != void.class) { + newCoordinates.remove(pos); + } newCoordinates.addAll(pos, filter.type().parameterList()); return new IndirectVarHandle(target, target.varType(), newCoordinates.toArray(new Class[0]), diff --git a/test/jdk/java/foreign/TestAdaptVarHandles.java b/test/jdk/java/foreign/TestAdaptVarHandles.java index 893755f15d4..5074b8d793b 100644 --- a/test/jdk/java/foreign/TestAdaptVarHandles.java +++ b/test/jdk/java/foreign/TestAdaptVarHandles.java @@ -351,6 +351,12 @@ public class TestAdaptVarHandles { assertEquals(value, 42); } + @Test + public void testCollectCoordinatesVoidFilterType() { + VarHandle handle = MethodHandles.collectCoordinates(intHandle, 0, VOID_FILTER); + assertEquals(handle.coordinateTypes(), List.of(String.class, MemorySegment.class)); + } + @Test(expectedExceptions = IllegalArgumentException.class) public void testBadCollectCoordinatesNegativePos() { MethodHandles.collectCoordinates(intHandle, -1, SUM_OFFSETS); @@ -366,11 +372,6 @@ public class TestAdaptVarHandles { MethodHandles.collectCoordinates(intHandle, 0, SUM_OFFSETS); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testBadCollectCoordinatesWrongVoidFilterType() { - MethodHandles.collectCoordinates(intHandle, 0, VOID_FILTER); - } - @Test(expectedExceptions = IllegalArgumentException.class) public void testBadCollectCoordinatesWrongFilterException() { MethodHandles.collectCoordinates(intHandle, 0, S2L_EX);