1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 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 jdk.internal.org.objectweb.asm.ClassWriter; 29 import jdk.internal.org.objectweb.asm.Opcodes; 30 import sun.invoke.util.Wrapper; 31 32 import java.util.ArrayList; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * Helper class to assist the GenerateJLIClassesPlugin to get access to 39 * generate classes ahead of time. 40 */ 41 class GenerateJLIClassesHelper { 42 43 static byte[] generateBasicFormsClassBytes(String className) { 44 ArrayList<LambdaForm> forms = new ArrayList<>(); 45 ArrayList<String> names = new ArrayList<>(); 46 HashSet<String> dedupSet = new HashSet<>(); 47 for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) { 48 LambdaForm zero = LambdaForm.zeroForm(type); 49 String name = zero.kind.defaultLambdaName 50 + "_" + zero.returnType().basicTypeChar(); 51 if (dedupSet.add(name)) { 52 names.add(name); 53 forms.add(zero); 54 } 55 56 LambdaForm identity = LambdaForm.identityForm(type); 57 name = identity.kind.defaultLambdaName 58 + "_" + identity.returnType().basicTypeChar(); 59 if (dedupSet.add(name)) { 60 names.add(name); 61 forms.add(identity); 62 } 63 } 64 return generateCodeBytesForLFs(className, 65 names.toArray(new String[0]), 66 forms.toArray(new LambdaForm[0])); 67 } 68 69 static byte[] generateDirectMethodHandleHolderClassBytes(String className, 70 MethodType[] methodTypes, int[] types) { 71 ArrayList<LambdaForm> forms = new ArrayList<>(); 72 ArrayList<String> names = new ArrayList<>(); 73 for (int i = 0; i < methodTypes.length; i++) { 74 LambdaForm form = DirectMethodHandle 75 .makePreparedLambdaForm(methodTypes[i], types[i]); 76 forms.add(form); 77 names.add(form.kind.defaultLambdaName); 78 } 79 for (Wrapper wrapper : Wrapper.values()) { 80 if (wrapper == Wrapper.VOID) { 81 continue; 82 } 83 for (byte b = DirectMethodHandle.AF_GETFIELD; b < DirectMethodHandle.AF_LIMIT; b++) { 84 int ftype = DirectMethodHandle.ftypeKind(wrapper.primitiveType()); 85 LambdaForm form = DirectMethodHandle 86 .makePreparedFieldLambdaForm(b, /*isVolatile*/false, ftype); 87 if (form.kind != LambdaForm.Kind.GENERIC) { 88 forms.add(form); 89 names.add(form.kind.defaultLambdaName); 90 } 91 // volatile 92 form = DirectMethodHandle 93 .makePreparedFieldLambdaForm(b, /*isVolatile*/true, ftype); 94 if (form.kind != LambdaForm.Kind.GENERIC) { 95 forms.add(form); 96 names.add(form.kind.defaultLambdaName); 97 } 98 } 99 } 100 return generateCodeBytesForLFs(className, 101 names.toArray(new String[0]), 102 forms.toArray(new LambdaForm[0])); 103 } 104 105 static byte[] generateDelegatingMethodHandleHolderClassBytes(String className, 106 MethodType[] methodTypes) { 107 108 HashSet<MethodType> dedupSet = new HashSet<>(); 109 ArrayList<LambdaForm> forms = new ArrayList<>(); 110 ArrayList<String> names = new ArrayList<>(); 111 for (int i = 0; i < methodTypes.length; i++) { 112 // generate methods representing the DelegatingMethodHandle 113 if (dedupSet.add(methodTypes[i])) { 114 // reinvokers are variant with the associated SpeciesData 115 // and shape of the target LF, but we can easily pregenerate 116 // the basic reinvokers associated with Species_L. Ultimately we 117 // may want to consider pregenerating more of these, which will 118 // require an even more complex naming scheme 119 LambdaForm reinvoker = makeReinvokerFor(methodTypes[i]); 120 forms.add(reinvoker); 121 String speciesSig = BoundMethodHandle.speciesDataFor(reinvoker).key(); 122 assert(speciesSig.equals("L")); 123 names.add(reinvoker.kind.defaultLambdaName + "_" + speciesSig); 124 125 LambdaForm delegate = makeDelegateFor(methodTypes[i]); 126 forms.add(delegate); 127 names.add(delegate.kind.defaultLambdaName); 128 } 129 } 130 return generateCodeBytesForLFs(className, 131 names.toArray(new String[0]), 132 forms.toArray(new LambdaForm[0])); 133 } 134 135 static byte[] generateInvokersHolderClassBytes(String className, 136 MethodType[] methodTypes) { 137 138 HashSet<MethodType> dedupSet = new HashSet<>(); 139 ArrayList<LambdaForm> forms = new ArrayList<>(); 140 ArrayList<String> names = new ArrayList<>(); 141 int[] types = { 142 MethodTypeForm.LF_EX_LINKER, 143 MethodTypeForm.LF_EX_INVOKER, 144 MethodTypeForm.LF_GEN_LINKER, 145 MethodTypeForm.LF_GEN_INVOKER 146 }; 147 for (int i = 0; i < methodTypes.length; i++) { 148 // generate methods representing invokers of the specified type 149 if (dedupSet.add(methodTypes[i])) { 150 for (int type : types) { 151 LambdaForm invokerForm = Invokers.invokeHandleForm(methodTypes[i], 152 /*customized*/false, type); 153 forms.add(invokerForm); 154 names.add(invokerForm.kind.defaultLambdaName); 155 } 156 } 157 } 158 return generateCodeBytesForLFs(className, 159 names.toArray(new String[0]), 160 forms.toArray(new LambdaForm[0])); 161 } 162 163 static byte[] generateCallSiteHolderClassBytes(String className, 164 MethodType[] methodTypes) { 165 166 HashSet<MethodType> dedupSet = new HashSet<>(); 167 ArrayList<LambdaForm> forms = new ArrayList<>(); 168 ArrayList<String> names = new ArrayList<>(); 169 170 for (int i = 0; i < methodTypes.length; i++) { 171 // generate methods representing invokers of the specified type 172 if (dedupSet.add(methodTypes[i])) { 173 LambdaForm callSiteForm = Invokers.callSiteForm(methodTypes[i], true); 174 forms.add(callSiteForm); 175 names.add(callSiteForm.kind.defaultLambdaName); 176 177 LambdaForm methodHandleForm = Invokers.callSiteForm(methodTypes[i], false); 178 forms.add(methodHandleForm); 179 names.add(methodHandleForm.kind.defaultLambdaName); 180 } 181 } 182 return generateCodeBytesForLFs(className, 183 names.toArray(new String[0]), 184 forms.toArray(new LambdaForm[0])); 185 } 186 187 /* 188 * Generate customized code for a set of LambdaForms of specified types into 189 * a class with a specified name. 190 */ 191 private static byte[] generateCodeBytesForLFs(String className, 192 String[] names, LambdaForm[] forms) { 193 194 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); 195 cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, 196 className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null); 197 cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null); 198 199 for (int i = 0; i < forms.length; i++) { 200 addMethod(className, names[i], forms[i], 201 forms[i].methodType(), cw); 202 } 203 return cw.toByteArray(); 204 } 205 206 private static void addMethod(String className, String methodName, LambdaForm form, 207 MethodType type, ClassWriter cw) { 208 InvokerBytecodeGenerator g 209 = new InvokerBytecodeGenerator(className, methodName, form, type); 210 g.setClassWriter(cw); 211 g.addMethod(); 212 } 213 214 private static LambdaForm makeReinvokerFor(MethodType type) { 215 MethodHandle emptyHandle = MethodHandles.empty(type); 216 return DelegatingMethodHandle.makeReinvokerForm(emptyHandle, 217 MethodTypeForm.LF_REBIND, 218 BoundMethodHandle.speciesData_L(), 219 BoundMethodHandle.speciesData_L().getterFunction(0)); 220 } 221 222 private static LambdaForm makeDelegateFor(MethodType type) { 223 MethodHandle handle = MethodHandles.empty(type); 224 return DelegatingMethodHandle.makeReinvokerForm( 225 handle, 226 MethodTypeForm.LF_DELEGATE, 227 DelegatingMethodHandle.class, 228 DelegatingMethodHandle.NF_getTarget); 229 } 230 231 @SuppressWarnings({"rawtypes", "unchecked"}) 232 static Map.Entry<String, byte[]> generateConcreteBMHClassBytes(final String types) { 233 for (char c : types.toCharArray()) { 234 if ("LIJFD".indexOf(c) < 0) { 235 throw new IllegalArgumentException("All characters must " 236 + "correspond to a basic field type: LIJFD"); 237 } 238 } 239 final BoundMethodHandle.SpeciesData species = BoundMethodHandle.SPECIALIZER.findSpecies(types); 240 final String className = species.speciesCode().getName(); 241 final ClassSpecializer.Factory factory = BoundMethodHandle.SPECIALIZER.factory(); 242 final byte[] code = factory.generateConcreteSpeciesCodeFile(className, species); 243 return Map.entry(className.replace('.', '/'), code); 244 } 245 246 }