Skip to content

Commit 03e84ef

Browse files
committed
8256189: Exact VarHandle tests should test withInvokeBehavior() works as expected
Reviewed-by: mcimadamore, chegar
1 parent 300cbaa commit 03e84ef

File tree

3 files changed

+93
-125
lines changed

3 files changed

+93
-125
lines changed

src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
3939
final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase {
4040

4141
static final boolean BE = UNSAFE.isBigEndian();
42-
42+
4343
static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
4444

4545
static final int VM_ALIGN = $BoxType$.BYTES - 1;
@@ -66,7 +66,7 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
6666
public MemoryAccessVarHandle$Type$Helper withInvokeBehavior() {
6767
return !hasInvokeExactBehavior() ?
6868
this :
69-
new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, true);
69+
new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, false);
7070
}
7171

7272
#if[floatingPoint]

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/Utils.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,17 @@
3838
import java.util.Optional;
3939
import java.util.function.Supplier;
4040

41+
import static sun.security.action.GetPropertyAction.*;
42+
4143
/**
4244
* This class contains misc helper functions to support creation of memory segments.
4345
*/
4446
public final class Utils {
4547

48+
// used when testing invoke exact behavior of memory access handles
49+
private static final boolean SHOULD_ADAPT_HANDLES
50+
= Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
51+
4652
private static final String foreignRestrictedAccess = Optional.ofNullable(VM.getSavedProperty("foreign.restricted"))
4753
.orElse("deny");
4854

@@ -72,7 +78,9 @@ public static long bitsToBytesOrThrow(long bits, Supplier<RuntimeException> exFa
7278
public static VarHandle fixUpVarHandle(VarHandle handle) {
7379
// This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
7480
// and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
75-
return MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER);
81+
return SHOULD_ADAPT_HANDLES
82+
? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
83+
: handle;
7684
}
7785

7886
private static MemorySegmentProxy filterSegment(MemorySegment segment) {

test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java

Lines changed: 82 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,31 @@
2424
/*
2525
* @test
2626
* @modules jdk.incubator.foreign
27+
* java.base/jdk.internal.access.foreign
2728
*
28-
* @run testng/othervm -Xverify:all VarHandleTestExact
29-
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact
30-
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestExact
31-
* @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact
29+
* @run testng/othervm -Xverify:all
30+
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
31+
* VarHandleTestExact
32+
* @run testng/othervm -Xverify:all
33+
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
34+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true
35+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true
36+
* VarHandleTestExact
37+
* @run testng/othervm -Xverify:all
38+
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
39+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false
40+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false
41+
* VarHandleTestExact
42+
* @run testng/othervm -Xverify:all
43+
* -Djdk.internal.foreign.SHOULD_ADAPT_HANDLES=false
44+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false
45+
* -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true
46+
* VarHandleTestExact
3247
*/
3348

34-
import jdk.incubator.foreign.MemoryAddress;
3549
import jdk.incubator.foreign.MemoryHandles;
3650
import jdk.incubator.foreign.MemorySegment;
51+
import jdk.internal.access.foreign.MemorySegmentProxy;
3752
import org.testng.SkipException;
3853
import org.testng.annotations.DataProvider;
3954
import org.testng.annotations.Test;
@@ -46,6 +61,7 @@
4661
import java.nio.ByteOrder;
4762
import java.util.ArrayList;
4863
import java.util.List;
64+
import java.util.function.Consumer;
4965

5066
import static org.testng.Assert.*;
5167

@@ -80,24 +96,12 @@ public void testExactSet(String fieldBaseName, Class<?> fieldType, boolean ro, O
8096
throws NoSuchFieldException, IllegalAccessException {
8197
if (ro) throw new SkipException("Can not test setter with read only field");
8298
VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + "_RW", fieldType);
83-
assertFalse(vh.hasInvokeExactBehavior());
8499
Widget w = new Widget();
85100

86-
try {
87-
vh.set(w, testValue);
88-
vh.withInvokeBehavior().set(w, testValue);
89-
} catch (WrongMethodTypeException wmte) {
90-
fail("Unexpected exception", wmte);
91-
}
92-
93-
vh = vh.withInvokeExactBehavior();
94-
assertTrue(vh.hasInvokeExactBehavior());
95-
try {
96-
setter.set(vh, w, testValue); // should throw
97-
fail("Exception expected");
98-
} catch (WrongMethodTypeException wmte) {
99-
assertMatches(wmte.getMessage(),".*\\Qexpected (Widget," + fieldType.getSimpleName() + ")void \\E.*");
100-
}
101+
doTest(vh,
102+
tvh -> tvh.set(w, testValue),
103+
tvh -> setter.set(tvh, w, testValue),
104+
".*\\Qexpected (Widget," + fieldType.getSimpleName() + ")void \\E.*");
101105
}
102106

103107
@Test(dataProvider = "dataObjectAccess")
@@ -106,24 +110,12 @@ public void testExactGet(String fieldBaseName, Class<?> fieldType, boolean ro, O
106110
SetStaticX staticSetter, GetStaticX staticGetter)
107111
throws NoSuchFieldException, IllegalAccessException {
108112
VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + (ro ? "_RO" : "_RW"), fieldType);
109-
assertFalse(vh.hasInvokeExactBehavior());
110113
Widget w = new Widget();
111114

112-
try {
113-
Object o = vh.get(w);
114-
Object o2 = vh.withInvokeBehavior().get(w);
115-
} catch (WrongMethodTypeException wmte) {
116-
fail("Unexpected exception", wmte);
117-
}
118-
119-
vh = vh.withInvokeExactBehavior();
120-
assertTrue(vh.hasInvokeExactBehavior());
121-
try {
122-
getter.get(vh, w); // should throw
123-
fail("Exception expected");
124-
} catch (WrongMethodTypeException wmte) {
125-
assertMatches(wmte.getMessage(),".*\\Qexpected (Widget)" + fieldType.getSimpleName() + " \\E.*");
126-
}
115+
doTest(vh,
116+
tvh -> tvh.get(w),
117+
tvh -> getter.get(tvh, w),
118+
".*\\Qexpected (Widget)" + fieldType.getSimpleName() + " \\E.*");
127119
}
128120

129121
@Test(dataProvider = "dataObjectAccess")
@@ -133,23 +125,11 @@ public void testExactSetStatic(String fieldBaseName, Class<?> fieldType, boolean
133125
throws NoSuchFieldException, IllegalAccessException {
134126
if (ro) throw new SkipException("Can not test setter with read only field");
135127
VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + "_SRW", fieldType);
136-
assertFalse(vh.hasInvokeExactBehavior());
137-
138-
try {
139-
vh.set(testValue);
140-
vh.withInvokeBehavior().set(testValue);
141-
} catch (WrongMethodTypeException wmte) {
142-
fail("Unexpected exception", wmte);
143-
}
144128

145-
vh = vh.withInvokeExactBehavior();
146-
assertTrue(vh.hasInvokeExactBehavior());
147-
try {
148-
staticSetter.set(vh, testValue); // should throw
149-
fail("Exception expected");
150-
} catch (WrongMethodTypeException wmte) {
151-
assertMatches(wmte.getMessage(),".*\\Qexpected (" + fieldType.getSimpleName() + ")void \\E.*");
152-
}
129+
doTest(vh,
130+
tvh -> tvh.set(testValue),
131+
tvh -> staticSetter.set(tvh, testValue),
132+
".*\\Qexpected (" + fieldType.getSimpleName() + ")void \\E.*");
153133
}
154134

155135
@Test(dataProvider = "dataObjectAccess")
@@ -158,94 +138,74 @@ public void testExactGetStatic(String fieldBaseName, Class<?> fieldType, boolean
158138
SetStaticX staticSetter, GetStaticX staticGetter)
159139
throws NoSuchFieldException, IllegalAccessException {
160140
VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + (ro ? "_SRO" : "_SRW"), fieldType);
161-
assertFalse(vh.hasInvokeExactBehavior());
162-
163-
try {
164-
Object o = vh.get();
165-
Object o2 = vh.withInvokeBehavior().get();
166-
} catch (WrongMethodTypeException wmte) {
167-
fail("Unexpected exception", wmte);
168-
}
169141

170-
vh = vh.withInvokeExactBehavior();
171-
assertTrue(vh.hasInvokeExactBehavior());
172-
try {
173-
staticGetter.get(vh); // should throw
174-
fail("Exception expected");
175-
} catch (WrongMethodTypeException wmte) {
176-
assertMatches(wmte.getMessage(),".*\\Qexpected ()" + fieldType.getSimpleName() + " \\E.*");
177-
}
142+
doTest(vh,
143+
tvh -> tvh.get(),
144+
tvh -> staticGetter.get(tvh),
145+
".*\\Qexpected ()" + fieldType.getSimpleName() + " \\E.*");
178146
}
179147

