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') { 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 StringBuilder sb = new StringBuilder(); 111 unparseSig(type, sb); 112 return sb.toString(); 113 } 114 115 public static String unparse(MethodType type) { 116 return unparseMethod(type.returnType(), type.parameterList()); 117 } 118 119 public static String unparse(Object type) { 120 if (type instanceof Class<?>) 121 return unparse((Class<?>) type); 122 if (type instanceof MethodType) 123 return unparse((MethodType) type); 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 private static void unparseSig(Class<?> t, StringBuilder sb) { 138 char c = Wrapper.forBasicType(t).basicTypeChar(); 139 if (c != 'L') { 140 sb.append(c); 141 } else { 142 boolean lsemi = (!t.isArray()); 143 if (lsemi) sb.append('L'); 144 sb.append(t.getName().replace('.', '/')); 145 if (lsemi) sb.append(';'); 146 } 147 } 148 149 }