1 /* 2 * Copyright (c) 2008, 2023, 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 sun.invoke.util; 27 28 import jdk.internal.value.PrimitiveClass; 29 30 import java.lang.invoke.MethodType; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Utility routines for dealing with bytecode-level signatures. 36 * @author jrose 37 */ 38 public class BytecodeDescriptor { 39 40 private BytecodeDescriptor() { } // cannot instantiate 41 42 /** 43 * @param loader the class loader in which to look up the types (null means 44 * bootstrap class loader) 45 */ 46 public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) { 47 return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); 48 } 49 50 /** 51 * @param loader the class loader in which to look up the types (null means 52 * bootstrap class loader) 53 */ 54 static List<Class<?>> parseMethod(String bytecodeSignature, 55 int start, int end, ClassLoader loader) { 56 String str = bytecodeSignature; 57 int[] i = {start}; 58 var ptypes = new ArrayList<Class<?>>(); 59 if (i[0] < end && str.charAt(i[0]) == '(') { 60 ++i[0]; // skip '(' 61 while (i[0] < end && str.charAt(i[0]) != ')') { 62 Class<?> pt = parseSig(str, i, end, loader); 63 if (pt == null || pt == void.class) 64 parseError(str, "bad argument type"); 65 ptypes.add(pt); 66 } 67 ++i[0]; // skip ')' 68 } else { 69 parseError(str, "not a method type"); 70 } 71 Class<?> rtype = parseSig(str, i, end, loader); 72 if (rtype == null || i[0] != end) 73 parseError(str, "bad return type"); 74 ptypes.add(rtype); 75 return ptypes; 76 } 77 78 private static void parseError(String str, String msg) { 79 throw new IllegalArgumentException("bad signature: "+str+": "+msg); 80 } 81 82 /** 83 * @param loader the class loader in which to look up the types (null means 84 * bootstrap class loader) 85 */ 86 private static Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) { 87 if (i[0] == end) return null; 88 char c = str.charAt(i[0]++); 89 if (c == 'L' || c == 'Q') { 90 int begc = i[0], endc = str.indexOf(';', begc); 91 if (endc < 0) return null; 92 i[0] = endc+1; 93 String name = str.substring(begc, endc).replace('/', '.'); 94 try { 95 Class<?> clz = Class.forName(name, false, loader); 96 return c == 'Q' ? PrimitiveClass.asValueType(clz) : PrimitiveClass.asPrimaryType(clz); 97 } catch (ClassNotFoundException ex) { 98 throw new TypeNotPresentException(name, ex); 99 } 100 } else if (c == '[') { 101 Class<?> t = parseSig(str, i, end, loader); 102 if (t != null) 103 t = t.arrayType(); 104 return t; 105 } else { 106 return Wrapper.forBasicType(c).primitiveType(); 107 } 108 } 109 110 public static String unparse(Class<?> type) { 111 if (type == Object.class) { 112 return "Ljava/lang/Object;"; 113 } else if (type == int.class) { 114 return "I"; 115 } 116 return type.descriptorString(); 117 } 118 119 public static String unparse(Object type) { 120 if (type instanceof Class<?> cl) 121 return unparse(cl); 122 if (type instanceof MethodType mt) 123 return mt.toMethodDescriptorString(); 124 return (String) type; 125 } 126 127 public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) { 128 StringBuilder sb = new StringBuilder(); 129 sb.append('('); 130 for (Class<?> pt : ptypes) 131 unparseSig(pt, sb); 132 sb.append(')'); 133 unparseSig(rtype, sb); 134 return sb.toString(); 135 } 136 137 public static String unparseMethod(Class<?> rtype, Class<?>[] ptypes) { 138 StringBuilder sb = new StringBuilder(); 139 sb.append('('); 140 for (Class<?> pt : ptypes) 141 unparseSig(pt, sb); 142 sb.append(')'); 143 unparseSig(rtype, sb); 144 return sb.toString(); 145 } 146 147 private static void unparseSig(Class<?> t, StringBuilder sb) { 148 char c = Wrapper.forBasicType(t).basicTypeChar(); 149 if (c != 'L') { 150 sb.append(c); 151 } else if (t == Object.class) { 152 sb.append("Ljava/lang/Object;"); 153 } else { 154 sb.append(t.descriptorString()); 155 } 156 } 157 }