8307508: IndirectVarHandle.isAccessModeSupported throws NPE

Reviewed-by: mchung
This commit is contained in:
Chen Liang 2023-06-13 17:05:52 +00:00 committed by Mandy Chung
parent bed9161c81
commit 75dcc4ef94
3 changed files with 78 additions and 36 deletions

View File

@ -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<AccessMode, MethodHandle, MethodHandle> handleFactory;
@ -66,16 +62,6 @@ import java.util.function.BiFunction;
this.coordinates = coordinates;
}
@Override
public Class<?> varType() {
return value;
}
@Override
public List<Class<?>> 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

View File

@ -526,8 +526,6 @@ public abstract sealed class VarHandle implements Constable
return this;
}
VarHandle target() { return null; }
/**
* Returns {@code true} if this VarHandle has <a href="#invoke-exact-behavior"><em>invoke-exact behavior</em></a>.
*
@ -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);

View File

@ -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());
}
}
}