Skip to content

Commit 0a41ca6

Browse files
committed
8254354: Add a withInvokeExactBehavior() VarHandle combinator
Reviewed-by: psandoz, chegar
1 parent d6f1463 commit 0a41ca6

File tree

12 files changed

+1606
-405
lines changed

12 files changed

+1606
-405
lines changed

src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@
5353
private final Class<?>[] coordinates;
5454

5555
IndirectVarHandle(VarHandle target, Class<?> value, Class<?>[] coordinates, BiFunction<AccessMode, MethodHandle, MethodHandle> handleFactory) {
56-
super(new VarForm(value, coordinates));
56+
this(target, value, coordinates, handleFactory, new VarForm(value, coordinates), false);
57+
}
58+
59+
private IndirectVarHandle(VarHandle target, Class<?> value, Class<?>[] coordinates,
60+
BiFunction<AccessMode, MethodHandle, MethodHandle> handleFactory, VarForm form, boolean exact) {
61+
super(form, exact);
5762
this.handleFactory = handleFactory;
5863
this.target = target;
5964
this.directTarget = target.asDirect();
@@ -72,8 +77,8 @@ public List<Class<?>> coordinateTypes() {
7277
}
7378

7479
@Override
75-
MethodType accessModeTypeUncached(AccessMode accessMode) {
76-
return accessMode.at.accessModeType(directTarget.getClass(), value, coordinates);
80+
MethodType accessModeTypeUncached(AccessType at) {
81+
return at.accessModeType(null, value, coordinates);
7782
}
7883

7984
@Override
@@ -90,6 +95,20 @@ VarHandle target() {
9095
return target;
9196
}
9297

98+
@Override
99+
public VarHandle withInvokeExactBehavior() {
100+
return hasInvokeExactBehavior()
101+
? this
102+
: new IndirectVarHandle(target, value, coordinates, handleFactory, vform, true);
103+
}
104+
105+
@Override
106+
public VarHandle withInvokeBehavior() {
107+
return !hasInvokeExactBehavior()
108+
? this
109+
: new IndirectVarHandle(target, value, coordinates, handleFactory, vform, false);
110+
}
111+
93112
@Override
94113
@ForceInline
95114
MethodHandle getMethodHandle(int mode) {

src/java.base/share/classes/java/lang/invoke/Invokers.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import jdk.internal.vm.annotation.DontInline;
2929
import jdk.internal.vm.annotation.ForceInline;
30+
import jdk.internal.vm.annotation.Hidden;
3031
import jdk.internal.vm.annotation.Stable;
3132

3233
import java.lang.reflect.Array;
@@ -463,7 +464,12 @@ private static LambdaForm varHandleMethodInvokerHandleForm(VarHandle.AccessMode
463464

464465
@ForceInline
465466
/*non-public*/
467+
@Hidden
466468
static MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) {
469+
if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) {
470+
throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found "
471+
+ ad.symbolicMethodTypeExact);
472+
}
467473
// Test for exact match on invoker types
468474
// TODO match with erased types and add cast of return value to lambda form
469475
MethodHandle mh = handle.getMethodHandle(ad.mode);

src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ abstract class MemoryAccessVarHandleBase extends VarHandle {
4242
/** alignment constraint (in bytes, expressed as a bit mask) **/
4343
final long alignmentMask;
4444

45-
MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask) {
46-
super(form);
45+
MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask, boolean exact) {
46+
super(form, exact);
4747
this.be = be;
4848
this.length = length;
4949
this.offset = offset;

src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleGenerator.java

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
7272
import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
7373
import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
74+
import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
7475
import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
7576
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
7677
import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
@@ -95,6 +96,12 @@ class MemoryAccessVarHandleGenerator {
9596
private final static MethodHandle ADD_OFFSETS_HANDLE;
9697
private final static MethodHandle MUL_OFFSETS_HANDLE;
9798

99+
private final static MethodType CONSTR_TYPE = MethodType.methodType(void.class, VarForm.class,
100+
boolean.class, long.class, long.class, long.class, boolean.class, long[].class);
101+
// MemoryAccessVarHandleBase
102+
private final static MethodType SUPER_CONTR_TYPE = MethodType.methodType(void.class, VarForm.class,
103+
boolean.class, long.class, long.class, long.class, boolean.class);
104+
98105
static {
99106
helperClassCache = new HashMap<>();
100107
helperClassCache.put(byte.class, MemoryAccessVarHandleByteHelper.class);
@@ -140,7 +147,7 @@ class MemoryAccessVarHandleGenerator {
140147
Arrays.fill(components, long.class);
141148
this.form = new VarForm(BASE_CLASS, MemoryAddressProxy.class, carrier, components);
142149
this.helperClass = helperClassCache.get(carrier);
143-
this.implClassName = helperClass.getName().replace('.', '/') + dimensions;
150+
this.implClassName = internalName(helperClass) + dimensions;
144151
// live constants
145152
Class<?>[] intermediate = new Class<?>[dimensions];
146153
Arrays.fill(intermediate, long.class);
@@ -164,8 +171,7 @@ MethodHandle generateHandleFactory() {
164171

165172
VarForm form = new VarForm(implCls, MemoryAddressProxy.class, carrier, components);
166173

167-
MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
168-
MethodHandle constr = lookup.findConstructor(implCls, constrType);
174+
MethodHandle constr = lookup.findConstructor(implCls, CONSTR_TYPE);
169175
constr = MethodHandles.insertArguments(constr, 0, form);
170176
return constr;
171177
} catch (Throwable ex) {
@@ -202,6 +208,9 @@ byte[] generateClassBytes() {
202208

203209
addCarrierAccessor(cw);
204210

211+
addAsExact(cw);
212+
addAsGeneric(cw);
213+
205214
for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
206215
addAccessModeMethodIfNeeded(mode, cw);
207216
}
@@ -253,23 +262,23 @@ void addStaticInitializer(ClassWriter cw) {
253262
}
254263

255264
void addConstructor(ClassWriter cw) {
256-
MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
257-
MethodVisitor mv = cw.visitMethod(0, "<init>", constrType.toMethodDescriptorString(), null, null);
265+
MethodVisitor mv = cw.visitMethod(0, "<init>", CONSTR_TYPE.toMethodDescriptorString(), null, null);
258266
mv.visitCode();
259267
//super call
260268
mv.visitVarInsn(ALOAD, 0);
261-
mv.visitVarInsn(ALOAD, 1);
269+
mv.visitVarInsn(ALOAD, 1); // vform
262270
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VarForm.class));
263-
mv.visitVarInsn(ILOAD, 2);
264-
mv.visitVarInsn(LLOAD, 3);
265-
mv.visitVarInsn(LLOAD, 5);
266-
mv.visitVarInsn(LLOAD, 7);
271+
mv.visitVarInsn(ILOAD, 2); // be
272+
mv.visitVarInsn(LLOAD, 3); // length
273+
mv.visitVarInsn(LLOAD, 5); // offset
274+
mv.visitVarInsn(LLOAD, 7); // alignmentMask
275+
mv.visitVarInsn(ILOAD, 9); // exact
267276
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(BASE_CLASS), "<init>",
268-
MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class).toMethodDescriptorString(), false);
277+
SUPER_CONTR_TYPE.toMethodDescriptorString(), false);
269278
//init dimensions
270279
for (int i = 0 ; i < dimensions ; i++) {
271280
mv.visitVarInsn(ALOAD, 0);
272-
mv.visitVarInsn(ALOAD, 9);
281+
mv.visitVarInsn(ALOAD, 10);
273282
mv.visitLdcInsn(i);
274283
mv.visitInsn(LALOAD);
275284
mv.visitFieldInsn(PUTFIELD, implClassName, "dim" + i, "J");
@@ -280,11 +289,10 @@ void addConstructor(ClassWriter cw) {
280289
}
281290

282291
void addAccessModeTypeMethod(ClassWriter cw) {
283-
MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessMode.class);
292+
MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessType.class);
284293
MethodVisitor mv = cw.visitMethod(ACC_FINAL, "accessModeTypeUncached", modeMethType.toMethodDescriptorString(), null, null);
285294
mv.visitCode();
286295
mv.visitVarInsn(ALOAD, 1);
287-
mv.visitFieldInsn(GETFIELD, Type.getInternalName(VarHandle.AccessMode.class), "at", VarHandle.AccessType.class.descriptorString());
288296
mv.visitLdcInsn(Type.getType(MemoryAddressProxy.class));
289297
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
290298
mv.visitFieldInsn(GETSTATIC, implClassName, "carrier", Class.class.descriptorString());
@@ -409,6 +417,38 @@ void addCarrierAccessor(ClassWriter cw) {
409417
mv.visitEnd();
410418
}
411419

420+
private void addAsExact(ClassWriter cw) {
421+
addAsExactOrAsGeneric(cw, "asExact", true);
422+
}
423+
424+
private void addAsGeneric(ClassWriter cw) {
425+
addAsExactOrAsGeneric(cw, "asGeneric", false);
426+
}
427+
428+
private void addAsExactOrAsGeneric(ClassWriter cw, String name, boolean exact) {
429+
MethodVisitor mv = cw.visitMethod(ACC_FINAL, name, "()Ljava/lang/invoke/VarHandle;", null, null);
430+
mv.visitCode();
431+
mv.visitTypeInsn(NEW, implClassName);
432+
mv.visitInsn(DUP);
433+
mv.visitVarInsn(ALOAD, 0);
434+
mv.visitFieldInsn(GETFIELD, internalName(VarHandle.class), "vform", VarForm.class.descriptorString());
435+
mv.visitVarInsn(ALOAD, 0);
436+
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "be", boolean.class.descriptorString());
437+
mv.visitVarInsn(ALOAD, 0);
438+
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "length", long.class.descriptorString());
439+
mv.visitVarInsn(ALOAD, 0);
440+
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "offset", long.class.descriptorString());
441+
mv.visitVarInsn(ALOAD, 0);
442+
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "alignmentMask", long.class.descriptorString());
443+
mv.visitIntInsn(BIPUSH, exact ? 1 : 0);
444+
mv.visitVarInsn(ALOAD, 0);
445+
mv.visitMethodInsn(INVOKEVIRTUAL, implClassName, "strides", "()[J", false);
446+
mv.visitMethodInsn(INVOKESPECIAL, implClassName, "<init>", CONSTR_TYPE.descriptorString(), false);
447+
mv.visitInsn(ARETURN);
448+
mv.visitMaxs(0, 0);
449+
mv.visitEnd();
450+
}
451+
412452
// shared code generation helpers
413453

414454
private static int getSlotsForType(Class<?> c) {
@@ -418,6 +458,10 @@ private static int getSlotsForType(Class<?> c) {
418458
return 1;
419459
}
420460

461+
private static String internalName(Class<?> cls) {
462+
return cls.getName().replace('.', '/');
463+
}
464+
421465
/**
422466
* Emits an actual return instruction conforming to the given return type.
423467
*/

0 commit comments

Comments
 (0)