001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.utils.bytecode; 022 023import java.util.*; 024import java.io.*; 025 026/** 027 * Build a Java class file constant pool. 028 * 029 * @author Thomas Down 030 * @author Matthew Pocock 031 */ 032 033public class ConstantPool { 034 private static final byte CONSTANT_Class = 7; 035 private static final byte CONSTANT_Fieldref = 9; 036 private static final byte CONSTANT_Methodref = 10; 037 private static final byte CONSTANT_InterfaceMethodref = 11; 038 private static final byte CONSTANT_String = 8; 039 private static final byte CONSTANT_Integer = 3; 040 private static final byte CONSTANT_Float = 4; 041 private static final byte CONSTANT_Long = 5; 042 private static final byte CONSTANT_Double = 6; 043 private static final byte CONSTANT_NameAndType = 12; 044 private static final byte CONSTANT_Utf8 = 1; 045 046 private List constants; 047 048 { 049 constants = new ArrayList(); 050 constants.add(null); // Initial padder. 051 } 052 053 // Publically visible constant types 054 055 public int resolveClass(CodeClass c) { 056 return resolve(new CPTypedStringEntry(CONSTANT_Class, resolveUtf8(c.getJName()))); 057 } 058 059 public int resolveField(CodeField f) { 060 try { 061 return resolve(new CPRefEntry(CONSTANT_Fieldref, resolveClass(f.getContainingClass()), resolveNameAndType(f.getName(), f.getType().getDescriptor()))); 062 } catch (NullPointerException npe) { 063 throw new Error("Can't resolve filed " + f); 064 } 065 } 066 067 public int resolveMethod(CodeMethod m) { 068 return resolve(new CPRefEntry(CONSTANT_Methodref, resolveClass(m.getContainingClass()), resolveNameAndType(m.getName(), m.getDescriptor()))); 069 } 070 071 public int resolveInterfaceMethod(CodeMethod m) { 072 return resolve(new CPRefEntry(CONSTANT_InterfaceMethodref, resolveClass(m.getContainingClass()), resolveNameAndType(m.getName(), m.getDescriptor()))); 073 } 074 075 public int resolveString(String s) { 076 return resolve(new CPTypedStringEntry(CONSTANT_String, resolveUtf8(s))); 077 } 078 079 public int resolveInt(int i) { 080 return resolve(new CPIntEntry(i)); 081 } 082 083 public int resolveFloat(float f) { 084 return resolve(new CPFloatEntry(f)); 085 } 086 087 public int resolveLong(long l) { 088 return resolve(new CPLongEntry(l)); 089 } 090 091 public int resolveDouble(double d) { 092 return resolve(new CPDoubleEntry(d)); 093 } 094 095 // internal resolvers 096 097 public int resolveUtf8(String s) { 098 return resolve(new CPUtf8Entry(s)); 099 } 100 101 public int resolveNameAndType(String name, String desc) { 102 return resolve(new CPNameAndTypeEntry(resolveUtf8(name), resolveUtf8(desc))); 103 } 104 105 // The master resolver 106 107 private int resolve(CPEntry e) { 108 for (int i = 1; i < constants.size(); ++i) { 109 CPEntry e2 = (CPEntry) constants.get(i); 110 if (e2 != null && e.equals(e2)) 111 return i; 112 } 113 int i = constants.size(); 114 constants.add(e); 115 for (int k = 1; k < e.needSlots(); ++k) 116 constants.add(null); 117 return i; 118 } 119 120 // Output again 121 122 public int constantPoolSize() { 123 return constants.size(); 124 } 125 126 public void writeConstantPool(DataOutput d) throws IOException { 127// int count = 1; 128 for (Iterator i = constants.iterator(); i.hasNext(); ) { 129 CPEntry e = (CPEntry) i.next(); 130 if (e != null) { 131// System.out.println("Writing constant " + count + " " + e); 132// count += e.needSlots(); 133 e.write(d); 134 } 135 } 136 } 137 138 // Types for storing the cpool 139 140 private static interface CPEntry { 141 public void write(DataOutput d) throws IOException; 142 public int needSlots(); 143 } 144 145 private static class CPTypedStringEntry implements CPEntry { 146 byte tag; 147 int name; 148 149 CPTypedStringEntry(byte tag, int name) { 150 this.tag = tag; 151 this.name = name; 152 } 153 154 public boolean equals(Object o) { 155 if (! (o instanceof CPTypedStringEntry)) 156 return false; 157 158 CPTypedStringEntry cte = (CPTypedStringEntry) o; 159 return (cte.name == name && cte.tag == tag); 160 } 161 162 public void write(DataOutput d) throws IOException { 163 d.writeByte(tag); 164 d.writeShort(name); 165 } 166 167 public int needSlots() { 168 return 1; 169 } 170 171 public String toString() { 172 return "CPTypedStringEntry tag=" + tag + " name=" + name; 173 } 174 } 175 176 private static class CPRefEntry implements CPEntry { 177 byte tag; 178 int clazz; 179 int name; 180 181 CPRefEntry(byte tag, int clazz, int name) { 182 this.tag = tag; 183 this.clazz = clazz; 184 this.name = name; 185 } 186 187 public boolean equals(Object o) { 188 if (! (o instanceof CPRefEntry)) 189 return false; 190 191 CPRefEntry cte = (CPRefEntry) o; 192 return (cte.clazz == clazz && cte.name == name && cte.tag == tag); 193 } 194 195 public void write(DataOutput d) throws IOException { 196 d.writeByte(tag); 197 d.writeShort(clazz); 198 d.writeShort(name); 199 } 200 201 public int needSlots() { 202 return 1; 203 } 204 205 public String toString() { 206 return "CPRefEntry tag=" + tag + " class=" + clazz + " name=" + name; 207 } 208 } 209 210 private static class CPIntEntry implements CPEntry { 211 int val; 212 213 CPIntEntry(int val) { 214 this.val = val; 215 } 216 217 public boolean equals(Object o) { 218 if (! (o instanceof CPIntEntry)) 219 return false; 220 221 return (((CPIntEntry) o).val == val); 222 } 223 224 public void write(DataOutput d) throws IOException { 225 d.writeByte(CONSTANT_Integer); 226 d.writeInt(val); 227 } 228 229 public int needSlots() { 230 return 1; 231 } 232 233 public String toString() { 234 return "CPIntEntry val=" + val; 235 } 236 } 237 238 private static class CPLongEntry implements CPEntry { 239 long val; 240 241 CPLongEntry(long val) { 242 this.val = val; 243 } 244 245 public boolean equals(Object o) { 246 if (! (o instanceof CPLongEntry)) 247 return false; 248 249 return (((CPLongEntry) o).val == val); 250 } 251 252 public void write(DataOutput d) throws IOException { 253 d.writeByte(CONSTANT_Long); 254 d.writeLong(val); 255 } 256 257 public int needSlots() { 258 return 2; 259 } 260 261 public String toString() { 262 return "CPLongEntry val=" + val; 263 } 264 } 265 266 private static class CPFloatEntry implements CPEntry { 267 float val; 268 269 CPFloatEntry(float val) { 270 this.val = val; 271 } 272 273 public boolean equals(Object o) { 274 if (! (o instanceof CPFloatEntry)) 275 return false; 276 277 return 278 (((CPFloatEntry) o).val == val) || 279 (Float.isNaN(((CPFloatEntry) o).val) && Float.isNaN(val)); 280 } 281 282 public void write(DataOutput d) throws IOException { 283 d.writeByte(CONSTANT_Float); 284 d.writeFloat(val); 285 } 286 287 public int needSlots() { 288 return 1; 289 } 290 291 public String toString() { 292 return "CPFloatEntry val=" + val; 293 } 294 } 295 296 private static class CPDoubleEntry implements CPEntry { 297 double val; 298 299 CPDoubleEntry(double val) { 300 this.val = val; 301 } 302 303 public boolean equals(Object o) { 304 if (! (o instanceof CPDoubleEntry)) 305 return false; 306 307 return 308 (((CPDoubleEntry) o).val == val) || 309 (Double.isNaN(((CPDoubleEntry) o).val) && Double.isNaN(val)); 310 } 311 312 public void write(DataOutput d) throws IOException { 313 d.writeByte(CONSTANT_Double); 314 d.writeDouble(val); 315 } 316 317 public int needSlots() { 318 return 2; 319 } 320 321 public String toString() { 322 return "CPDoubleEntry val=" + val; 323 } 324 } 325 326 private static class CPUtf8Entry implements CPEntry { 327 String val; 328 329 CPUtf8Entry(String val) { 330 this.val = val; 331 } 332 333 public boolean equals(Object o) { 334 if (! (o instanceof CPUtf8Entry)) 335 return false; 336 337 return (((CPUtf8Entry) o).val.equals(val)); 338 } 339 340 public void write(DataOutput d) throws IOException { 341 d.writeByte(CONSTANT_Utf8); 342 d.writeUTF(val); 343 } 344 345 public int needSlots() { 346 return 1; 347 } 348 349 public String toString() { 350 return "CPUtf8Entry val=" + val; 351 } 352 } 353 354 private static class CPNameAndTypeEntry implements CPEntry { 355 int name; 356 int desc; 357 358 CPNameAndTypeEntry(int name, int desc) { 359 this.name = name; 360 this.desc = desc; 361 } 362 363 public boolean equals(Object o) { 364 if (! (o instanceof CPNameAndTypeEntry)) 365 return false; 366 367 CPNameAndTypeEntry cpnte = (CPNameAndTypeEntry) o; 368 return (cpnte.desc == desc && cpnte.name == name); 369 } 370 371 public void write(DataOutput d) throws IOException { 372 d.writeByte(CONSTANT_NameAndType); 373 d.writeShort(name); 374 d.writeShort(desc); 375 } 376 377 public int needSlots() { 378 return 1; 379 } 380 381 public String toString() { 382 return "CPNameAndTypeEntry name=" + name + " desc=" + desc; 383 } 384 } 385}