ConstantPool.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // Copyright (c) 1997 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.bytecode;
  4. /** Manages a pool of constants, as used in .class files and Java interpreters.
  5. * @author Per Bothner
  6. */
  7. public class ConstantPool {
  8. static public final byte CLASS = 7;
  9. static public final byte FIELDREF = 9;
  10. static public final byte METHODREF = 10;
  11. static public final byte INTERFACE_METHODREF = 11;
  12. /** Any one of the XXX_REF types. */
  13. static public final byte ANY_REF = -1;
  14. static public final byte STRING = 8;
  15. static public final byte INTEGER = 3;
  16. static public final byte FLOAT = 4;
  17. static public final byte LONG = 5;
  18. static public final byte DOUBLE = 6;
  19. static public final byte METHOD_HANDLE = 15;
  20. static public final byte METHOD_TYPE = 16;
  21. static public final byte INVOKE_DYNAMIC = 18;
  22. static public final byte NAME_AND_TYPE = 12;
  23. static public final byte UTF8 = 1;
  24. /** The entries in the constant pool.
  25. * The first element (constant_pool[0]) is an unused dummy. */
  26. CpoolEntry[] pool;
  27. /** Number of elements in the constant pool, not counting
  28. * the initial dummy element (with index 0). */
  29. int count;
  30. public final int getCount()
  31. {
  32. return count;
  33. }
  34. /**
  35. * Get the index'th entry in pool.
  36. * Will throw ArrayIndexOutOfBoundsException on an invalid index
  37. */
  38. public final CpoolEntry getPoolEntry(int index)
  39. {
  40. return pool[index];
  41. }
  42. boolean locked;
  43. CpoolEntry[] hashTab;
  44. void rehash ()
  45. {
  46. if (hashTab == null && count > 0)
  47. {
  48. // Entries may not have been hashed before. Make sure they are now.
  49. for (int i = pool.length; --i >= 0; )
  50. {
  51. CpoolEntry entry = pool[i];
  52. // Make sure entry.hash is not the default value 0.
  53. if (entry != null)
  54. entry.hashCode();
  55. }
  56. }
  57. hashTab = new CpoolEntry[count < 5 ? 101 : 2 * count];
  58. if (pool != null)
  59. {
  60. for (int i = pool.length; --i >= 0; )
  61. {
  62. CpoolEntry entry = pool[i];
  63. if (entry != null)
  64. entry.add_hashed (this);
  65. }
  66. }
  67. }
  68. public CpoolUtf8 addUtf8 (String s)
  69. {
  70. s = s.intern();
  71. int h = s.hashCode();
  72. // Check if we already have a matching CONSTANT_Utf8.
  73. if (hashTab == null)
  74. rehash();
  75. int index = (h & 0x7FFFFFFF) % hashTab.length;
  76. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  77. {
  78. if (h == entry.hash && entry instanceof CpoolUtf8)
  79. {
  80. CpoolUtf8 utf = (CpoolUtf8) entry;
  81. if (utf.string == s)
  82. return utf;
  83. }
  84. }
  85. if (locked)
  86. throw new Error("adding new Utf8 entry to locked contant pool: "+s);
  87. return new CpoolUtf8(this, h, s);
  88. }
  89. public CpoolClass addClass (ObjectType otype)
  90. {
  91. CpoolClass entry = addClass(addUtf8(otype.getInternalName()));
  92. entry.clas = otype;
  93. return entry;
  94. }
  95. public CpoolMethodHandle addMethodHandle(Method method) {
  96. int kind;
  97. if ((method.access_flags & Access.STATIC) != 0)
  98. kind = 6; // REF_invokeStatic
  99. else if (method.classfile.isInterface())
  100. kind = 9; // REF_invokeInterface
  101. else if ("<init>".equals(method.getName()))
  102. kind = 8; // REF_newInvokeSpecial
  103. else if ((method.access_flags & Access.PRIVATE) != 0)
  104. kind = 7; // REF_invokeSpecial
  105. else
  106. kind = 5; // REF_invokeVirtual
  107. return addMethodHandle(kind, addMethodRef(method));
  108. }
  109. public CpoolMethodHandle addMethodHandle(int kind, CpoolRef reference) {
  110. int h = CpoolMethodHandle.hashCode(kind, reference);
  111. // Check if we already have a matching CONSTANT_METHOD_HANDLE
  112. if (hashTab == null)
  113. rehash();
  114. int index = (h & 0x7FFFFFFF) % hashTab.length;
  115. for (CpoolEntry entry = hashTab[index]; entry != null;
  116. entry = entry.next) {
  117. if (h == entry.hash
  118. && entry instanceof CpoolMethodHandle
  119. && ((CpoolMethodHandle)entry).kind == kind
  120. && ((CpoolMethodHandle)entry).reference == reference)
  121. return (CpoolMethodHandle)entry;
  122. }
  123. return new CpoolMethodHandle(this, h, kind, reference);
  124. }
  125. public CpoolClass addClass (CpoolUtf8 name)
  126. {
  127. int h = CpoolClass.hashCode(name);
  128. // Check if we already have a matching CONSTANT_Class.
  129. if (hashTab == null)
  130. rehash();
  131. int index = (h & 0x7FFFFFFF) % hashTab.length;
  132. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  133. {
  134. if (h == entry.hash && entry instanceof CpoolClass)
  135. {
  136. CpoolClass ent = (CpoolClass) entry;
  137. if (ent.name == name)
  138. return ent;
  139. }
  140. }
  141. return new CpoolClass (this, h, name);
  142. }
  143. CpoolValue1 addValue1 (int tag, int val)
  144. {
  145. int h = CpoolValue1.hashCode(val);
  146. // Check if we already have a matching CONSTANT_Integer.
  147. if (hashTab == null)
  148. rehash();
  149. int index = (h & 0x7FFFFFFF) % hashTab.length;
  150. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  151. {
  152. if (h == entry.hash && entry instanceof CpoolValue1)
  153. {
  154. CpoolValue1 ent = (CpoolValue1) entry;
  155. if (ent.tag == tag && ent.value == val)
  156. return ent;
  157. }
  158. }
  159. return new CpoolValue1 (this, tag, h, val);
  160. }
  161. CpoolValue2 addValue2 (int tag, long val)
  162. {
  163. int h = CpoolValue2.hashCode(val);
  164. // Check if we already have a matching CONSTANT_Long
  165. if (hashTab == null)
  166. rehash();
  167. int index = (h & 0x7FFFFFFF) % hashTab.length;
  168. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  169. {
  170. if (h == entry.hash && entry instanceof CpoolValue2)
  171. {
  172. CpoolValue2 ent = (CpoolValue2) entry;
  173. if (ent.tag == tag && ent.value == val)
  174. return ent;
  175. }
  176. }
  177. return new CpoolValue2 (this, tag, h, val);
  178. }
  179. public CpoolValue1 addInt (int val)
  180. {
  181. return addValue1(INTEGER, val);
  182. }
  183. public CpoolValue2 addLong (long val)
  184. {
  185. return addValue2(LONG, val);
  186. }
  187. public CpoolValue1 addFloat (float val)
  188. {
  189. return addValue1(FLOAT, Float.floatToIntBits(val));
  190. }
  191. public CpoolValue2 addDouble (double val)
  192. {
  193. return addValue2(DOUBLE, Double.doubleToLongBits(val));
  194. }
  195. public final CpoolString addString (String string)
  196. {
  197. return addString(addUtf8(string));
  198. }
  199. public CpoolString addString (CpoolUtf8 str)
  200. {
  201. int h = CpoolString.hashCode (str);
  202. // Check if we already have a matching CONSTANT_String.
  203. if (hashTab == null)
  204. rehash();
  205. int index = (h & 0x7FFFFFFF) % hashTab.length;
  206. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  207. {
  208. if (h == entry.hash && entry instanceof CpoolString)
  209. {
  210. CpoolString ent = (CpoolString) entry;
  211. if (ent.str == str)
  212. return ent;
  213. }
  214. }
  215. return new CpoolString (this, h, str);
  216. }
  217. public CpoolNameAndType addNameAndType (Method method)
  218. {
  219. CpoolUtf8 name = addUtf8(method.getName());
  220. CpoolUtf8 type = addUtf8(method.getSignature ());
  221. return addNameAndType(name, type);
  222. }
  223. public CpoolNameAndType addNameAndType (Field field)
  224. {
  225. CpoolUtf8 name = addUtf8(field.getName());
  226. CpoolUtf8 type = addUtf8(field.getSignature ());
  227. return addNameAndType(name, type);
  228. }
  229. public CpoolNameAndType
  230. addNameAndType (CpoolUtf8 name, CpoolUtf8 type)
  231. {
  232. int h = CpoolNameAndType.hashCode (name, type);
  233. // Check if we already have a matching CONSTANT_NAME_AND_TYPE
  234. if (hashTab == null)
  235. rehash();
  236. int index = (h & 0x7FFFFFFF) % hashTab.length;
  237. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  238. {
  239. if (h == entry.hash
  240. && entry instanceof CpoolNameAndType
  241. && ((CpoolNameAndType)entry).name == name
  242. && ((CpoolNameAndType)entry).type == type)
  243. return (CpoolNameAndType)entry;
  244. }
  245. return new CpoolNameAndType(this, h, name, type);
  246. }
  247. public CpoolRef
  248. addRef (int tag, CpoolClass clas, CpoolNameAndType nameAndType)
  249. {
  250. int h = CpoolRef.hashCode (clas, nameAndType);
  251. // Check if we already have a matching CONSTANT_Ref
  252. if (hashTab == null)
  253. rehash();
  254. int index = (h & 0x7FFFFFFF) % hashTab.length;
  255. for (CpoolEntry entry = hashTab[index]; entry != null; entry = entry.next)
  256. {
  257. if (h == entry.hash && entry instanceof CpoolRef)
  258. {
  259. CpoolRef ref = (CpoolRef) entry;
  260. if (ref.tag == tag
  261. && ref.clas == clas
  262. && ref.nameAndType== nameAndType)
  263. return ref;
  264. }
  265. }
  266. return new CpoolRef (this, h, tag, clas, nameAndType);
  267. }
  268. public CpoolRef addMethodRef (Method method)
  269. {
  270. CpoolClass clas = addClass(method.classfile);
  271. int tag;
  272. if ((method.getDeclaringClass().getModifiers() & Access.INTERFACE) == 0)
  273. tag = 10; // CONSTANT_Methodref
  274. else
  275. tag = 11; // CONSTANT_InterfaceMethodref
  276. CpoolNameAndType nameType = addNameAndType(method);
  277. return addRef(tag, clas, nameType);
  278. }
  279. public CpoolRef addFieldRef (Field field)
  280. {
  281. CpoolClass clas = addClass(field.owner);
  282. int tag = 9; // CONSTANT_Fieldref
  283. CpoolNameAndType nameType = addNameAndType(field);
  284. return addRef(tag, clas, nameType);
  285. }
  286. void write (java.io.DataOutputStream dstr) throws java.io.IOException
  287. {
  288. dstr.writeShort(count+1);
  289. for (int i = 1; i <= count; i++)
  290. {
  291. CpoolEntry entry = pool[i];
  292. if (entry != null)
  293. entry.write (dstr);
  294. }
  295. locked = true;
  296. }
  297. /** Get or create a CpoolEntry at a given index.
  298. * If there is an existing entry, it must match the tag.
  299. * If not, a new one is create of the class appropriate for the tag.
  300. */
  301. CpoolEntry getForced(int index, int tag) {
  302. index = index & 0xffff;
  303. CpoolEntry entry = pool[index];
  304. if (entry == null) {
  305. if (locked)
  306. throw new Error("adding new entry to locked contant pool");
  307. switch (tag) {
  308. case UTF8: entry = new CpoolUtf8(); break;
  309. case INTEGER:
  310. case FLOAT: entry = new CpoolValue1(tag); break;
  311. case LONG:
  312. case DOUBLE: entry = new CpoolValue2(tag); break;
  313. case CLASS: entry = new CpoolClass(); break;
  314. case STRING: entry = new CpoolString(); break;
  315. case ANY_REF:
  316. case FIELDREF:
  317. case METHODREF:
  318. case INTERFACE_METHODREF: entry = new CpoolRef(tag); break;
  319. case NAME_AND_TYPE: entry = new CpoolNameAndType(); break;
  320. case INVOKE_DYNAMIC: entry = new CpoolInvokeDynamic(); break;
  321. case METHOD_HANDLE: entry = new CpoolMethodHandle(); break;
  322. case METHOD_TYPE: entry = new CpoolMethodType(); break;
  323. default: System.err.println("tag: "+tag);
  324. }
  325. pool[index] = entry;
  326. entry.index = index;
  327. } else if (entry.getTag() != tag) {
  328. if (entry.getTag() == ANY_REF)
  329. ((CpoolRef) entry).tag = tag;
  330. else if (tag != ANY_REF)
  331. throw new ClassFormatError("conflicting constant pool tags at "+index);
  332. }
  333. return entry;
  334. }
  335. CpoolClass getForcedClass (int index)
  336. {
  337. return (CpoolClass) getForced (index, ConstantPool.CLASS);
  338. }
  339. public ConstantPool () { }
  340. public ConstantPool (java.io.DataInputStream dstr)
  341. throws java.io.IOException
  342. {
  343. count = dstr.readUnsignedShort() - 1;
  344. pool = new CpoolEntry[count+1];
  345. for (int i = 1; i <= count; i++)
  346. {
  347. byte tag = dstr.readByte();
  348. CpoolEntry entry = getForced(i, tag);
  349. switch (tag)
  350. {
  351. case UTF8:
  352. ((CpoolUtf8) entry).string = dstr.readUTF();
  353. break;
  354. case INTEGER:
  355. case FLOAT:
  356. ((CpoolValue1) entry).value = dstr.readInt();
  357. break;
  358. case LONG:
  359. case DOUBLE:
  360. ((CpoolValue2) entry).value = dstr.readLong();
  361. i++;
  362. break;
  363. case CLASS:
  364. ((CpoolClass) entry).name =
  365. (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
  366. break;
  367. case STRING:
  368. ((CpoolString) entry).str =
  369. (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
  370. break;
  371. case FIELDREF:
  372. case METHODREF:
  373. case INTERFACE_METHODREF:
  374. CpoolRef ref = (CpoolRef) entry;
  375. ref.clas = getForcedClass(dstr.readUnsignedShort());
  376. ref.nameAndType = (CpoolNameAndType)
  377. getForced(dstr.readUnsignedShort(), NAME_AND_TYPE);
  378. break;
  379. case METHOD_HANDLE:
  380. CpoolMethodHandle mh = (CpoolMethodHandle) entry;
  381. mh.kind = dstr.readUnsignedByte();
  382. /*
  383. int kindtag = mh.kind <= 4 ? FIELDREF
  384. : mh.kid == 5 ? METHODREF
  385. : ...;
  386. */
  387. mh.reference = (CpoolRef)
  388. getForced(dstr.readUnsignedShort(), ANY_REF);
  389. break;
  390. case METHOD_TYPE:
  391. CpoolMethodType mt = (CpoolMethodType) entry;
  392. mt.descriptor =
  393. (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
  394. break;
  395. case INVOKE_DYNAMIC:
  396. CpoolInvokeDynamic idyn = (CpoolInvokeDynamic) entry;
  397. idyn.bootstrapMethodIndex = dstr.readUnsignedShort();
  398. idyn.nameAndType = (CpoolNameAndType)
  399. getForced(dstr.readUnsignedShort(), NAME_AND_TYPE);
  400. break;
  401. case NAME_AND_TYPE:
  402. CpoolNameAndType ntyp = (CpoolNameAndType) entry;
  403. ntyp.name = (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
  404. ntyp.type = (CpoolUtf8) getForced(dstr.readUnsignedShort(), UTF8);
  405. break;
  406. }
  407. }
  408. }
  409. }