/src/kilim/analysis/TypeDesc.java

http://github.com/kilim/kilim · Java · 281 lines · 228 code · 29 blank · 24 comment · 88 complexity · 3636c535186d18134dac91b706bcf7a8 MD5 · raw file

  1. /* Copyright (c) 2006, Sriram Srinivasan
  2. *
  3. * You may distribute this software under the terms of the license
  4. * specified in the file "License"
  5. */
  6. package kilim.analysis;
  7. import static kilim.Constants.D_BOOLEAN;
  8. import static kilim.Constants.D_BYTE;
  9. import static kilim.Constants.D_CHAR;
  10. import static kilim.Constants.D_DOUBLE;
  11. import static kilim.Constants.D_FLOAT;
  12. import static kilim.Constants.D_INT;
  13. import static kilim.Constants.D_LONG;
  14. import static kilim.Constants.D_NULL;
  15. import static kilim.Constants.D_OBJECT;
  16. import static kilim.Constants.D_SHORT;
  17. import static kilim.Constants.D_STRING;
  18. import static kilim.Constants.D_UNDEFINED;
  19. import java.lang.reflect.Field;
  20. import java.util.HashMap;
  21. import kilim.Constants;
  22. import kilim.mirrors.ClassMirrorNotFoundException;
  23. import kilim.mirrors.Detector;
  24. import org.objectweb.asm.Type;
  25. /**
  26. * A utility class that provides static methods for interning type strings and merging type
  27. * descriptors.
  28. *
  29. */
  30. public class TypeDesc {
  31. static final HashMap<String, String> knownTypes = new HashMap<String, String>(30);
  32. static {
  33. Field[] fields = Constants.class.getFields();
  34. try {
  35. for (int i = 0; i < fields.length; i++) {
  36. Field f = fields[i];
  37. if (f.getName().startsWith("D_")) {
  38. String val = (String) f.get(null);
  39. knownTypes.put(val, val);
  40. }
  41. }
  42. } catch (IllegalAccessException iae) {
  43. iae.printStackTrace();
  44. }
  45. knownTypes.put("java/lang/Object", D_OBJECT);
  46. knownTypes.put("java/lang/String", D_STRING);
  47. }
  48. static boolean isDoubleWord(String desc) {
  49. return (desc == D_DOUBLE || desc == D_LONG);
  50. }
  51. public static String getInterned(String desc) {
  52. String ret = knownTypes.get(desc);
  53. if (ret == null) {
  54. switch (desc.charAt(0)) {
  55. case 'L':
  56. case '[':
  57. return desc;
  58. default:
  59. return "L" + desc + ';';
  60. }
  61. } else {
  62. return ret;
  63. }
  64. }
  65. public static String getReturnTypeDesc(String desc) {
  66. return getInterned(desc.substring(desc.indexOf(")") + 1));
  67. }
  68. static boolean isSingleWord(String desc) {
  69. return !isDoubleWord(desc);
  70. }
  71. public static String getComponentType(String t) {
  72. if (t.charAt(0) != '[') {
  73. throw new InternalError("Can't get component type of " + t);
  74. }
  75. return getInterned(t.substring(1));
  76. }
  77. public static String getTypeDesc(Object object) {
  78. if (object instanceof Integer)
  79. return D_INT;
  80. if (object instanceof Long)
  81. return D_LONG;
  82. if (object instanceof Float)
  83. return D_FLOAT;
  84. if (object instanceof Double)
  85. return D_DOUBLE;
  86. if (object instanceof String)
  87. return D_STRING;
  88. if (object instanceof Boolean)
  89. return D_BOOLEAN;
  90. if (object instanceof Type)
  91. return TypeDesc.getInterned(((Type) object).getDescriptor());
  92. throw new InternalError("Unrecognized ldc constant: " + object);
  93. }
  94. private static int typelen(char[] buf, int off) {
  95. int start = off;
  96. switch (buf[off]) {
  97. case 'L':
  98. while (buf[off++] != ';') {}
  99. return off - start;
  100. case 'B':
  101. case 'C':
  102. case 'D':
  103. case 'F':
  104. case 'I':
  105. case 'J':
  106. case 'S':
  107. case 'Z':
  108. case 'V':
  109. return 1;
  110. case '[':
  111. return typelen(buf, off + 1) + 1;
  112. default:
  113. throw new InternalError("Unknown descriptor type: " + buf[0]);
  114. }
  115. }
  116. public static String[] getArgumentTypes(String methodDescriptor) {
  117. char[] buf = methodDescriptor.toCharArray();
  118. int size = getNumArgumentTypes(buf);
  119. String[] args = new String[size];
  120. size = 0;
  121. int off = 1;
  122. while (buf[off] != ')') {
  123. int len = typelen(buf, off);
  124. args[size] = getInterned(new String(buf, off, len));
  125. off += len;
  126. size += 1;
  127. }
  128. return args;
  129. }
  130. public static int getNumArgumentTypes(String desc) {
  131. return getNumArgumentTypes(desc.toCharArray());
  132. }
  133. public static int getNumArgumentTypes(char[] buf) {
  134. int off = 1;
  135. int size = 0;
  136. while (true) {
  137. if (buf[off] == ')') {
  138. break;
  139. }
  140. off += typelen(buf, off);
  141. size++;
  142. }
  143. return size;
  144. }
  145. /**
  146. * Given two type descriptors, it returns an appropriate merge: 1) If they are Array types, the
  147. * result is a an array of the merged component types 2) If they are ref types, it returns the
  148. * least common super type. If one of them is an interface, the result is D_OBJECT 3) All other
  149. * types must match exactly in order to not raise an error.
  150. */
  151. public static String mergeType(Detector det,String a, String b) throws IncompatibleTypesException {
  152. // given: a and b are different.
  153. if (a == D_UNDEFINED)
  154. return b;
  155. if (b == D_UNDEFINED)
  156. return a;
  157. char ac = a.charAt(0);
  158. char bc = b.charAt(0);
  159. if (a == D_NULL) {
  160. assert b == D_NULL || bc == 'L' || bc == '[' : "merging NULL type with non ref type: "
  161. + b;
  162. return b;
  163. }
  164. if (b == D_NULL) {
  165. assert b == D_NULL || bc == 'L' || bc == '[' : "merging NULL type with non ref type: "
  166. + a;
  167. return a;
  168. }
  169. if (a == b || a.equals(b))
  170. return a;
  171. switch (ac) {
  172. case 'N': // D_NULL
  173. if (bc == 'L')
  174. return b;
  175. break;
  176. case 'L':
  177. if (bc == 'L') {
  178. return commonSuperType(det,a, b);
  179. } else if (bc == 'N') {
  180. return a;
  181. } else if (bc == '[') {
  182. return D_OBJECT; // common supertype of Ref and ArrayRef
  183. }
  184. break;
  185. case '[':
  186. if (bc == '[') {
  187. try {
  188. return "["
  189. + mergeType(det, TypeDesc.getComponentType(a), TypeDesc.getComponentType(b));
  190. } catch (IncompatibleTypesException ite) {
  191. // The component types are incompatible, but two disparate arrays still
  192. // inherit from Object
  193. return D_OBJECT;
  194. }
  195. } else if (bc == 'L') {
  196. return D_OBJECT; // common supertype of Ref and ArrayRef
  197. }
  198. break;
  199. case 'I':
  200. case 'Z':
  201. case 'B':
  202. case 'C':
  203. case 'S':
  204. // all int types are interchangeable
  205. switch (bc) {
  206. case 'I':
  207. case 'Z':
  208. case 'B':
  209. case 'C':
  210. case 'S':
  211. return D_INT;
  212. }
  213. break;
  214. }
  215. throw new IncompatibleTypesException("" + a + "," + b);
  216. }
  217. static String JAVA_LANG_OBJECT = "java.lang.Object";
  218. // public for testing purposes
  219. public static String commonSuperType(Detector det,String oa, String ob) {
  220. try {
  221. if (oa == D_OBJECT || ob == D_OBJECT)
  222. return D_OBJECT;
  223. if (oa.equals(ob))
  224. return oa;
  225. String lub = det.commonSuperType(getInternalName(oa),getInternalName(ob));
  226. if (lub.equals("java/lang/Object"))
  227. return D_OBJECT;
  228. return "L" + lub + ";";
  229. } catch (ClassMirrorNotFoundException cnfe) {
  230. throw new InternalError(cnfe.getMessage());
  231. }
  232. }
  233. public static boolean isIntType(String typeDesc) {
  234. return (typeDesc == D_INT || typeDesc == D_CHAR || typeDesc == D_SHORT
  235. || typeDesc == D_BYTE || typeDesc == D_BOOLEAN);
  236. }
  237. public static boolean isRefType(String typeDesc) {
  238. char c = typeDesc.charAt(0);
  239. return typeDesc == D_NULL || c == '[' || c == 'L';
  240. }
  241. public static String getInternalName(String desc) {
  242. if (desc.charAt(0) == 'L') {
  243. return desc.substring(1, desc.length() - 1);
  244. } else {
  245. assert desc.charAt(0) == '[' : "Unexpected internal name " + desc;
  246. return desc;
  247. }
  248. }
  249. // public static void main(String[] args) throws Exception {
  250. // System.out.println(mergeType("Lkilim/test/ex/ExC;", "Lkilim/test/ex/ExD;"));
  251. // }
  252. }