Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8254354: Add a withInvokeExactBehavior() VarHandle combinator #843

Closed
wants to merge 19 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -53,7 +53,12 @@
private final Class<?>[] coordinates;

IndirectVarHandle(VarHandle target, Class<?> value, Class<?>[] coordinates, BiFunction<AccessMode, MethodHandle, MethodHandle> handleFactory) {
super(new VarForm(value, coordinates));
this(target, value, coordinates, handleFactory, new VarForm(value, coordinates), false);
}

private IndirectVarHandle(VarHandle target, Class<?> value, Class<?>[] coordinates,
BiFunction<AccessMode, MethodHandle, MethodHandle> handleFactory, VarForm form, boolean exact) {
super(form, exact);
this.handleFactory = handleFactory;
this.target = target;
this.directTarget = target.asDirect();
@@ -72,8 +77,8 @@ public List<Class<?>> coordinateTypes() {
}

@Override
MethodType accessModeTypeUncached(AccessMode accessMode) {
return accessMode.at.accessModeType(directTarget.getClass(), value, coordinates);
MethodType accessModeTypeUncached(AccessType at) {
return at.accessModeType(null, value, coordinates);
}

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

@Override
public VarHandle withInvokeExactBehavior() {
return hasInvokeExactBehavior()
? this
: new IndirectVarHandle(target, value, coordinates, handleFactory, vform, true);
}

@Override
public VarHandle withInvokeBehavior() {
return !hasInvokeExactBehavior()
? this
: new IndirectVarHandle(target, value, coordinates, handleFactory, vform, false);
}

@Override
@ForceInline
MethodHandle getMethodHandle(int mode) {
6 changes: 6 additions & 0 deletions src/java.base/share/classes/java/lang/invoke/Invokers.java
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@

import jdk.internal.vm.annotation.DontInline;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Hidden;
import jdk.internal.vm.annotation.Stable;

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

@ForceInline
/*non-public*/
@Hidden
static MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) {
if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) {
throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found "
+ ad.symbolicMethodTypeExact);
}
// Test for exact match on invoker types
// TODO match with erased types and add cast of return value to lambda form
MethodHandle mh = handle.getMethodHandle(ad.mode);
Original file line number Diff line number Diff line change
@@ -42,8 +42,8 @@ abstract class MemoryAccessVarHandleBase extends VarHandle {
/** alignment constraint (in bytes, expressed as a bit mask) **/
final long alignmentMask;

MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask) {
super(form);
MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask, boolean exact) {
super(form, exact);
this.be = be;
this.length = length;
this.offset = offset;
Original file line number Diff line number Diff line change
@@ -71,6 +71,7 @@
import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
@@ -95,6 +96,12 @@ class MemoryAccessVarHandleGenerator {
private final static MethodHandle ADD_OFFSETS_HANDLE;
private final static MethodHandle MUL_OFFSETS_HANDLE;

private final static MethodType CONSTR_TYPE = MethodType.methodType(void.class, VarForm.class,
boolean.class, long.class, long.class, long.class, boolean.class, long[].class);
// MemoryAccessVarHandleBase
private final static MethodType SUPER_CONTR_TYPE = MethodType.methodType(void.class, VarForm.class,
boolean.class, long.class, long.class, long.class, boolean.class);

static {
helperClassCache = new HashMap<>();
helperClassCache.put(byte.class, MemoryAccessVarHandleByteHelper.class);
@@ -140,7 +147,7 @@ class MemoryAccessVarHandleGenerator {
Arrays.fill(components, long.class);
this.form = new VarForm(BASE_CLASS, MemoryAddressProxy.class, carrier, components);
this.helperClass = helperClassCache.get(carrier);
this.implClassName = helperClass.getName().replace('.', '/') + dimensions;
this.implClassName = internalName(helperClass) + dimensions;
// live constants
Class<?>[] intermediate = new Class<?>[dimensions];
Arrays.fill(intermediate, long.class);
@@ -164,8 +171,7 @@ MethodHandle generateHandleFactory() {

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

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

addCarrierAccessor(cw);

addAsExact(cw);
addAsGeneric(cw);

for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
addAccessModeMethodIfNeeded(mode, cw);
}
@@ -253,23 +262,23 @@ void addStaticInitializer(ClassWriter cw) {
}

void addConstructor(ClassWriter cw) {
MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
MethodVisitor mv = cw.visitMethod(0, "<init>", constrType.toMethodDescriptorString(), null, null);
MethodVisitor mv = cw.visitMethod(0, "<init>", CONSTR_TYPE.toMethodDescriptorString(), null, null);
mv.visitCode();
//super call
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 1); // vform
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VarForm.class));
mv.visitVarInsn(ILOAD, 2);
mv.visitVarInsn(LLOAD, 3);
mv.visitVarInsn(LLOAD, 5);
mv.visitVarInsn(LLOAD, 7);
mv.visitVarInsn(ILOAD, 2); // be
mv.visitVarInsn(LLOAD, 3); // length
mv.visitVarInsn(LLOAD, 5); // offset
mv.visitVarInsn(LLOAD, 7); // alignmentMask
mv.visitVarInsn(ILOAD, 9); // exact
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(BASE_CLASS), "<init>",
MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class).toMethodDescriptorString(), false);
SUPER_CONTR_TYPE.toMethodDescriptorString(), false);
//init dimensions
for (int i = 0 ; i < dimensions ; i++) {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 9);
mv.visitVarInsn(ALOAD, 10);
mv.visitLdcInsn(i);
mv.visitInsn(LALOAD);
mv.visitFieldInsn(PUTFIELD, implClassName, "dim" + i, "J");
@@ -280,11 +289,10 @@ void addConstructor(ClassWriter cw) {
}

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

private void addAsExact(ClassWriter cw) {
addAsExactOrAsGeneric(cw, "asExact", true);
}

private void addAsGeneric(ClassWriter cw) {
addAsExactOrAsGeneric(cw, "asGeneric", false);
}

private void addAsExactOrAsGeneric(ClassWriter cw, String name, boolean exact) {
MethodVisitor mv = cw.visitMethod(ACC_FINAL, name, "()Ljava/lang/invoke/VarHandle;", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, implClassName);
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, internalName(VarHandle.class), "vform", VarForm.class.descriptorString());
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "be", boolean.class.descriptorString());
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "length", long.class.descriptorString());
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "offset", long.class.descriptorString());
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "alignmentMask", long.class.descriptorString());
mv.visitIntInsn(BIPUSH, exact ? 1 : 0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, implClassName, "strides", "()[J", false);
mv.visitMethodInsn(INVOKESPECIAL, implClassName, "<init>", CONSTR_TYPE.descriptorString(), false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}

// shared code generation helpers

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

private static String internalName(Class<?> cls) {
return cls.getName().replace('.', '/');
}

/**
* Emits an actual return instruction conforming to the given return type.
*/
Loading