12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import java.util.Map;
29 import jdk.internal.org.objectweb.asm.ClassWriter;
30 import jdk.internal.org.objectweb.asm.Opcodes;
31
32 /**
33 * Helper class to assist the GenerateJLIClassesPlugin to get access to
34 * generate classes ahead of time.
35 */
36 class GenerateJLIClassesHelper {
37
38 static byte[] generateDMHClassBytes(String className,
39 MethodType[] methodTypes, int[] types) {
40 LambdaForm[] forms = new LambdaForm[methodTypes.length];
41 for (int i = 0; i < forms.length; i++) {
42 forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i],
43 types[i]);
44 methodTypes[i] = forms[i].methodType();
45 }
46 return generateCodeBytesForLFs(className, forms, methodTypes);
47 }
48
49 /*
50 * Generate customized code for a set of LambdaForms of specified types into
51 * a class with a specified name.
52 */
53 private static byte[] generateCodeBytesForLFs(String className,
54 LambdaForm[] forms, MethodType[] types) {
55 assert(forms.length == types.length);
56
57 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
58 cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
59 className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null);
60 cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null);
61 for (int i = 0; i < forms.length; i++) {
62 InvokerBytecodeGenerator g
63 = new InvokerBytecodeGenerator(className, forms[i], types[i]);
64 g.setClassWriter(cw);
65 g.addMethod();
66 }
67 return cw.toByteArray();
68 }
69
70 static Map.Entry<String, byte[]> generateConcreteBMHClassBytes(
71 final String types) {
72 for (char c : types.toCharArray()) {
73 if ("LIJFD".indexOf(c) < 0) {
74 throw new IllegalArgumentException("All characters must "
75 + "correspond to a basic field type: LIJFD");
76 }
77 }
78 String shortTypes = LambdaForm.shortenSignature(types);
79 final String className =
80 BoundMethodHandle.Factory.speciesInternalClassName(shortTypes);
81 return Map.entry(className,
82 BoundMethodHandle.Factory.generateConcreteBMHClassBytes(
83 shortTypes, types, className));
84 }
85 }
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import java.util.Map;
29 import jdk.internal.org.objectweb.asm.ClassWriter;
30 import jdk.internal.org.objectweb.asm.Opcodes;
31
32 import java.util.ArrayList;
33 import java.util.HashSet;
34
35 /**
36 * Helper class to assist the GenerateJLIClassesPlugin to get access to
37 * generate classes ahead of time.
38 */
39 class GenerateJLIClassesHelper {
40
41 static byte[] generateDirectMethodHandleHolderClassBytes(String className,
42 MethodType[] methodTypes, int[] types) {
43 LambdaForm[] forms = new LambdaForm[methodTypes.length];
44 String[] names = new String[methodTypes.length];
45 for (int i = 0; i < forms.length; i++) {
46 forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i],
47 types[i]);
48 names[i] = forms[i].kind.defaultLambdaName;
49 }
50 return generateCodeBytesForLFs(className, names, forms);
51 }
52
53 static byte[] generateDelegatingMethodHandleHolderClassBytes(String className,
54 MethodType[] methodTypes) {
55
56 HashSet<MethodType> dedupSet = new HashSet<>();
57 ArrayList<LambdaForm> forms = new ArrayList<>();
58 ArrayList<String> names = new ArrayList<>();
59 for (int i = 0; i < methodTypes.length; i++) {
60 // generate methods representing the DelegatingMethodHandle
61 if (dedupSet.add(methodTypes[i])) {
62 // reinvokers are variant with the associated SpeciesData
63 // and shape of the target LF, but we can easily pregenerate
64 // the basic reinvokers associated with Species_L. Ultimately we
65 // may want to consider pregenerating more of these, which will
66 // require an even more complex naming scheme
67 LambdaForm reinvoker = makeReinvokerFor(methodTypes[i]);
68 forms.add(reinvoker);
69 String speciesSig = BoundMethodHandle
70 .speciesData(reinvoker).fieldSignature();
71 assert(speciesSig.equals("L"));
72 names.add(reinvoker.kind.defaultLambdaName + "_" + speciesSig);
73
74 LambdaForm delegate = makeDelegateFor(methodTypes[i]);
75 forms.add(delegate);
76 names.add(delegate.kind.defaultLambdaName);
77 }
78 }
79 return generateCodeBytesForLFs(className,
80 names.toArray(new String[0]),
81 forms.toArray(new LambdaForm[0]));
82 }
83
84 /*
85 * Generate customized code for a set of LambdaForms of specified types into
86 * a class with a specified name.
87 */
88 private static byte[] generateCodeBytesForLFs(String className,
89 String[] names, LambdaForm[] forms) {
90
91 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
92 cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
93 className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null);
94 cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null);
95
96 for (int i = 0; i < forms.length; i++) {
97 addMethod(className, names[i], forms[i],
98 forms[i].methodType(), cw);
99 }
100 return cw.toByteArray();
101 }
102
103 private static void addMethod(String className, String methodName, LambdaForm form,
104 MethodType type, ClassWriter cw) {
105 InvokerBytecodeGenerator g
106 = new InvokerBytecodeGenerator(className, methodName, form, type);
107 g.setClassWriter(cw);
108 g.addMethod();
109 }
110
111 private static LambdaForm makeReinvokerFor(MethodType type) {
112 MethodHandle emptyHandle = MethodHandles.empty(type);
113 return DelegatingMethodHandle.makeReinvokerForm(emptyHandle,
114 MethodTypeForm.LF_REBIND,
115 BoundMethodHandle.speciesData_L(),
116 BoundMethodHandle.speciesData_L().getterFunction(0));
117 }
118
119 private static LambdaForm makeDelegateFor(MethodType type) {
120 MethodHandle handle = MethodHandles.empty(type);
121 return DelegatingMethodHandle.makeReinvokerForm(
122 handle,
123 MethodTypeForm.LF_DELEGATE,
124 DelegatingMethodHandle.class,
125 DelegatingMethodHandle.NF_getTarget);
126 }
127
128 static Map.Entry<String, byte[]> generateConcreteBMHClassBytes(
129 final String types) {
130 for (char c : types.toCharArray()) {
131 if ("LIJFD".indexOf(c) < 0) {
132 throw new IllegalArgumentException("All characters must "
133 + "correspond to a basic field type: LIJFD");
134 }
135 }
136 String shortTypes = LambdaForm.shortenSignature(types);
137 final String className =
138 BoundMethodHandle.Factory.speciesInternalClassName(shortTypes);
139 return Map.entry(className,
140 BoundMethodHandle.Factory.generateConcreteBMHClassBytes(
141 shortTypes, types, className));
142 }
143 }
|