# HG changeset patch # User redestad # Date 1521036642 -3600 # Wed Mar 14 15:10:42 2018 +0100 # Node ID f2cbeb473e85e02167c158a8851f6511e88c7529 # Parent 2a25589b5971c99b5cf79228a2027492312616d0 8199471: Enable generation of callSiteForms at link time Reviewed-by: psandoz diff --git a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java --- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java +++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java @@ -133,7 +133,7 @@ } static byte[] generateInvokersHolderClassBytes(String className, - MethodType[] methodTypes) { + MethodType[] invokerMethodTypes, MethodType[] callSiteMethodTypes) { HashSet dedupSet = new HashSet<>(); ArrayList forms = new ArrayList<>(); @@ -144,17 +144,33 @@ MethodTypeForm.LF_GEN_LINKER, MethodTypeForm.LF_GEN_INVOKER }; - for (int i = 0; i < methodTypes.length; i++) { + + for (int i = 0; i < invokerMethodTypes.length; i++) { // generate methods representing invokers of the specified type - if (dedupSet.add(methodTypes[i])) { + if (dedupSet.add(invokerMethodTypes[i])) { for (int type : types) { - LambdaForm invokerForm = Invokers.invokeHandleForm(methodTypes[i], + LambdaForm invokerForm = Invokers.invokeHandleForm(invokerMethodTypes[i], /*customized*/false, type); forms.add(invokerForm); names.add(invokerForm.kind.defaultLambdaName); } } } + + dedupSet = new HashSet<>(); + for (int i = 0; i < callSiteMethodTypes.length; i++) { + // generate methods representing invokers of the specified type + if (dedupSet.add(callSiteMethodTypes[i])) { + LambdaForm callSiteForm = Invokers.callSiteForm(callSiteMethodTypes[i], true); + forms.add(callSiteForm); + names.add(callSiteForm.kind.defaultLambdaName); + + LambdaForm methodHandleForm = Invokers.callSiteForm(callSiteMethodTypes[i], false); + forms.add(methodHandleForm); + names.add(methodHandleForm.kind.defaultLambdaName); + } + } + return generateCodeBytesForLFs(className, names.toArray(new String[0]), forms.toArray(new LambdaForm[0])); diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -649,6 +649,8 @@ } case EXACT_INVOKER: // fall-through case EXACT_LINKER: // fall-through + case LINK_TO_CALL_SITE: // fall-through + case LINK_TO_TARGET_METHOD: // fall-through case GENERIC_INVOKER: // fall-through case GENERIC_LINKER: return resolveFrom(name, invokerType.basicType(), Invokers.Holder.class); case GET_OBJECT: // fall-through diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -523,7 +523,7 @@ } // skipCallSite is true if we are optimizing a ConstantCallSite - private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { + static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); LambdaForm lform = mtype.form().cachedLambdaForm(which); diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -1841,10 +1841,13 @@ @Override public byte[] generateInvokersHolderClassBytes(final String className, - MethodType[] methodTypes) { + MethodType[] invokerMethodTypes, + MethodType[] callSiteMethodTypes) { return GenerateJLIClassesHelper - .generateInvokersHolderClassBytes(className, methodTypes); + .generateInvokersHolderClassBytes(className, + invokerMethodTypes, callSiteMethodTypes); } + }); } diff --git a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java --- a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java +++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java @@ -102,5 +102,7 @@ * the invoker forms for the set of supplied {@code methodTypes}. */ byte[] generateInvokersHolderClassBytes(String className, - MethodType[] methodTypes); + MethodType[] invokerMethodTypes, + MethodType[] callSiteFormsMethodTypes); + } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java @@ -69,7 +69,9 @@ private static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder"; private static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder"; - private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder"; + + private static final String INVOKERS_HOLDER_NAME = "java.lang.invoke.Invokers$Holder"; + private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/'); private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); @@ -78,6 +80,8 @@ Set invokerTypes = Set.of(); + Set callSiteTypes = Set.of(); + Map> dmhMethods = Map.of(); String mainArgument; @@ -128,7 +132,7 @@ * @return the default invoker forms to generate. */ private static Set defaultInvokers() { - return Set.of("LL_L", "LL_I", "LILL_I", "L6_L"); + return Set.of("LL_L", "LL_I", "LLLL_L", "LLLL_I", "LLIL_L", "LLIL_I", "L6_L"); } /** @@ -209,6 +213,8 @@ // ease finding methods in the generated code speciesTypes = new TreeSet<>(speciesTypes); invokerTypes = new TreeSet<>(invokerTypes); + callSiteTypes = new TreeSet<>(callSiteTypes); + TreeMap> newDMHMethods = new TreeMap<>(); for (Map.Entry> entry : dmhMethods.entrySet()) { newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue())); @@ -229,8 +235,13 @@ case "[LF_RESOLVE]": String methodType = parts[3]; validateMethodType(methodType); - if (parts[1].contains("Invokers")) { - invokerTypes.add(methodType); + if (parts[1].equals(INVOKERS_HOLDER_NAME)) { + if ("linkToTargetMethod".equals(parts[2]) || + "linkToCallSite".equals(parts[2])) { + callSiteTypes.add(methodType); + } else { + invokerTypes.add(methodType); + } } else if (parts[1].contains("DirectMethodHandle")) { String dmh = parts[2]; // ignore getObject etc for now (generated @@ -294,10 +305,11 @@ // Copy all but DMH_ENTRY to out in.transformAndCopy(entry -> { // filter out placeholder entries - if (entry.path().equals(DIRECT_METHOD_HOLDER_ENTRY) || - entry.path().equals(DELEGATING_METHOD_HOLDER_ENTRY) || - entry.path().equals(INVOKERS_HOLDER_ENTRY) || - entry.path().equals(BASIC_FORMS_HOLDER_ENTRY)) { + String path = entry.path(); + if (path.equals(DIRECT_METHOD_HOLDER_ENTRY) || + path.equals(DELEGATING_METHOD_HOLDER_ENTRY) || + path.equals(INVOKERS_HOLDER_ENTRY) || + path.equals(BASIC_FORMS_HOLDER_ENTRY)) { return null; } else { return entry; @@ -361,23 +373,40 @@ index++; } } + + // The invoker type to ask for is retrieved by removing the first + // and the last argument, which needs to be of Object.class MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()]; int i = 0; for (String invokerType : invokerTypes) { - // The invoker type to ask for is retrieved by removing the first - // and the last argument, which needs to be of Object.class MethodType mt = asMethodType(invokerType); final int lastParam = mt.parameterCount() - 1; if (mt.parameterCount() < 2 || mt.parameterType(0) != Object.class || mt.parameterType(lastParam) != Object.class) { throw new PluginException( - "Invoker type parameter must start and end with L"); + "Invoker type parameter must start and end with Object: " + invokerType); } mt = mt.dropParameterTypes(lastParam, lastParam + 1); invokerMethodTypes[i] = mt.dropParameterTypes(0, 1); i++; } + + // The callSite type to ask for is retrieved by removing the last + // argument, which needs to be of Object.class + MethodType[] callSiteMethodTypes = new MethodType[this.callSiteTypes.size()]; + i = 0; + for (String callSiteType : callSiteTypes) { + MethodType mt = asMethodType(callSiteType); + final int lastParam = mt.parameterCount() - 1; + if (mt.parameterCount() < 1 || + mt.parameterType(lastParam) != Object.class) { + throw new PluginException( + "CallSite type parameter must end with Object: " + callSiteType); + } + callSiteMethodTypes[i] = mt.dropParameterTypes(lastParam, lastParam + 1); + i++; + } try { byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes( DIRECT_HOLDER, directMethodTypes, dmhTypes); @@ -390,8 +419,8 @@ ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HOLDER_ENTRY, bytes); out.add(ndata); - bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER, - invokerMethodTypes); + bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER_INTERNAL_NAME, + invokerMethodTypes, callSiteMethodTypes); ndata = ResourcePoolEntry.create(INVOKERS_HOLDER_ENTRY, bytes); out.add(ndata); @@ -409,7 +438,7 @@ private static final String BASIC_FORMS_HOLDER_ENTRY = "/java.base/" + BASIC_FORMS_HOLDER + ".class"; private static final String INVOKERS_HOLDER_ENTRY = - "/java.base/" + INVOKERS_HOLDER + ".class"; + "/java.base/" + INVOKERS_HOLDER_INTERNAL_NAME + ".class"; // Convert LL -> LL, L3 -> LLL public static String expandSignature(String signature) {