From 75dcc4ef94d90e4aa7f8ca5eccc97c91492d6eed Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 13 Jun 2023 17:05:52 +0000 Subject: [PATCH] 8307508: IndirectVarHandle.isAccessModeSupported throws NPE Reviewed-by: mchung --- .../java/lang/invoke/IndirectVarHandle.java | 44 ++++--------- .../classes/java/lang/invoke/VarHandle.java | 8 +-- .../VarHandles/IndirectVarHandleTest.java | 62 +++++++++++++++++++ 3 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 test/jdk/java/lang/invoke/VarHandles/IndirectVarHandleTest.java diff --git a/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java b/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java index 8d24c6b31fe..3e804ec4f11 100644 --- a/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, 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 @@ -27,9 +27,7 @@ package java.lang.invoke; import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; -import java.util.List; import java.util.function.BiFunction; /** @@ -44,8 +42,6 @@ import java.util.function.BiFunction; */ /* package */ final class IndirectVarHandle extends VarHandle { - @Stable - private final MethodHandle[] handleMap = new MethodHandle[AccessMode.COUNT]; private final VarHandle directTarget; // cache, for performance reasons private final VarHandle target; private final BiFunction handleFactory; @@ -66,16 +62,6 @@ import java.util.function.BiFunction; this.coordinates = coordinates; } - @Override - public Class varType() { - return value; - } - - @Override - public List> coordinateTypes() { - return List.of(coordinates); - } - @Override MethodType accessModeTypeUncached(AccessType at) { return at.accessModeType(null, value, coordinates); @@ -86,10 +72,6 @@ import java.util.function.BiFunction; return directTarget; } - VarHandle target() { - return target; - } - @Override public VarHandle withInvokeExactBehavior() { return hasInvokeExactBehavior() @@ -97,6 +79,13 @@ import java.util.function.BiFunction; : new IndirectVarHandle(target, value, coordinates, handleFactory, vform, true); } + @Override + public VarHandle withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new IndirectVarHandle(target, value, coordinates, handleFactory, vform, false); + } + @ForceInline boolean checkAccessModeThenIsDirect(VarHandle.AccessDescriptor ad) { super.checkAccessModeThenIsDirect(ad); @@ -105,21 +94,14 @@ import java.util.function.BiFunction; } @Override - public VarHandle withInvokeBehavior() { - return !hasInvokeExactBehavior() - ? this - : new IndirectVarHandle(target, value, coordinates, handleFactory, vform, false); + public boolean isAccessModeSupported(AccessMode accessMode) { + return directTarget.isAccessModeSupported(accessMode); } @Override - @ForceInline - MethodHandle getMethodHandle(int mode) { - MethodHandle handle = handleMap[mode]; - if (handle == null) { - MethodHandle targetHandle = target.getMethodHandle(mode); // might throw UOE of access mode is not supported, which is ok - handle = handleMap[mode] = handleFactory.apply(AccessMode.values()[mode], targetHandle); - } - return handle; + MethodHandle getMethodHandleUncached(int mode) { + MethodHandle targetHandle = target.getMethodHandle(mode); // might throw UOE of access mode is not supported, which is ok + return handleFactory.apply(AccessMode.values()[mode], targetHandle); } @Override diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index 54a5c602d3c..2ffa75cf12b 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -526,8 +526,6 @@ public abstract sealed class VarHandle implements Constable return this; } - VarHandle target() { return null; } - /** * Returns {@code true} if this VarHandle has invoke-exact behavior. * @@ -2120,7 +2118,7 @@ public abstract sealed class VarHandle implements Constable * @return {@code true} if the given access mode is supported, otherwise * {@code false}. */ - public final boolean isAccessModeSupported(AccessMode accessMode) { + public boolean isAccessModeSupported(AccessMode accessMode) { return vform.getMemberNameOrNull(accessMode.ordinal()) != null; } @@ -2176,7 +2174,7 @@ public abstract sealed class VarHandle implements Constable MethodHandle[] methodHandleTable; @ForceInline - MethodHandle getMethodHandle(int mode) { + final MethodHandle getMethodHandle(int mode) { MethodHandle[] mhTable = methodHandleTable; if (mhTable == null) { mhTable = methodHandleTable = new MethodHandle[AccessMode.COUNT]; @@ -2188,7 +2186,7 @@ public abstract sealed class VarHandle implements Constable return mh; } - private final MethodHandle getMethodHandleUncached(int mode) { + MethodHandle getMethodHandleUncached(int mode) { MethodType mt = accessModeType(AccessMode.values()[mode]). insertParameterTypes(0, VarHandle.class); MemberName mn = vform.getMemberName(mode); diff --git a/test/jdk/java/lang/invoke/VarHandles/IndirectVarHandleTest.java b/test/jdk/java/lang/invoke/VarHandles/IndirectVarHandleTest.java new file mode 100644 index 00000000000..bf1b6f66401 --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/IndirectVarHandleTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023, 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 8307508 + * @enablePreview + * @run junit IndirectVarHandleTest + * @summary Test VarHandle::isAccessModeSupported on indirect VarHandle + * produced by MethodHandles.filterCoordinates + */ +import org.junit.jupiter.api.Test; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.function.IntUnaryOperator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IndirectVarHandleTest { + @Test + public void testIsAccessModeTypeSupported() throws Throwable { + var lookup = MethodHandles.lookup(); + var intArrayVh = MethodHandles.arrayElementVarHandle(int[].class); + var addOne = lookup.bind((IntUnaryOperator) a -> a + 1, "applyAsInt", + MethodType.methodType(int.class, int.class)); + var offsetIntArrayVh = MethodHandles.filterCoordinates(intArrayVh, 1, addOne); + + for (var mode : VarHandle.AccessMode.values()) { + assertEquals(intArrayVh.isAccessModeSupported(mode), + offsetIntArrayVh.isAccessModeSupported(mode), mode.toString()); + } + + var stringArrayVh = MethodHandles.arrayElementVarHandle(String[].class); + var offsetStringArrayVh = MethodHandles.filterCoordinates(stringArrayVh, 1, addOne); + + for (var mode : VarHandle.AccessMode.values()) { + assertEquals(stringArrayVh.isAccessModeSupported(mode), + offsetStringArrayVh.isAccessModeSupported(mode), mode.toString()); + } + } +}