# HG changeset patch # User redestad # Date 1471607403 -7200 # Node ID 20e2e4b25a400a70d6085e1ceac0b08179be461f # Parent fb874cf2497478560450cf19e7e2585446485e61 8164451: Generate all zero and identity forms at link time Reviewed-by: shade, mhaupt, vlivanov diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Fri Aug 19 13:50:03 2016 +0200 @@ -38,6 +38,34 @@ */ class GenerateJLIClassesHelper { + static byte[] generateBasicFormsClassBytes(String className) { + ArrayList forms = new ArrayList<>(); + ArrayList names = new ArrayList<>(); + HashSet dedupSet = new HashSet<>(); + for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) { + LambdaForm zero = LambdaForm.zeroForm(type); + String name = zero.kind.defaultLambdaName + + "_" + zero.returnType().basicTypeChar(); + // since zero is the same as identity for Void, we deduplicate + // aggressively to guard against this specifically and not get + // caught on future equivalences + if (dedupSet.add(name)) { + names.add(name); + forms.add(zero); + } + LambdaForm identity = LambdaForm.identityForm(type); + name = identity.kind.defaultLambdaName + + "_" + identity.returnType().basicTypeChar(); + if (dedupSet.add(name)) { + names.add(name); + forms.add(identity); + } + } + return generateCodeBytesForLFs(className, + names.toArray(new String[0]), + forms.toArray(new LambdaForm[0])); + } + static byte[] generateDirectMethodHandleHolderClassBytes(String className, MethodType[] methodTypes, int[] types) { LambdaForm[] forms = new LambdaForm[methodTypes.length]; diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Aug 19 13:50:03 2016 +0200 @@ -624,6 +624,11 @@ return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class); } case DELEGATE: return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class); + case ZERO: // fall-through + case IDENTITY: { + name = name + "_" + form.returnType().basicTypeChar(); + return resolveFrom(name, invokerType, LambdaForm.Holder.class); + } case DIRECT_INVOKE_INTERFACE: // fall-through case DIRECT_INVOKE_SPECIAL: // fall-through case DIRECT_INVOKE_STATIC: // fall-through diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Fri Aug 19 13:50:03 2016 +0200 @@ -270,6 +270,8 @@ enum Kind { GENERIC(""), + ZERO("zero"), + IDENTITY("identity"), BOUND_REINVOKER("BMH.reinvoke"), REINVOKER("MH.reinvoke"), DELEGATE("MH.delegate"), @@ -1848,7 +1850,7 @@ // bootstrap dependency on this method in case we're interpreting LFs if (isVoid) { Name[] idNames = new Name[] { argument(0, L_TYPE) }; - idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT); + idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT, Kind.IDENTITY); idForm.compileToBytecode(); idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm)); @@ -1856,13 +1858,13 @@ zeFun = idFun; } else { Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) }; - idForm = new LambdaForm(idMem.getName(), 2, idNames, 1); + idForm = new LambdaForm(idMem.getName(), 2, idNames, 1, Kind.IDENTITY); idForm.compileToBytecode(); idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm)); Object zeValue = Wrapper.forBasicType(btChar).zero(); Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) }; - zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1); + zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1, Kind.ZERO); zeForm.compileToBytecode(); zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm)); } @@ -1921,8 +1923,17 @@ if (USE_PREDEFINED_INTERPRET_METHODS) computeInitialPreparedForms(); NamedFunction.initializeInvokers(); + + // The Holder class will contain pre-generated forms resolved + // using MemberName.getFactory(). However, that doesn't initialize the + // class, which subtly breaks inlining etc. By forcing + // initialization of the Holder class we avoid these issues. + UNSAFE.ensureClassInitialized(Holder.class); } + /* Placeholder class for zero and identity forms generated ahead of time */ + final class Holder {} + // The following hack is necessary in order to suppress TRACE_INTERPRETER // during execution of the static initializes of this class. // Turning on TRACE_INTERPRETER too early will cause diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Aug 19 13:50:03 2016 +0200 @@ -1739,6 +1739,12 @@ return GenerateJLIClassesHelper .generateConcreteBMHClassBytes(types); } + + @Override + public byte[] generateBasicFormsClassBytes(final String className) { + return GenerateJLIClassesHelper + .generateBasicFormsClassBytes(className); + } }); } diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Fri Aug 19 13:50:03 2016 +0200 @@ -72,4 +72,10 @@ */ Map.Entry generateConcreteBMHClassBytes( final String types); + + /** + * Returns a {@code byte[]} containing the bytecode for a class implementing + * the zero and identity forms of all {@code LambdaForm.BasicType}s. + */ + byte[] generateBasicFormsClassBytes(final String className); } diff -r fb874cf24974 -r 20e2e4b25a40 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Fri Aug 19 10:03:43 2016 +0200 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Fri Aug 19 13:50:03 2016 +0200 @@ -65,6 +65,8 @@ private static final String DELEGATING_METHOD_HANDLE = "java/lang/invoke/DelegatingMethodHandle$Holder"; + private static final String BASIC_FORMS_HANDLE = "java/lang/invoke/LambdaForm$Holder"; + private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); @@ -227,14 +229,15 @@ in.transformAndCopy(entry -> { // filter out placeholder entries if (entry.path().equals(DIRECT_METHOD_HANDLE_ENTRY) || - entry.path().equals(DELEGATING_METHOD_HANDLE_ENTRY)) { + entry.path().equals(DELEGATING_METHOD_HANDLE_ENTRY) || + entry.path().equals(BASIC_FORMS_HANDLE_ENTRY)) { return null; } else { return entry; } }, out); speciesTypes.forEach(types -> generateBMHClass(types, out)); - generateDMHClass(out); + generateHolderClasses(out); return out.build(); } @@ -257,7 +260,7 @@ } } - private void generateDMHClass(ResourcePoolBuilder out) { + private void generateHolderClasses(ResourcePoolBuilder out) { int count = 0; for (List entry : dmhMethods.values()) { count += entry.size(); @@ -284,6 +287,10 @@ DELEGATING_METHOD_HANDLE, methodTypes); ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HANDLE_ENTRY, bytes); out.add(ndata); + + bytes = JLIA.generateBasicFormsClassBytes(BASIC_FORMS_HANDLE); + ndata = ResourcePoolEntry.create(BASIC_FORMS_HANDLE_ENTRY, bytes); + out.add(ndata); } catch (Exception ex) { throw new PluginException(ex); } @@ -292,6 +299,8 @@ "/java.base/" + DIRECT_METHOD_HANDLE + ".class"; private static final String DELEGATING_METHOD_HANDLE_ENTRY = "/java.base/" + DELEGATING_METHOD_HANDLE + ".class"; + private static final String BASIC_FORMS_HANDLE_ENTRY = + "/java.base/" + BASIC_FORMS_HANDLE + ".class"; // Convert LL -> LL, L3 -> LLL private static String expandSignature(String signature) {