From b8d4e02ce77367711fda23dd330bd90f0280babd Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Tue, 3 Nov 2020 12:10:48 +0000 Subject: [PATCH] 8255374: Add a dropReturn MethodHandle combinator Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 23 +++++++ .../invoke/MethodHandles/TestDropReturn.java | 68 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java 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 64698d94a00..7a615729c4e 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -62,6 +62,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.lang.invoke.LambdaForm.BasicType.V_TYPE; import static java.lang.invoke.MethodHandleImpl.Intrinsic; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; @@ -5205,6 +5206,28 @@ assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c")); return dropArgumentsToMatch(target, skip, newTypes, pos, false); } + /** + * Drop the return value of the target handle (if any). + * The returned method handle will have a {@code void} return type. + * + * @param target the method handle to adapt + * @return a possibly adapted method handle + * @throws NullPointerException if {@code target} is null + * @since 16 + */ + public static MethodHandle dropReturn(MethodHandle target) { + Objects.requireNonNull(target); + MethodType oldType = target.type(); + Class oldReturnType = oldType.returnType(); + if (oldReturnType == void.class) + return target; + MethodType newType = oldType.changeReturnType(void.class); + BoundMethodHandle result = target.rebind(); + LambdaForm lform = result.editor().filterReturnForm(V_TYPE, true); + result = result.copyWith(newType, lform); + return result; + } + /** * Adapts a target method handle by pre-processing * one or more of its arguments, each with its own unary filter function, diff --git a/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java new file mode 100644 index 00000000000..ff31dd63f0b --- /dev/null +++ b/test/jdk/java/lang/invoke/MethodHandles/TestDropReturn.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255398 + * @run testng TestDropReturn + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import static java.lang.invoke.MethodType.methodType; +import static org.testng.Assert.assertEquals; + +public class TestDropReturn { + + @Test(dataProvider = "dropReturnCases") + public void testDropReturn(Class cls, Object testValue) throws Throwable { + MethodHandle mh = MethodHandles.identity(cls); + assertEquals(mh.type(), methodType(cls, cls)); + Object x = mh.invoke(testValue); + assertEquals(x, testValue); + + mh = MethodHandles.dropReturn(mh); + assertEquals(mh.type(), methodType(void.class, cls)); + mh.invoke(testValue); // should at least work + } + + @DataProvider + public static Object[][] dropReturnCases() { + return new Object[][]{ + { boolean.class, true }, + { byte.class, (byte) 10 }, + { char.class, 'x' }, + { short.class, (short) 10 }, + { int.class, 10 }, + { long.class, 10L }, + { float.class, 10F }, + { double.class, 10D }, + { Object.class, new Object() }, + { String.class, "ABCD" }, + }; + } +}