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