1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.generic; 23 24 25 import com.sun.org.apache.bcel.internal.Constants; 26 import com.sun.org.apache.bcel.internal.classfile.*; 27 import java.util.HashMap; 28 29 /** 30 * This class is used to build up a constant pool. The user adds 31 * constants via `addXXX' methods, `addString', `addClass', 32 * etc.. These methods return an index into the constant 33 * pool. Finally, `getFinalConstantPool()' returns the constant pool 34 * built up. Intermediate versions of the constant pool can be 35 * obtained with `getConstantPool()'. A constant pool has capacity for 36 * Constants.MAX_SHORT entries. Note that the first (0) is used by the 37 * JVM and that Double and Long constants need two slots. 38 * 39 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 40 * @see Constant 41 */ 42 public class ConstantPoolGen implements java.io.Serializable { 43 protected int size = 1024; // Inital size, sufficient in most cases 44 protected Constant[] constants = new Constant[size]; 45 protected int index = 1; // First entry (0) used by JVM 46 47 private static final String METHODREF_DELIM = ":"; 48 private static final String IMETHODREF_DELIM = "#"; 49 private static final String FIELDREF_DELIM = "&"; 50 private static final String NAT_DELIM = "%"; 51 52 private static class Index implements java.io.Serializable { 53 int index; 54 Index(int i) { index = i; } 55 } 56 57 /** 58 * Initialize with given array of constants. 59 * 60 * @param c array of given constants, new ones will be appended 61 */ 62 public ConstantPoolGen(Constant[] cs) { 63 if(cs.length > size) { 64 size = cs.length; 65 constants = new Constant[size]; 66 } 67 68 System.arraycopy(cs, 0, constants, 0, cs.length); 69 70 if(cs.length > 0) 71 index = cs.length; 72 73 for(int i=1; i < index; i++) { 74 Constant c = constants[i]; 75 76 if(c instanceof ConstantString) { 77 ConstantString s = (ConstantString)c; 78 ConstantUtf8 u8 = (ConstantUtf8)constants[s.getStringIndex()]; 79 80 string_table.put(u8.getBytes(), new Index(i)); 81 } else if(c instanceof ConstantClass) { 82 ConstantClass s = (ConstantClass)c; 83 ConstantUtf8 u8 = (ConstantUtf8)constants[s.getNameIndex()]; 84 85 class_table.put(u8.getBytes(), new Index(i)); 86 } else if(c instanceof ConstantNameAndType) { 87 ConstantNameAndType n = (ConstantNameAndType)c; 88 ConstantUtf8 u8 = (ConstantUtf8)constants[n.getNameIndex()]; 89 ConstantUtf8 u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()]; 90 91 n_a_t_table.put(u8.getBytes() + NAT_DELIM + u8_2.getBytes(), new Index(i)); 92 } else if(c instanceof ConstantUtf8) { 93 ConstantUtf8 u = (ConstantUtf8)c; 94 95 utf8_table.put(u.getBytes(), new Index(i)); 96 } else if(c instanceof ConstantCP) { 97 ConstantCP m = (ConstantCP)c; 98 ConstantClass clazz = (ConstantClass)constants[m.getClassIndex()]; 99 ConstantNameAndType n = (ConstantNameAndType)constants[m.getNameAndTypeIndex()]; 100 101 ConstantUtf8 u8 = (ConstantUtf8)constants[clazz.getNameIndex()]; 102 String class_name = u8.getBytes().replace('/', '.'); 103 104 u8 = (ConstantUtf8)constants[n.getNameIndex()]; 105 String method_name = u8.getBytes(); 106 107 u8 = (ConstantUtf8)constants[n.getSignatureIndex()]; 108 String signature = u8.getBytes(); 109 110 String delim = METHODREF_DELIM; 111 112 if(c instanceof ConstantInterfaceMethodref) 113 delim = IMETHODREF_DELIM; 114 else if(c instanceof ConstantFieldref) 115 delim = FIELDREF_DELIM; 116 117 cp_table.put(class_name + delim + method_name + delim + signature, new Index(i)); 118 } 119 } 120 } 121 122 /** 123 * Initialize with given constant pool. 124 */ 125 public ConstantPoolGen(ConstantPool cp) { 126 this(cp.getConstantPool()); 127 } 128 129 /** 130 * Create empty constant pool. 131 */ 132 public ConstantPoolGen() {} 133 134 /** Resize internal array of constants. 135 */ 136 protected void adjustSize() { 137 if(index + 3 >= size) { 138 Constant[] cs = constants; 139 140 size *= 2; 141 constants = new Constant[size]; 142 System.arraycopy(cs, 0, constants, 0, index); 143 } 144 } 145 146 private HashMap string_table = new HashMap(); 147 148 /** 149 * Look for ConstantString in ConstantPool containing String `str'. 150 * 151 * @param str String to search for 152 * @return index on success, -1 otherwise 153 */ 154 public int lookupString(String str) { 155 Index index = (Index)string_table.get(str); 156 return (index != null)? index.index : -1; 157 } 158 159 /** 160 * Add a new String constant to the ConstantPool, if it is not already in there. 161 * 162 * @param str String to add 163 * @return index of entry 164 */ 165 public int addString(String str) { 166 int ret; 167 168 if((ret = lookupString(str)) != -1) 169 return ret; // Already in CP 170 171 int utf8 = addUtf8(str); 172 173 adjustSize(); 174 175 ConstantString s = new ConstantString(utf8); 176 177 ret = index; 178 constants[index++] = s; 179 180 string_table.put(str, new Index(ret)); 181 182 return ret; 183 } 184 185 private HashMap class_table = new HashMap(); 186 187 /** 188 * Look for ConstantClass in ConstantPool named `str'. 189 * 190 * @param str String to search for 191 * @return index on success, -1 otherwise 192 */ 193 public int lookupClass(String str) { 194 Index index = (Index)class_table.get(str.replace('.', '/')); 195 return (index != null)? index.index : -1; 196 } 197 198 private int addClass_(String clazz) { 199 int ret; 200 201 if((ret = lookupClass(clazz)) != -1) 202 return ret; // Already in CP 203 204 adjustSize(); 205 206 ConstantClass c = new ConstantClass(addUtf8(clazz)); 207 208 ret = index; 209 constants[index++] = c; 210 211 class_table.put(clazz, new Index(ret)); 212 213 return ret; 214 } 215 216 /** 217 * Add a new Class reference to the ConstantPool, if it is not already in there. 218 * 219 * @param str Class to add 220 * @return index of entry 221 */ 222 public int addClass(String str) { 223 return addClass_(str.replace('.', '/')); 224 } 225 226 /** 227 * Add a new Class reference to the ConstantPool for a given type. 228 * 229 * @param str Class to add 230 * @return index of entry 231 */ 232 public int addClass(ObjectType type) { 233 return addClass(type.getClassName()); 234 } 235 236 /** 237 * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY 238 * instruction, e.g. to the ConstantPool. 239 * 240 * @param type type of array class 241 * @return index of entry 242 */ 243 public int addArrayClass(ArrayType type) { 244 return addClass_(type.getSignature()); 245 } 246 247 /** 248 * Look for ConstantInteger in ConstantPool. 249 * 250 * @param n integer number to look for 251 * @return index on success, -1 otherwise 252 */ 253 public int lookupInteger(int n) { 254 for(int i=1; i < index; i++) { 255 if(constants[i] instanceof ConstantInteger) { 256 ConstantInteger c = (ConstantInteger)constants[i]; 257 258 if(c.getBytes() == n) 259 return i; 260 } 261 } 262 263 return -1; 264 } 265 266 /** 267 * Add a new Integer constant to the ConstantPool, if it is not already in there. 268 * 269 * @param n integer number to add 270 * @return index of entry 271 */ 272 public int addInteger(int n) { 273 int ret; 274 275 if((ret = lookupInteger(n)) != -1) 276 return ret; // Already in CP 277 278 adjustSize(); 279 280 ret = index; 281 constants[index++] = new ConstantInteger(n); 282 283 return ret; 284 } 285 286 /** 287 * Look for ConstantFloat in ConstantPool. 288 * 289 * @param n Float number to look for 290 * @return index on success, -1 otherwise 291 */ 292 public int lookupFloat(float n) { 293 int bits = Float.floatToIntBits(n); 294 295 for(int i=1; i < index; i++) { 296 if(constants[i] instanceof ConstantFloat) { 297 ConstantFloat c = (ConstantFloat)constants[i]; 298 299 if(Float.floatToIntBits(c.getBytes()) == bits) 300 return i; 301 } 302 } 303 304 return -1; 305 } 306 307 /** 308 * Add a new Float constant to the ConstantPool, if it is not already in there. 309 * 310 * @param n Float number to add 311 * @return index of entry 312 */ 313 public int addFloat(float n) { 314 int ret; 315 316 if((ret = lookupFloat(n)) != -1) 317 return ret; // Already in CP 318 319 adjustSize(); 320 321 ret = index; 322 constants[index++] = new ConstantFloat(n); 323 324 return ret; 325 } 326 327 private HashMap utf8_table = new HashMap(); 328 329 /** 330 * Look for ConstantUtf8 in ConstantPool. 331 * 332 * @param n Utf8 string to look for 333 * @return index on success, -1 otherwise 334 */ 335 public int lookupUtf8(String n) { 336 Index index = (Index)utf8_table.get(n); 337 338 return (index != null)? index.index : -1; 339 } 340 341 /** 342 * Add a new Utf8 constant to the ConstantPool, if it is not already in there. 343 * 344 * @param n Utf8 string to add 345 * @return index of entry 346 */ 347 public int addUtf8(String n) { 348 int ret; 349 350 if((ret = lookupUtf8(n)) != -1) 351 return ret; // Already in CP 352 353 adjustSize(); 354 355 ret = index; 356 constants[index++] = new ConstantUtf8(n); 357 358 utf8_table.put(n, new Index(ret)); 359 360 return ret; 361 } 362 363 /** 364 * Look for ConstantLong in ConstantPool. 365 * 366 * @param n Long number to look for 367 * @return index on success, -1 otherwise 368 */ 369 public int lookupLong(long n) { 370 for(int i=1; i < index; i++) { 371 if(constants[i] instanceof ConstantLong) { 372 ConstantLong c = (ConstantLong)constants[i]; 373 374 if(c.getBytes() == n) 375 return i; 376 } 377 } 378 379 return -1; 380 } 381 382 /** 383 * Add a new long constant to the ConstantPool, if it is not already in there. 384 * 385 * @param n Long number to add 386 * @return index of entry 387 */ 388 public int addLong(long n) { 389 int ret; 390 391 if((ret = lookupLong(n)) != -1) 392 return ret; // Already in CP 393 394 adjustSize(); 395 396 ret = index; 397 constants[index] = new ConstantLong(n); 398 index += 2; // Wastes one entry according to spec 399 400 return ret; 401 } 402 403 /** 404 * Look for ConstantDouble in ConstantPool. 405 * 406 * @param n Double number to look for 407 * @return index on success, -1 otherwise 408 */ 409 public int lookupDouble(double n) { 410 long bits = Double.doubleToLongBits(n); 411 412 for(int i=1; i < index; i++) { 413 if(constants[i] instanceof ConstantDouble) { 414 ConstantDouble c = (ConstantDouble)constants[i]; 415 416 if(Double.doubleToLongBits(c.getBytes()) == bits) 417 return i; 418 } 419 } 420 421 return -1; 422 } 423 424 /** 425 * Add a new double constant to the ConstantPool, if it is not already in there. 426 * 427 * @param n Double number to add 428 * @return index of entry 429 */ 430 public int addDouble(double n) { 431 int ret; 432 433 if((ret = lookupDouble(n)) != -1) 434 return ret; // Already in CP 435 436 adjustSize(); 437 438 ret = index; 439 constants[index] = new ConstantDouble(n); 440 index += 2; // Wastes one entry according to spec 441 442 return ret; 443 } 444 445 private HashMap n_a_t_table = new HashMap(); 446 447 /** 448 * Look for ConstantNameAndType in ConstantPool. 449 * 450 * @param name of variable/method 451 * @param signature of variable/method 452 * @return index on success, -1 otherwise 453 */ 454 public int lookupNameAndType(String name, String signature) { 455 Index index = (Index)n_a_t_table.get(name + NAT_DELIM + signature); 456 return (index != null)? index.index : -1; 457 } 458 459 /** 460 * Add a new NameAndType constant to the ConstantPool if it is not already 461 * in there. 462 * 463 * @param n NameAndType string to add 464 * @return index of entry 465 */ 466 public int addNameAndType(String name, String signature) { 467 int ret; 468 int name_index, signature_index; 469 470 if((ret = lookupNameAndType(name, signature)) != -1) 471 return ret; // Already in CP 472 473 adjustSize(); 474 475 name_index = addUtf8(name); 476 signature_index = addUtf8(signature); 477 ret = index; 478 constants[index++] = new ConstantNameAndType(name_index, signature_index); 479 480 n_a_t_table.put(name + NAT_DELIM + signature, new Index(ret)); 481 return ret; 482 } 483 484 private HashMap cp_table = new HashMap(); 485 486 /** 487 * Look for ConstantMethodref in ConstantPool. 488 * 489 * @param class_name Where to find method 490 * @param method_name Guess what 491 * @param signature return and argument types 492 * @return index on success, -1 otherwise 493 */ 494 public int lookupMethodref(String class_name, String method_name, String signature) { 495 Index index = (Index)cp_table.get(class_name + METHODREF_DELIM + method_name + 496 METHODREF_DELIM + signature); 497 return (index != null)? index.index : -1; 498 } 499 500 public int lookupMethodref(MethodGen method) { 501 return lookupMethodref(method.getClassName(), method.getName(), 502 method.getSignature()); 503 } 504 505 /** 506 * Add a new Methodref constant to the ConstantPool, if it is not already 507 * in there. 508 * 509 * @param n Methodref string to add 510 * @return index of entry 511 */ 512 public int addMethodref(String class_name, String method_name, String signature) { 513 int ret, class_index, name_and_type_index; 514 515 if((ret = lookupMethodref(class_name, method_name, signature)) != -1) 516 return ret; // Already in CP 517 518 adjustSize(); 519 520 name_and_type_index = addNameAndType(method_name, signature); 521 class_index = addClass(class_name); 522 ret = index; 523 constants[index++] = new ConstantMethodref(class_index, name_and_type_index); 524 525 cp_table.put(class_name + METHODREF_DELIM + method_name + 526 METHODREF_DELIM + signature, new Index(ret)); 527 528 return ret; 529 } 530 531 public int addMethodref(MethodGen method) { 532 return addMethodref(method.getClassName(), method.getName(), 533 method.getSignature()); 534 } 535 536 /** 537 * Look for ConstantInterfaceMethodref in ConstantPool. 538 * 539 * @param class_name Where to find method 540 * @param method_name Guess what 541 * @param signature return and argument types 542 * @return index on success, -1 otherwise 543 */ 544 public int lookupInterfaceMethodref(String class_name, String method_name, String signature) { 545 Index index = (Index)cp_table.get(class_name + IMETHODREF_DELIM + method_name + 546 IMETHODREF_DELIM + signature); 547 return (index != null)? index.index : -1; 548 } 549 550 public int lookupInterfaceMethodref(MethodGen method) { 551 return lookupInterfaceMethodref(method.getClassName(), method.getName(), 552 method.getSignature()); 553 } 554 555 /** 556 * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already 557 * in there. 558 * 559 * @param n InterfaceMethodref string to add 560 * @return index of entry 561 */ 562 public int addInterfaceMethodref(String class_name, String method_name, String signature) { 563 int ret, class_index, name_and_type_index; 564 565 if((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1) 566 return ret; // Already in CP 567 568 adjustSize(); 569 570 class_index = addClass(class_name); 571 name_and_type_index = addNameAndType(method_name, signature); 572 ret = index; 573 constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index); 574 575 cp_table.put(class_name + IMETHODREF_DELIM + method_name + 576 IMETHODREF_DELIM + signature, new Index(ret)); 577 578 return ret; 579 } 580 581 public int addInterfaceMethodref(MethodGen method) { 582 return addInterfaceMethodref(method.getClassName(), method.getName(), 583 method.getSignature()); 584 } 585 586 /** 587 * Look for ConstantFieldref in ConstantPool. 588 * 589 * @param class_name Where to find method 590 * @param field_name Guess what 591 * @param signature return and argument types 592 * @return index on success, -1 otherwise 593 */ 594 public int lookupFieldref(String class_name, String field_name, String signature) { 595 Index index = (Index)cp_table.get(class_name + FIELDREF_DELIM + field_name + 596 FIELDREF_DELIM + signature); 597 return (index != null)? index.index : -1; 598 } 599 600 /** 601 * Add a new Fieldref constant to the ConstantPool, if it is not already 602 * in there. 603 * 604 * @param n Fieldref string to add 605 * @return index of entry 606 */ 607 public int addFieldref(String class_name, String field_name, String signature) { 608 int ret; 609 int class_index, name_and_type_index; 610 611 if((ret = lookupFieldref(class_name, field_name, signature)) != -1) 612 return ret; // Already in CP 613 614 adjustSize(); 615 616 class_index = addClass(class_name); 617 name_and_type_index = addNameAndType(field_name, signature); 618 ret = index; 619 constants[index++] = new ConstantFieldref(class_index, name_and_type_index); 620 621 cp_table.put(class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature, new Index(ret)); 622 623 return ret; 624 } 625 626 /** 627 * @param i index in constant pool 628 * @return constant pool entry at index i 629 */ 630 public Constant getConstant(int i) { return constants[i]; } 631 632 /** 633 * Use with care! 634 * 635 * @param i index in constant pool 636 * @param c new constant pool entry at index i 637 */ 638 public void setConstant(int i, Constant c) { constants[i] = c; } 639 640 /** 641 * @return intermediate constant pool 642 */ 643 public ConstantPool getConstantPool() { 644 return new ConstantPool(constants); 645 } 646 647 /** 648 * @return current size of constant pool 649 */ 650 public int getSize() { 651 return index; 652 } 653 654 /** 655 * @return constant pool with proper length 656 */ 657 public ConstantPool getFinalConstantPool() { 658 Constant[] cs = new Constant[index]; 659 660 System.arraycopy(constants, 0, cs, 0, index); 661 662 return new ConstantPool(cs); 663 } 664 665 /** 666 * @return String representation. 667 */ 668 public String toString() { 669 StringBuffer buf = new StringBuffer(); 670 671 for(int i=1; i < index; i++) 672 buf.append(i + ")" + constants[i] + "\n"); 673 674 return buf.toString(); 675 } 676 677 /** Import constant from another ConstantPool and return new index. 678 */ 679 public int addConstant(Constant c, ConstantPoolGen cp) { 680 Constant[] constants = cp.getConstantPool().getConstantPool(); 681 682 switch(c.getTag()) { 683 case Constants.CONSTANT_String: { 684 ConstantString s = (ConstantString)c; 685 ConstantUtf8 u8 = (ConstantUtf8)constants[s.getStringIndex()]; 686 687 return addString(u8.getBytes()); 688 } 689 690 case Constants.CONSTANT_Class: { 691 ConstantClass s = (ConstantClass)c; 692 ConstantUtf8 u8 = (ConstantUtf8)constants[s.getNameIndex()]; 693 694 return addClass(u8.getBytes()); 695 } 696 697 case Constants.CONSTANT_NameAndType: { 698 ConstantNameAndType n = (ConstantNameAndType)c; 699 ConstantUtf8 u8 = (ConstantUtf8)constants[n.getNameIndex()]; 700 ConstantUtf8 u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()]; 701 702 return addNameAndType(u8.getBytes(), u8_2.getBytes()); 703 } 704 705 case Constants.CONSTANT_Utf8: 706 return addUtf8(((ConstantUtf8)c).getBytes()); 707 708 case Constants.CONSTANT_Double: 709 return addDouble(((ConstantDouble)c).getBytes()); 710 711 case Constants.CONSTANT_Float: 712 return addFloat(((ConstantFloat)c).getBytes()); 713 714 case Constants.CONSTANT_Long: 715 return addLong(((ConstantLong)c).getBytes()); 716 717 case Constants.CONSTANT_Integer: 718 return addInteger(((ConstantInteger)c).getBytes()); 719 720 case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref: 721 case Constants.CONSTANT_Fieldref: { 722 ConstantCP m = (ConstantCP)c; 723 ConstantClass clazz = (ConstantClass)constants[m.getClassIndex()]; 724 ConstantNameAndType n = (ConstantNameAndType)constants[m.getNameAndTypeIndex()]; 725 ConstantUtf8 u8 = (ConstantUtf8)constants[clazz.getNameIndex()]; 726 String class_name = u8.getBytes().replace('/', '.'); 727 728 u8 = (ConstantUtf8)constants[n.getNameIndex()]; 729 String name = u8.getBytes(); 730 731 u8 = (ConstantUtf8)constants[n.getSignatureIndex()]; 732 String signature = u8.getBytes(); 733 734 switch(c.getTag()) { 735 case Constants.CONSTANT_InterfaceMethodref: 736 return addInterfaceMethodref(class_name, name, signature); 737 738 case Constants.CONSTANT_Methodref: 739 return addMethodref(class_name, name, signature); 740 741 case Constants.CONSTANT_Fieldref: 742 return addFieldref(class_name, name, signature); 743 744 default: // Never reached 745 throw new RuntimeException("Unknown constant type " + c); 746 } 747 } 748 749 default: // Never reached 750 throw new RuntimeException("Unknown constant type " + c); 751 } 752 } 753 }