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 return (loader == null) 94 ? Class.forName(name, false, null) 95 : loader.loadClass(name); 96 } catch (ClassNotFoundException ex) { 97 throw new TypeNotPresentException(name, ex); 98 } 99 } else if (c == '[') { 100 Class<?> t = parseSig(str, i, end, loader); 101 if (t != null) 102 t = java.lang.reflect.Array.newInstance(t, 0).getClass(); 103 return t; 104 } else { 105 return Wrapper.forBasicType(c).primitiveType(); 106 } 107 } 108 109 public static String unparse(Class<?> type) { 110 if (type == Object.class) { 111 return "Ljava/lang/Object;"; 112 } else if (type == int.class) { 113 return "I"; 114 } 115 StringBuilder sb = new StringBuilder(); 116 unparseSig(type, sb); 117 return sb.toString(); 118 } 119 120 public static String unparse(MethodType type) { 121 return unparseMethod(type.returnType(), type.parameterArray()); 122 } 123 124 public static String unparse(Object type) { 125 if (type instanceof Class<?>) 126 return unparse((Class<?>) type); 127 if (type instanceof MethodType) 128 return unparse((MethodType) type); 129 return (String) type; 130 } 131 132 public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) { 133 StringBuilder sb = new StringBuilder(); 134 sb.append('('); 135 for (Class<?> pt : ptypes) 136 unparseSig(pt, sb); 137 sb.append(')'); 138 unparseSig(rtype, sb); 139 return sb.toString(); 140 } 141 142 public static String unparseMethod(Class<?> rtype, Class<?>[] ptypes) { 143 StringBuilder sb = new StringBuilder(); 144 sb.append('('); 145 for (Class<?> pt : ptypes) 146 unparseSig(pt, sb); 147 sb.append(')'); 148 unparseSig(rtype, sb); 149 return sb.toString(); 150 } 151 152 private static void unparseSig(Class<?> t, StringBuilder sb) { 153 char c = Wrapper.forBasicType(t).basicTypeChar(); 154 if (c != 'L' && c != 'Q') { 155 sb.append(c); 156 } else if (t == Object.class) { 157 sb.append("Ljava/lang/Object;"); 158 } else { 159 boolean lsemi = (!t.isArray()); 160 if (lsemi) sb.append(c); 161 sb.append(t.getName().replace('.', '/')); 162 if (lsemi) sb.append(';'); 163 } 164 } 165 166 }