Skip to content

Commit

Permalink
8254354: Add a withInvokeExactBehavior() VarHandle combinator
Browse files Browse the repository at this point in the history
Reviewed-by: psandoz, chegar
  • Loading branch information
JornVernee committed Nov 10, 2020
1 parent d6f1463 commit 0a41ca6
Show file tree
Hide file tree
Showing 12 changed files with 1,606 additions and 405 deletions.
Expand Up @@ -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();
Expand All @@ -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
Expand All @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions src/java.base/share/classes/java/lang/invoke/Invokers.java
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -202,6 +208,9 @@ byte[] generateClassBytes() {

addCarrierAccessor(cw);

addAsExact(cw);
addAsGeneric(cw);

for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
addAccessModeMethodIfNeeded(mode, cw);
}
Expand Down Expand Up @@ -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");
Expand All @@ -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());
Expand Down Expand Up @@ -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) {
Expand All @@ -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.
*/
Expand Down

1 comment on commit 0a41ca6

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.