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 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[] generateBasicFormsClassBytes(String className) { 42 ArrayList<LambdaForm> forms = new ArrayList<>(); 43 ArrayList<String> names = new ArrayList<>(); 44 HashSet<String> dedupSet = new HashSet<>(); 45 for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) { 46 LambdaForm zero = LambdaForm.zeroForm(type); 47 String name = zero.kind.defaultLambdaName 48 + "_" + zero.returnType().basicTypeChar(); 49 if (dedupSet.add(name)) { 50 names.add(name); 51 forms.add(zero); 52 } 53 54 LambdaForm identity = LambdaForm.identityForm(type); 55 name = identity.kind.defaultLambdaName 56 + "_" + identity.returnType().basicTypeChar(); 57 if (dedupSet.add(name)) { 58 names.add(name); 59 forms.add(identity); 60 } 61 } 62 return generateCodeBytesForLFs(className, 63 names.toArray(new String[0]), 64 forms.toArray(new LambdaForm[0])); 65 } 66 67 static byte[] generateDirectMethodHandleHolderClassBytes(String className, 68 MethodType[] methodTypes, int[] types) { 69 LambdaForm[] forms = new LambdaForm[methodTypes.length]; 70 String[] names = new String[methodTypes.length]; 71 for (int i = 0; i < forms.length; i++) { 72 forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i], 73 types[i]); 74 names[i] = forms[i].kind.defaultLambdaName; 75 } 76 return generateCodeBytesForLFs(className, names, forms); 77 } 78 79 static byte[] generateDelegatingMethodHandleHolderClassBytes(String className, 80 MethodType[] methodTypes) { 81 82 HashSet<MethodType> dedupSet = new HashSet<>(); 83 ArrayList<LambdaForm> forms = new ArrayList<>(); 84 ArrayList<String> names = new ArrayList<>(); 85 for (int i = 0; i < methodTypes.length; i++) { 86 // generate methods representing the DelegatingMethodHandle 87 if (dedupSet.add(methodTypes[i])) { 88 // reinvokers are variant with the associated SpeciesData 89 // and shape of the target LF, but we can easily pregenerate 90 // the basic reinvokers associated with Species_L. Ultimately we 91 // may want to consider pregenerating more of these, which will 92 // require an even more complex naming scheme 93 LambdaForm reinvoker = makeReinvokerFor(methodTypes[i]); 94 forms.add(reinvoker); 95 String speciesSig = BoundMethodHandle 96 .speciesData(reinvoker).fieldSignature(); 97 assert(speciesSig.equals("L")); 98 names.add(reinvoker.kind.defaultLambdaName + "_" + speciesSig); 99 100 LambdaForm delegate = makeDelegateFor(methodTypes[i]); 101 forms.add(delegate); 102 names.add(delegate.kind.defaultLambdaName); 103 } 104 } 105 return generateCodeBytesForLFs(className, 106 names.toArray(new String[0]), 107 forms.toArray(new LambdaForm[0])); 108 } 109 110 /* 111 * Generate customized code for a set of LambdaForms of specified types into 112 * a class with a specified name. 113 */ 114 private static byte[] generateCodeBytesForLFs(String className, 115 String[] names, LambdaForm[] forms) { 116 117 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); 118 cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, 119 className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null); 120 cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null); 121 122 for (int i = 0; i < forms.length; i++) { 123 addMethod(className, names[i], forms[i], 124 forms[i].methodType(), cw); 125 } 126 return cw.toByteArray(); 127 } 128 129 private static void addMethod(String className, String methodName, LambdaForm form, 130 MethodType type, ClassWriter cw) { 131 InvokerBytecodeGenerator g 132 = new InvokerBytecodeGenerator(className, methodName, form, type); 133 g.setClassWriter(cw); 134 g.addMethod(); 135 } 136 137 private static LambdaForm makeReinvokerFor(MethodType type) { 138 MethodHandle emptyHandle = MethodHandles.empty(type); 139 return DelegatingMethodHandle.makeReinvokerForm(emptyHandle, 140 MethodTypeForm.LF_REBIND, 141 BoundMethodHandle.speciesData_L(), 142 BoundMethodHandle.speciesData_L().getterFunction(0)); 143 } 144 145 private static LambdaForm makeDelegateFor(MethodType type) { 146 MethodHandle handle = MethodHandles.empty(type); 147 return DelegatingMethodHandle.makeReinvokerForm( 148 handle, 149 MethodTypeForm.LF_DELEGATE, 150 DelegatingMethodHandle.class, 151 DelegatingMethodHandle.NF_getTarget); 152 } 153 154 static Map.Entry<String, byte[]> generateConcreteBMHClassBytes( 155 final String types) { 156 for (char c : types.toCharArray()) { 157 if ("LIJFD".indexOf(c) < 0) { 158 throw new IllegalArgumentException("All characters must " 159 + "correspond to a basic field type: LIJFD"); 160 } 161 } 162 String shortTypes = LambdaForm.shortenSignature(types); 163 final String className = 164 BoundMethodHandle.Factory.speciesInternalClassName(shortTypes); 165 return Map.entry(className, 166 BoundMethodHandle.Factory.generateConcreteBMHClassBytes( 167 shortTypes, types, className)); 168 } 169 }