1 /* 2 * copyright (c) 2008, 2015, 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 java.lang.invoke.MethodType; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Utility routines for dealing with bytecode-level signatures. 34 * @author jrose 35 */ 36 public class BytecodeDescriptor { 37 38 private BytecodeDescriptor() { } // cannot instantiate 39 40 /** 41 * @param loader the class loader in which to look up the types (null means 42 * bootstrap class loader) 43 */ 44 public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) { 45 return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); 46 } 47 48 /** 49 * @param loader the class loader in which to look up the types (null means 50 * bootstrap class loader) 51 */ 52 static List<Class<?>> parseMethod(String bytecodeSignature, 53 int start, int end, ClassLoader loader) { 54 String str = bytecodeSignature; 55 int[] i = {start}; 56 ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>(); 57 if (i[0] < end && str.charAt(i[0]) == '(') { 58 ++i[0]; // skip '(' 59 while (i[0] < end && str.charAt(i[0]) != ')') { 60 Class<?> pt = parseSig(str, i, end, loader); 61 if (pt == null || pt == void.class) 62 parseError(str, "bad argument type"); 63 ptypes.add(pt); 64 } 65 ++i[0]; // skip ')' 66 } else { 67 parseError(str, "not a method type"); 68 } 69 Class<?> rtype = parseSig(str, i, end, loader); 70 if (rtype == null || i[0] != end) 71 parseError(str, "bad return type"); 72 ptypes.add(rtype); 73 return ptypes; 74 } 75 76 private static void parseError(String str, String msg) { 77 throw new IllegalArgumentException("bad signature: "+str+": "+msg); 78 } 79 80 /** 81 * @param loader the class loader in which to look up the types (null means 82 * bootstrap class loader) 83 */ 84 private static Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) { 85 if (i[0] == end) return null; 86 char c = str.charAt(i[0]++); 87 if (c == 'L' || c == 'Q') { 88 int begc = i[0], endc = str.indexOf(';', begc); 89 if (endc < 0) return null; 90 i[0] = endc+1; 91 String name = str.substring(begc, endc).replace('/', '.'); 92 try { 93 Class<?> clz = (loader == null) 94 ? Class.forName(name, false, null) 95 : loader.loadClass(name); 96 return c == 'Q' ? clz.asValueType() : clz.asBoxType(); 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 = java.lang.reflect.Array.newInstance(t, 0).getClass(); 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 StringBuilder sb = new StringBuilder(); 117 unparseSig(type, sb); 118 return sb.toString(); 119 } 120 121 public static String unparse(MethodType type) { 122 return unparseMethod(type.returnType(), type.parameterArray()); 123 } 124 125 public static String unparse(Object type) { 126 if (type instanceof Class<?>) 127 return unparse((Class<?>) type); 128 if (type instanceof MethodType) 129 return unparse((MethodType) type); 130 return (String) type; 131 } 132 133 public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) { 134 StringBuilder sb = new StringBuilder(); 135 sb.append('('); 136 for (Class<?> pt : ptypes) 137 unparseSig(pt, sb); 138 sb.append(')'); 139 unparseSig(rtype, sb); 140 return sb.toString(); 141 } 142 143 public static String unparseMethod(Class<?> rtype, Class<?>[] ptypes) { 144 StringBuilder sb = new StringBuilder(); 145 sb.append('('); 146 for (Class<?> pt : ptypes) 147 unparseSig(pt, sb); 148 sb.append(')'); 149 unparseSig(rtype, sb); 150 return sb.toString(); 151 } 152 153 private static void unparseSig(Class<?> t, StringBuilder sb) { 154 char c = Wrapper.forBasicType(t).basicTypeChar(); 155 if (c != 'L') { 156 sb.append(c); 157 } else if (t == Object.class) { 158 sb.append("Ljava/lang/Object;"); 159 } else { 160 boolean lsemi = (!t.isArray()); 161 if (t == t.asValueType()) 162 c = 'Q'; 163 if (lsemi) sb.append(c); 164 sb.append(t.getName().replace('.', '/')); 165 if (lsemi) sb.append(';'); 166 } 167 } 168 169 }