180148
@Test(dataProvider = "dataSetArray")
181149
public void testExactArraySet(Class<?> arrayClass, Object testValue, SetArrayX setter) {
182150
VarHandle vh = MethodHandles.arrayElementVarHandle(arrayClass);
183151
Object arr = Array.newInstance(arrayClass.componentType(), 1);
184-
assertFalse(vh.hasInvokeExactBehavior());
185-
186-
try {
187-
vh.set(arr, 0, testValue);
188-
vh.withInvokeBehavior().set(arr, 0, testValue);
189-
} catch (WrongMethodTypeException wmte) {
190-
fail("Unexpected exception", wmte);
191-
}
192152

193-
vh = vh.withInvokeExactBehavior();
194-
assertTrue(vh.hasInvokeExactBehavior());
195-
try {
196-
setter.set(vh, arr, testValue); // should throw
197-
fail("Exception expected");
198-
} catch (WrongMethodTypeException wmte) {
199-
assertMatches(wmte.getMessage(),
200-
".*\\Qexpected (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
201-
}
153+
doTest(vh,
154+
tvh -> tvh.set(arr, 0, testValue),
155+
tvh -> setter.set(tvh, arr, testValue),
156+
".*\\Qexpected (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
202157
}
203158

204159
@Test(dataProvider = "dataSetBuffer")
205160
public void testExactBufferSet(Class<?> arrayClass, Object testValue, SetBufferX setter) {
206161
VarHandle vh = MethodHandles.byteBufferViewVarHandle(arrayClass, ByteOrder.nativeOrder());
207-
assertFalse(vh.hasInvokeExactBehavior());
208162
ByteBuffer buff = ByteBuffer.allocateDirect(8);
209163

164+
doTest(vh,
165+
tvh -> tvh.set(buff, 0, testValue),
166+
tvh -> setter.set(tvh, buff, testValue),
167+
".*\\Qexpected (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
168+
}
169+
170+
@Test(dataProvider = "dataSetMemorySegment")
171+
public void testExactSegmentSet(Class<?> carrier, Object testValue, SetSegmentX setter) {
172+
VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder());
173+
try (MemorySegment seg = MemorySegment.allocateNative(8)) {
174+
175+
doTest(vh,
176+
tvh -> tvh.set(seg, 0L, testValue),
177+
tvh -> setter.set(tvh, seg, 0L, testValue),
178+
".*\\Qexpected (MemorySegmentProxy,long," + carrier.getSimpleName() + ")void \\E.*");
179+
}
180+
}
181+
182+
private static void doTest(VarHandle invokeHandle, Consumer<VarHandle> invokeTest,
183+
Consumer<VarHandle> invokeExactTest, String expectedMessage) {
184+
assertFalse(invokeHandle.hasInvokeExactBehavior());
185+
assertSame(invokeHandle, invokeHandle.withInvokeBehavior());
210186
try {
211-
vh.set(buff, 0, testValue);
212-
vh.withInvokeBehavior().set(buff, 0, testValue);
187+
invokeTest.accept(invokeHandle);
213188
} catch (WrongMethodTypeException wmte) {
214189
fail("Unexpected exception", wmte);
215190
}
216191

217-
vh = vh.withInvokeExactBehavior();
218-
assertTrue(vh.hasInvokeExactBehavior());
192+
VarHandle invokeExactHandle = invokeHandle.withInvokeExactBehavior();
193+
assertTrue(invokeExactHandle.hasInvokeExactBehavior());
194+
assertSame(invokeExactHandle, invokeExactHandle.withInvokeExactBehavior());
219195
try {
220-
setter.set(vh, buff, testValue); // should throw
196+
invokeExactTest.accept(invokeExactHandle); // should throw
221197
fail("Exception expected");
222198
} catch (WrongMethodTypeException wmte) {
223-
assertMatches(wmte.getMessage(),
224-
".*\\Qexpected (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*");
199+
assertMatches(wmte.getMessage(), expectedMessage);
225200
}
226-
}
227201

228-
@Test(dataProvider = "dataSetMemorySegment")
229-
public void testExactSegmentSet(Class<?> carrier, Object testValue, SetSegmentX setter) {
230-
VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder());
231-
assertFalse(vh.hasInvokeExactBehavior());
232-
try (MemorySegment seg = MemorySegment.allocateNative(8)) {
233-
try {
234-
vh.set(seg, 0L, testValue);
235-
vh.withInvokeBehavior().set(seg, 0L, testValue);
236-
} catch (WrongMethodTypeException wmte) {
237-
fail("Unexpected exception", wmte);
238-
}
239-
240-
vh = vh.withInvokeExactBehavior();
241-
assertTrue(vh.hasInvokeExactBehavior());
242-
try {
243-
setter.set(vh, seg, 0L, testValue); // should throw
244-
fail("Exception expected");
245-
} catch (WrongMethodTypeException wmte) {
246-
assertMatches(wmte.getMessage(),
247-
".*\\Qexpected (MemorySegment,long," + carrier.getSimpleName() + ")void \\E.*");
248-
}
202+
// try going back
203+
VarHandle invokeHandle2 = invokeExactHandle.withInvokeBehavior();
204+
assertFalse(invokeHandle2.hasInvokeExactBehavior());
205+
try {
206+
invokeTest.accept(invokeHandle2);
207+
} catch (WrongMethodTypeException wmte) {
208+
fail("Unexpected exception", wmte);
249209
}
250210
}
251211

@@ -280,7 +240,7 @@ private interface SetBufferX {
280240
}
281241

282242
private interface SetSegmentX {
283-
void set(VarHandle vh, MemorySegment segment, long offser, Object testValue);
243+
void set(VarHandle vh, MemorySegment segment, long offset, Object testValue);
284244
}
285245

286246
private static void consume(Object o) {}
@@ -417,11 +377,11 @@ public static Object[][] dataSetMemorySegment() {
417377
List<Object[]> cases = new ArrayList<>();
418378

419379
// create a bunch of different sig-poly call sites
420-
testCaseSegmentSet(cases, long.class, 1234, (vh, seg, off, tv) -> vh.set(seg, off, (int) tv));
421-
testCaseSegmentSet(cases, long.class, (char) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (char) tv));
422-
testCaseSegmentSet(cases, long.class, (short) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (short) tv));
423-
testCaseSegmentSet(cases, long.class, (byte) 1234, (vh, seg, off, tv) -> vh.set(seg, off, (byte) tv));
424-
testCaseSegmentSet(cases, double.class, 1234F, (vh, seg, off, tv) -> vh.set(seg, off, (float) tv));
380+
testCaseSegmentSet(cases, long.class, 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (int) tv));
381+
testCaseSegmentSet(cases, long.class, (char) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (char) tv));
382+
testCaseSegmentSet(cases, long.class, (short) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (short) tv));
383+
testCaseSegmentSet(cases, long.class, (byte) 1234, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (byte) tv));
384+
testCaseSegmentSet(cases, double.class, 1234F, (vh, seg, off, tv) -> vh.set((MemorySegmentProxy) seg, off, (float) tv));
425385

426386
return cases.toArray(Object[][]::new);
427387
}

0 commit comments

Comments
 (0)