# HG changeset patch # User redestad # Date 1472047774 -7200 # Node ID e7be26f852fab2f34711eabfa68e2430a0019158 # Parent 8850531a2bebd63ff30555f0c38302f2d4c8bde4 8164483: Generate field lambda forms at link time Reviewed-by: vlivanov diff -r 8850531a2beb -r e7be26f852fa jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Aug 24 13:54:17 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Aug 24 16:09:34 2016 +0200 @@ -492,7 +492,7 @@ } // Caching machinery for field accessors: - private static final byte + static final byte AF_GETFIELD = 0, AF_PUTFIELD = 1, AF_GETSTATIC = 2, @@ -502,7 +502,7 @@ AF_LIMIT = 6; // Enumerate the different field kinds using Wrapper, // with an extra case added for checked references. - private static final int + static final int FT_LAST_WRAPPER = Wrapper.COUNT-1, FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(), FT_CHECKED_REF = FT_LAST_WRAPPER+1, @@ -515,7 +515,7 @@ @Stable private static final LambdaForm[] ACCESSOR_FORMS = new LambdaForm[afIndex(AF_LIMIT, false, 0)]; - private static int ftypeKind(Class ftype) { + static int ftypeKind(Class ftype) { if (ftype.isPrimitive()) return Wrapper.forPrimitiveType(ftype).ordinal(); else if (VerifyType.isNullReferenceConversion(Object.class, ftype)) @@ -566,7 +566,64 @@ private static final Wrapper[] ALL_WRAPPERS = Wrapper.values(); - private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) { + private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) { + if (isGetter) { + if (isVolatile) { + switch (wrapper) { + case BOOLEAN: return GET_BOOLEAN_VOLATILE; + case BYTE: return GET_BYTE_VOLATILE; + case SHORT: return GET_SHORT_VOLATILE; + case CHAR: return GET_CHAR_VOLATILE; + case INT: return GET_INT_VOLATILE; + case LONG: return GET_LONG_VOLATILE; + case FLOAT: return GET_FLOAT_VOLATILE; + case DOUBLE: return GET_DOUBLE_VOLATILE; + case OBJECT: return GET_OBJECT_VOLATILE; + } + } else { + switch (wrapper) { + case BOOLEAN: return GET_BOOLEAN; + case BYTE: return GET_BYTE; + case SHORT: return GET_SHORT; + case CHAR: return GET_CHAR; + case INT: return GET_INT; + case LONG: return GET_LONG; + case FLOAT: return GET_FLOAT; + case DOUBLE: return GET_DOUBLE; + case OBJECT: return GET_OBJECT; + } + } + } else { + if (isVolatile) { + switch (wrapper) { + case BOOLEAN: return PUT_BOOLEAN_VOLATILE; + case BYTE: return PUT_BYTE_VOLATILE; + case SHORT: return PUT_SHORT_VOLATILE; + case CHAR: return PUT_CHAR_VOLATILE; + case INT: return PUT_INT_VOLATILE; + case LONG: return PUT_LONG_VOLATILE; + case FLOAT: return PUT_FLOAT_VOLATILE; + case DOUBLE: return PUT_DOUBLE_VOLATILE; + case OBJECT: return PUT_OBJECT_VOLATILE; + } + } else { + switch (wrapper) { + case BOOLEAN: return PUT_BOOLEAN; + case BYTE: return PUT_BYTE; + case SHORT: return PUT_SHORT; + case CHAR: return PUT_CHAR; + case INT: return PUT_INT; + case LONG: return PUT_LONG; + case FLOAT: return PUT_FLOAT; + case DOUBLE: return PUT_DOUBLE; + case OBJECT: return PUT_OBJECT; + } + } + } + throw new AssertionError("Invalid arguments"); + } + + static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) { boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1); boolean isStatic = (formOp >= AF_GETSTATIC); boolean needsInit = (formOp >= AF_GETSTATIC_INIT); @@ -576,24 +633,14 @@ assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind); // getObject, putIntVolatile, etc. - StringBuilder nameBuilder = new StringBuilder(); - if (isGetter) { - nameBuilder.append("get"); - } else { - nameBuilder.append("put"); - } - nameBuilder.append(fw.primitiveSimpleName()); - nameBuilder.setCharAt(3, Character.toUpperCase(nameBuilder.charAt(3))); - if (isVolatile) { - nameBuilder.append("Volatile"); - } + Kind kind = getFieldKind(isGetter, isVolatile, fw); MethodType linkerType; if (isGetter) linkerType = MethodType.methodType(ft, Object.class, long.class); else linkerType = MethodType.methodType(void.class, Object.class, long.class, ft); - MemberName linker = new MemberName(Unsafe.class, nameBuilder.toString(), linkerType, REF_invokeVirtual); + MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual); try { linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class); } catch (ReflectiveOperationException ex) { @@ -620,6 +667,7 @@ final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any final int F_OFFSET = nameCursor++; // Either static offset or field offset. final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1); + final int U_HOLDER = nameCursor++; // UNSAFE holder final int INIT_BAR = (needsInit ? nameCursor++ : -1); final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1); final int LINKER_CALL = nameCursor++; @@ -632,7 +680,7 @@ names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]); Object[] outArgs = new Object[1 + linkerType.parameterCount()]; assert(outArgs.length == (isGetter ? 3 : 4)); - outArgs[0] = UNSAFE; + outArgs[0] = names[U_HOLDER] = new Name(NF_UNSAFE); if (isStatic) { outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]); outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]); @@ -650,6 +698,7 @@ for (Name n : names) assert(n != null); // add some detail to the lambdaForm debugname, // significant only for debugging + StringBuilder nameBuilder = new StringBuilder(kind.methodName); if (isStatic) { nameBuilder.append("Static"); } else { @@ -657,7 +706,12 @@ } if (needsCast) nameBuilder.append("Cast"); if (needsInit) nameBuilder.append("Init"); - return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT); + if (needsCast || needsInit) { + // can't use the pre-generated form when casting and/or initializing + return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT); + } else { + return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT, kind); + } } /** @@ -674,7 +728,8 @@ NF_staticOffset, NF_checkCast, NF_allocateInstance, - NF_constructorMethod; + NF_constructorMethod, + NF_UNSAFE; static { try { NamedFunction nfs[] = { @@ -697,7 +752,9 @@ NF_allocateInstance = new NamedFunction(DirectMethodHandle.class .getDeclaredMethod("allocateInstance", Object.class)), NF_constructorMethod = new NamedFunction(DirectMethodHandle.class - .getDeclaredMethod("constructorMethod", Object.class)) + .getDeclaredMethod("constructorMethod", Object.class)), + NF_UNSAFE = new NamedFunction(new MemberName(MethodHandleStatics.class + .getDeclaredField("UNSAFE"))) }; // Each nf must be statically invocable or we get tied up in our bootstraps. assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs)); diff -r 8850531a2beb -r e7be26f852fa jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Aug 24 13:54:17 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Aug 24 16:09:34 2016 +0200 @@ -28,9 +28,11 @@ import java.util.Map; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; - import java.util.ArrayList; import java.util.HashSet; +import sun.invoke.util.Wrapper; + +import static java.lang.invoke.MethodHandleNatives.Constants.*; /** * Helper class to assist the GenerateJLIClassesPlugin to get access to @@ -66,14 +68,38 @@ static byte[] generateDirectMethodHandleHolderClassBytes(String className, MethodType[] methodTypes, int[] types) { - LambdaForm[] forms = new LambdaForm[methodTypes.length]; - String[] names = new String[methodTypes.length]; - for (int i = 0; i < forms.length; i++) { - forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i], - types[i]); - names[i] = forms[i].kind.defaultLambdaName; + ArrayList forms = new ArrayList<>(); + ArrayList names = new ArrayList<>(); + for (int i = 0; i < methodTypes.length; i++) { + LambdaForm form = DirectMethodHandle + .makePreparedLambdaForm(methodTypes[i], types[i]); + forms.add(form); + names.add(form.kind.defaultLambdaName); } - return generateCodeBytesForLFs(className, names, forms); + for (Wrapper wrapper : Wrapper.values()) { + if (wrapper == Wrapper.VOID) { + continue; + } + for (byte b = DirectMethodHandle.AF_GETFIELD; b < DirectMethodHandle.AF_LIMIT; b++) { + int ftype = DirectMethodHandle.ftypeKind(wrapper.primitiveType()); + LambdaForm form = DirectMethodHandle + .makePreparedFieldLambdaForm(b, /*isVolatile*/false, ftype); + if (form.kind != LambdaForm.Kind.GENERIC) { + forms.add(form); + names.add(form.kind.defaultLambdaName); + } + // volatile + form = DirectMethodHandle + .makePreparedFieldLambdaForm(b, /*isVolatile*/true, ftype); + if (form.kind != LambdaForm.Kind.GENERIC) { + forms.add(form); + names.add(form.kind.defaultLambdaName); + } + } + } + return generateCodeBytesForLFs(className, + names.toArray(new String[0]), + forms.toArray(new LambdaForm[0])); } static byte[] generateDelegatingMethodHandleHolderClassBytes(String className, @@ -166,4 +192,5 @@ BoundMethodHandle.Factory.generateConcreteBMHClassBytes( shortTypes, types, className)); } + } diff -r 8850531a2beb -r e7be26f852fa jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Aug 24 13:54:17 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Aug 24 16:09:34 2016 +0200 @@ -629,6 +629,24 @@ name = name + "_" + form.returnType().basicTypeChar(); return resolveFrom(name, invokerType, LambdaForm.Holder.class); } + case GET_OBJECT: // fall-through + case GET_BOOLEAN: // fall-through + case GET_BYTE: // fall-through + case GET_CHAR: // fall-through + case GET_SHORT: // fall-through + case GET_INT: // fall-through + case GET_LONG: // fall-through + case GET_FLOAT: // fall-through + case GET_DOUBLE: // fall-through + case PUT_OBJECT: // fall-through + case PUT_BOOLEAN: // fall-through + case PUT_BYTE: // fall-through + case PUT_CHAR: // fall-through + case PUT_SHORT: // fall-through + case PUT_INT: // fall-through + case PUT_LONG: // fall-through + case PUT_FLOAT: // fall-through + case PUT_DOUBLE: // fall-through case DIRECT_INVOKE_INTERFACE: // fall-through case DIRECT_INVOKE_SPECIAL: // fall-through case DIRECT_INVOKE_STATIC: // fall-through diff -r 8850531a2beb -r e7be26f852fa jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug 24 13:54:17 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug 24 16:09:34 2016 +0200 @@ -280,7 +280,43 @@ DIRECT_INVOKE_STATIC("DMH.invokeStatic"), DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial"), DIRECT_INVOKE_INTERFACE("DMH.invokeInterface"), - DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit"); + DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit"), + GET_OBJECT("getObject"), + PUT_OBJECT("putObject"), + GET_OBJECT_VOLATILE("getObjectVolatile"), + PUT_OBJECT_VOLATILE("putObjectVolatile"), + GET_INT("getInt"), + PUT_INT("putInt"), + GET_INT_VOLATILE("getIntVolatile"), + PUT_INT_VOLATILE("putIntVolatile"), + GET_BOOLEAN("getBoolean"), + PUT_BOOLEAN("putBoolean"), + GET_BOOLEAN_VOLATILE("getBooleanVolatile"), + PUT_BOOLEAN_VOLATILE("putBooleanVolatile"), + GET_BYTE("getByte"), + PUT_BYTE("putByte"), + GET_BYTE_VOLATILE("getByteVolatile"), + PUT_BYTE_VOLATILE("putByteVolatile"), + GET_CHAR("getChar"), + PUT_CHAR("putChar"), + GET_CHAR_VOLATILE("getCharVolatile"), + PUT_CHAR_VOLATILE("putCharVolatile"), + GET_SHORT("getShort"), + PUT_SHORT("putShort"), + GET_SHORT_VOLATILE("getShortVolatile"), + PUT_SHORT_VOLATILE("putShortVolatile"), + GET_LONG("getLong"), + PUT_LONG("putLong"), + GET_LONG_VOLATILE("getLongVolatile"), + PUT_LONG_VOLATILE("putLongVolatile"), + GET_FLOAT("getFloat"), + PUT_FLOAT("putFloat"), + GET_FLOAT_VOLATILE("getFloatVolatile"), + PUT_FLOAT_VOLATILE("putFloatVolatile"), + GET_DOUBLE("getDouble"), + PUT_DOUBLE("putDouble"), + GET_DOUBLE_VOLATILE("getDoubleVolatile"), + PUT_DOUBLE_VOLATILE("putDoubleVolatile"); final String defaultLambdaName; final String methodName;