8256189: Exact VarHandle tests should test withInvokeBehavior() works as expected

Reviewed-by: mcimadamore, chegar
This commit is contained in:
Jorn Vernee 2020-11-18 19:01:52 +00:00
parent 300cbaa6ad
commit 03e84ef7e3
3 changed files with 96 additions and 128 deletions

View file

@ -39,7 +39,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase { final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase {
static final boolean BE = UNSAFE.isBigEndian(); static final boolean BE = UNSAFE.isBigEndian();
static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess(); static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
static final int VM_ALIGN = $BoxType$.BYTES - 1; static final int VM_ALIGN = $BoxType$.BYTES - 1;
@ -66,7 +66,7 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
public MemoryAccessVarHandle$Type$Helper withInvokeBehavior() { public MemoryAccessVarHandle$Type$Helper withInvokeBehavior() {
return !hasInvokeExactBehavior() ? return !hasInvokeExactBehavior() ?
this : this :
new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, true); new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, false);
} }
#if[floatingPoint] #if[floatingPoint]

View file

@ -38,11 +38,17 @@ import java.lang.invoke.VarHandle;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
import static sun.security.action.GetPropertyAction.*;
/** /**
* This class contains misc helper functions to support creation of memory segments. * This class contains misc helper functions to support creation of memory segments.
*/ */
public final class Utils { public final class Utils {
// used when testing invoke exact behavior of memory access handles
private static final boolean SHOULD_ADAPT_HANDLES
= Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
private static final String foreignRestrictedAccess = Optional.ofNullable(VM.getSavedProperty("foreign.restricted")) private static final String foreignRestrictedAccess = Optional.ofNullable(VM.getSavedProperty("foreign.restricted"))
.orElse("deny"); .orElse("deny");
@ -72,7 +78,9 @@ public final class Utils {
public static VarHandle fixUpVarHandle(VarHandle handle) { public static VarHandle fixUpVarHandle(VarHandle handle) {
// This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy, // This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
// and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations. // and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
return MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER); return SHOULD_ADAPT_HANDLES
? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
: handle;
} }
private static MemorySegmentProxy filterSegment(MemorySegment segment) { private static MemorySegmentProxy filterSegment(MemorySegment segment) {

View file

@ -24,16 +24,31 @@
/* /*
* @test * @test
* @modules jdk.incubator.foreign * @modules jdk.incubator.foreign
* java.base/jdk.internal.access.foreign
* *
* @run testng/othervm -Xverify:all VarHandleTestExact * @run testng/othervm -Xverify:all
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact * -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestExact * VarHandleTestExact
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact * @run testng/othervm -Xverify:all
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true
* VarHandleTestExact
* @run testng/othervm -Xverify:all
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false
* VarHandleTestExact
* @run testng/othervm -Xverify:all
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true
* VarHandleTestExact
*/ */
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryHandles; import jdk.incubator.foreign.MemoryHandles;
import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.MemorySegment;
import jdk.internal.access.foreign.MemorySegmentProxy;
import org.testng.SkipException; import org.testng.SkipException;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -46,6 +61,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import static org.testng.Assert.*; import static org.testng.Assert.*;
@ -80,24 +96,12 @@ public class VarHandleTestExact {
throws NoSuchFieldException, IllegalAccessException { throws NoSuchFieldException, IllegalAccessException {
if (ro) throw new SkipException("Can not test setter with read only field"); if (ro) throw new SkipException("Can not test setter with read only field");
VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + "_RW", fieldType); VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + "_RW", fieldType);
assertFalse(vh.hasInvokeExactBehavior());
Widget w = new Widget(); Widget w = new Widget();
try { doTest(vh,
vh.set(w, testValue); tvh -> tvh.set(w, testValue),
vh.withInvokeBehavior().set(w, testValue); tvh -> setter.set(tvh, w, testValue),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected (Widget," + fieldType.getSimpleName() + ")void \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
setter.set(vh, w, testValue); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),".*\\Qexpected (Widget," + fieldType.getSimpleName() + ")void \\E.*");
}
} }
@Test(dataProvider = "dataObjectAccess") @Test(dataProvider = "dataObjectAccess")
@ -106,24 +110,12 @@ public class VarHandleTestExact {
SetStaticX staticSetter, GetStaticX staticGetter) SetStaticX staticSetter, GetStaticX staticGetter)
throws NoSuchFieldException, IllegalAccessException { throws NoSuchFieldException, IllegalAccessException {
VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + (ro ? "_RO" : "_RW"), fieldType); VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + (ro ? "_RO" : "_RW"), fieldType);
assertFalse(vh.hasInvokeExactBehavior());
Widget w = new Widget(); Widget w = new Widget();
try { doTest(vh,
Object o = vh.get(w); tvh -> tvh.get(w),
Object o2 = vh.withInvokeBehavior().get(w); tvh -> getter.get(tvh, w),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected (Widget)" + fieldType.getSimpleName() + " \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
getter.get(vh, w); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),".*\\Qexpected (Widget)" + fieldType.getSimpleName() + " \\E.*");
}
} }
@Test(dataProvider = "dataObjectAccess") @Test(dataProvider = "dataObjectAccess")
@ -133,23 +125,11 @@ public class VarHandleTestExact {
throws NoSuchFieldException, IllegalAccessException { throws NoSuchFieldException, IllegalAccessException {
if (ro) throw new SkipException("Can not test setter with read only field"); if (ro) throw new SkipException("Can not test setter with read only field");
VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + "_SRW", fieldType); VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + "_SRW", fieldType);
assertFalse(vh.hasInvokeExactBehavior());
try { doTest(vh,
vh.set(testValue); tvh -> tvh.set(testValue),
vh.withInvokeBehavior().set(testValue); tvh -> staticSetter.set(tvh, testValue),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected (" + fieldType.getSimpleName() + ")void \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
staticSetter.set(vh, testValue); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),".*\\Qexpected (" + fieldType.getSimpleName() + ")void \\E.*");
}
} }
@Test(dataProvider = "dataObjectAccess") @Test(dataProvider = "dataObjectAccess")
@ -158,94 +138,74 @@ public class VarHandleTestExact {
SetStaticX staticSetter, GetStaticX staticGetter) SetStaticX staticSetter, GetStaticX staticGetter)
throws NoSuchFieldException, IllegalAccessException { throws NoSuchFieldException, IllegalAccessException {
VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + (ro ? "_SRO" : "_SRW"), fieldType); VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + (ro ? "_SRO" : "_SRW"), fieldType);
assertFalse(vh.hasInvokeExactBehavior());
try { doTest(vh,
Object o = vh.get(); tvh -> tvh.get(),
Object o2 = vh.withInvokeBehavior().get(); tvh -> staticGetter.get(tvh),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected ()" + fieldType.getSimpleName() + " \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
staticGetter.get(vh); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),".*\\Qexpected ()" + fieldType.getSimpleName() + " \\E.*");
}
} }
@Test(dataProvider = "dataSetArray") @Test(dataProvider = "dataSetArray")
public void testExactArraySet(Class<?> arrayClass, Object testValue, SetArrayX setter) { public void testExactArraySet(Class<?> arrayClass, Object testValue, SetArrayX setter) {
VarHandle vh = MethodHandles.arrayElementVarHandle(arrayClass); VarHandle vh = MethodHandles.arrayElementVarHandle(arrayClass);
Object arr = Array.newInstance(arrayClass.componentType(), 1); Object arr = Array.newInstance(arrayClass.componentType(), 1);
assertFalse(vh.hasInvokeExactBehavior());
try { doTest(vh,
vh.set(arr, 0, testValue); tvh -> tvh.set(arr, 0, testValue),
vh.withInvokeBehavior().set(arr, 0, testValue); tvh -> setter.set(tvh, arr, testValue),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
setter.set(vh, arr, testValue); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),
".*\\Qexpected (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
}
} }
@Test(dataProvider = "dataSetBuffer") @Test(dataProvider = "dataSetBuffer")
public void testExactBufferSet(Class<?> arrayClass, Object testValue, SetBufferX setter) { public void testExactBufferSet(Class<?> arrayClass, Object testValue, SetBufferX setter) {
VarHandle vh = MethodHandles.byteBufferViewVarHandle(arrayClass, ByteOrder.nativeOrder()); VarHandle vh = MethodHandles.byteBufferViewVarHandle(arrayClass, ByteOrder.nativeOrder());
assertFalse(vh.hasInvokeExactBehavior());
ByteBuffer buff = ByteBuffer.allocateDirect(8); ByteBuffer buff = ByteBuffer.allocateDirect(8);
try { doTest(vh,
vh.set(buff, 0, testValue); tvh -> tvh.set(buff, 0, testValue),
vh.withInvokeBehavior().set(buff, 0, testValue); tvh -> setter.set(tvh, buff, testValue),
} catch (WrongMethodTypeException wmte) { ".*\\Qexpected (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior();
assertTrue(vh.hasInvokeExactBehavior());
try {
setter.set(vh, buff, testValue); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(),
".*\\Qexpected (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
}
} }
@Test(dataProvider = "dataSetMemorySegment") @Test(dataProvider = "dataSetMemorySegment")
public void testExactSegmentSet(Class<?> carrier, Object testValue, SetSegmentX setter) { public void testExactSegmentSet(Class<?> carrier, Object testValue, SetSegmentX setter) {
VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder()); VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder());
assertFalse(vh.hasInvokeExactBehavior());
try (MemorySegment seg = MemorySegment.allocateNative(8)) { try (MemorySegment seg = MemorySegment.allocateNative(8)) {
try {
vh.set(seg, 0L, testValue);
vh.withInvokeBehavior().set(seg, 0L, testValue);
} catch (WrongMethodTypeException wmte) {
fail("Unexpected exception", wmte);
}
vh = vh.withInvokeExactBehavior(); doTest(vh,
assertTrue(vh.hasInvokeExactBehavior()); tvh -> tvh.set(seg, 0L, testValue),
try { tvh -> setter.set(tvh, seg, 0L, testValue),
setter.set(vh, seg, 0L, testValue); // should throw ".*\\Qexpected (MemorySegmentProxy,long," + carrier.getSimpleName() + ")void \\E.*");
fail("Exception expected"); }
} catch (WrongMethodTypeException wmte) { }
assertMatches(wmte.getMessage(),
".*\\Qexpected (MemorySegment,long," + carrier.getSimpleName() + ")void \\E.*"); private static void doTest(VarHandle invokeHandle, Consumer<VarHandle> invokeTest,
} Consumer<VarHandle> invokeExactTest, String expectedMessage) {
assertFalse(invokeHandle.hasInvokeExactBehavior());
assertSame(invokeHandle, invokeHandle.withInvokeBehavior());
try {
invokeTest.accept(invokeHandle);
} catch (WrongMethodTypeException wmte) {
fail("Unexpected exception", wmte);
}
VarHandle invokeExactHandle = invokeHandle.withInvokeExactBehavior();
assertTrue(invokeExactHandle.hasInvokeExactBehavior());
assertSame(invokeExactHandle, invokeExactHandle.withInvokeExactBehavior());
try {
invokeExactTest.accept(invokeExactHandle); // should throw
fail("Exception expected");
} catch (WrongMethodTypeException wmte) {
assertMatches(wmte.getMessage(), expectedMessage);
}
// try going back
VarHandle invokeHandle2 = invokeExactHandle.withInvokeBehavior();
assertFalse(invokeHandle2.hasInvokeExactBehavior());
try {
invokeTest.accept(invokeHandle2);
} catch (WrongMethodTypeException wmte) {
fail("Unexpected exception", wmte);
} }
} }
@ -280,7 +240,7 @@ public class VarHandleTestExact {
} }
private interface SetSegmentX { private interface SetSegmentX {
void set(VarHandle vh, MemorySegment segment, long offser, Object testValue); void set(VarHandle vh, MemorySegment segment, long offset, Object testValue);
} }
private static void consume(Object o) {} private static void consume(Object o) {}
@ -417,11 +377,11 @@ public class VarHandleTestExact {
List<Object[]> cases = new ArrayList<>(); List<Object[]> cases = new ArrayList<>();
// create a bunch of different sig-poly call sites // create a bunch of different sig-poly call sites
testCaseSegmentSet(cases, long.class, 1234, (vh, seg, off, tv) -> vh.set(seg, off, (int) tv)); testCaseSegmentSet(cases, long.class, 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (int) tv));
testCaseSegmentSet(cases, long.class, (char) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (char) tv)); testCaseSegmentSet(cases, long.class, (char) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (char) tv));
testCaseSegmentSet(cases, long.class, (short) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (short) tv)); testCaseSegmentSet(cases, long.class, (short) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (short) tv));
testCaseSegmentSet(cases, long.class, (byte) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (byte) tv)); testCaseSegmentSet(cases, long.class, (byte) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (byte) tv));
testCaseSegmentSet(cases, double.class, 1234F, (vh, seg, off, tv) -> vh.set(seg, off, (float) tv)); testCaseSegmentSet(cases, double.class, 1234F, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (float) tv));
return cases.toArray(Object[][]::new); return cases.toArray(Object[][]::new);
} }