1 /*
   2  * Copyright (c) 2007, 2011, 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 com.sun.tools.classfile;
  27 
  28 import java.io.DataOutputStream;
  29 import java.io.IOException;
  30 import java.io.OutputStream;
  31 import java.util.Iterator;
  32 
  33 /**
  34  * See JVMS, section 4.5.
  35  *
  36  *  <p><b>This is NOT part of any supported API.
  37  *  If you write code that depends on this, you do so at your own risk.
  38  *  This code and its internal interfaces are subject to change or
  39  *  deletion without notice.</b>
  40  */
  41 public class ConstantPool {
  42 
  43     public static class InvalidIndex extends ConstantPoolException {
  44         private static final long serialVersionUID = -4350294289300939730L;
  45         InvalidIndex(int index) {
  46             super(index);
  47         }
  48 
  49         @Override
  50         public String getMessage() {
  51             // i18n
  52             return "invalid index #" + index;
  53         }
  54     }
  55 
  56     public static class UnexpectedEntry extends ConstantPoolException {
  57         private static final long serialVersionUID = 6986335935377933211L;
  58         UnexpectedEntry(int index, int expected_tag, int found_tag) {
  59             super(index);
  60             this.expected_tag = expected_tag;
  61             this.found_tag = found_tag;
  62         }
  63 
  64         @Override
  65         public String getMessage() {
  66             // i18n?
  67             return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag;
  68         }
  69 
  70         public final int expected_tag;
  71         public final int found_tag;
  72     }
  73 
  74     public static class InvalidEntry extends ConstantPoolException {
  75         private static final long serialVersionUID = 1000087545585204447L;
  76         InvalidEntry(int index, int tag) {
  77             super(index);
  78             this.tag = tag;
  79         }
  80 
  81         @Override
  82         public String getMessage() {
  83             // i18n?
  84             return "unexpected tag at #" + index + ": " + tag;
  85         }
  86 
  87         public final int tag;
  88     }
  89 
  90     public static class EntryNotFound extends ConstantPoolException {
  91         private static final long serialVersionUID = 2885537606468581850L;
  92         EntryNotFound(Object value) {
  93             super(-1);
  94             this.value = value;
  95         }
  96 
  97         @Override
  98         public String getMessage() {
  99             // i18n?
 100             return "value not found: " + value;
 101         }
 102 
 103         public final Object value;
 104     }
 105 
 106     public static final int CONSTANT_Utf8 = 1;
 107     public static final int CONSTANT_Integer = 3;
 108     public static final int CONSTANT_Float = 4;
 109     public static final int CONSTANT_Long = 5;
 110     public static final int CONSTANT_Double = 6;
 111     public static final int CONSTANT_Class = 7;
 112     public static final int CONSTANT_String = 8;
 113     public static final int CONSTANT_Fieldref = 9;
 114     public static final int CONSTANT_Methodref = 10;
 115     public static final int CONSTANT_InterfaceMethodref = 11;
 116     public static final int CONSTANT_NameAndType = 12;
 117     public static final int CONSTANT_MethodHandle = 15;
 118     public static final int CONSTANT_MethodType = 16;
 119     public static final int CONSTANT_InvokeDynamic = 18;
 120 
 121     public static enum RefKind {
 122         REF_getField(1, "getfield"),
 123         REF_getStatic(2, "getstatic"),
 124         REF_putField(3, "putfield"),
 125         REF_putStatic(4, "putstatic"),
 126         REF_invokeVirtual(5, "invokevirtual"),
 127         REF_invokeStatic(6, "invokestatic"),
 128         REF_invokeSpecial(7, "invokespecial"),
 129         REF_newInvokeSpecial(8, "newinvokespecial"),
 130         REF_invokeInterface(9, "invokeinterface");
 131 
 132         public final int tag;
 133         public final String name;
 134 
 135         RefKind(int tag, String name) {
 136             this.tag = tag;
 137             this.name = name;
 138         }
 139 
 140         static RefKind getRefkind(int tag) {
 141             switch(tag) {
 142                 case 1:
 143                     return REF_getField;
 144                 case 2:
 145                     return REF_getStatic;
 146                 case 3:
 147                     return REF_putField;
 148                 case 4:
 149                     return REF_putStatic;
 150                 case 5:
 151                     return REF_invokeVirtual;
 152                 case 6:
 153                     return REF_invokeStatic;
 154                 case 7:
 155                     return REF_invokeSpecial;
 156                 case 8:
 157                     return REF_newInvokeSpecial;
 158                 case 9:
 159                     return REF_invokeInterface;
 160                 default:
 161                     return null;
 162             }
 163         }
 164     }
 165 
 166     ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
 167         int count = cr.readUnsignedShort();
 168         pool = new CPInfo[count];
 169         for (int i = 1; i < count; i++) {
 170             int tag = cr.readUnsignedByte();
 171             switch (tag) {
 172             case CONSTANT_Class:
 173                 pool[i] = new CONSTANT_Class_info(this, cr);
 174                 break;
 175 
 176             case CONSTANT_Double:
 177                 pool[i] = new CONSTANT_Double_info(cr);
 178                 i++;
 179                 break;
 180 
 181             case CONSTANT_Fieldref:
 182                 pool[i] = new CONSTANT_Fieldref_info(this, cr);
 183                 break;
 184 
 185             case CONSTANT_Float:
 186                 pool[i] = new CONSTANT_Float_info(cr);
 187                 break;
 188 
 189             case CONSTANT_Integer:
 190                 pool[i] = new CONSTANT_Integer_info(cr);
 191                 break;
 192 
 193             case CONSTANT_InterfaceMethodref:
 194                 pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
 195                 break;
 196 
 197             case CONSTANT_InvokeDynamic:
 198                 pool[i] = new CONSTANT_InvokeDynamic_info(this, cr);
 199                 break;
 200 
 201             case CONSTANT_Long:
 202                 pool[i] = new CONSTANT_Long_info(cr);
 203                 i++;
 204                 break;
 205 
 206             case CONSTANT_MethodHandle:
 207                 pool[i] = new CONSTANT_MethodHandle_info(this, cr);
 208                 break;
 209 
 210             case CONSTANT_MethodType:
 211                 pool[i] = new CONSTANT_MethodType_info(this, cr);
 212                 break;
 213 
 214             case CONSTANT_Methodref:
 215                 pool[i] = new CONSTANT_Methodref_info(this, cr);
 216                 break;
 217 
 218             case CONSTANT_NameAndType:
 219                 pool[i] = new CONSTANT_NameAndType_info(this, cr);
 220                 break;
 221 
 222             case CONSTANT_String:
 223                 pool[i] = new CONSTANT_String_info(this, cr);
 224                 break;
 225 
 226             case CONSTANT_Utf8:
 227                 pool[i] = new CONSTANT_Utf8_info(cr);
 228                 break;
 229 
 230             default:
 231                 throw new InvalidEntry(i, tag);
 232             }
 233         }
 234     }
 235 
 236     public ConstantPool(CPInfo[] pool) {
 237         this.pool = pool;
 238     }
 239 
 240     public int size() {
 241         return pool.length;
 242     }
 243 
 244     public int byteLength() {
 245         int length = 2;
 246         for (int i = 1; i < size(); ) {
 247             CPInfo cpInfo = pool[i];
 248             length += cpInfo.byteLength();
 249             i += cpInfo.size();
 250         }
 251         return length;
 252     }
 253 
 254     public CPInfo get(int index) throws InvalidIndex {
 255         if (index <= 0 || index >= pool.length)
 256             throw new InvalidIndex(index);
 257         CPInfo info = pool[index];
 258         if (info == null) {
 259             // this occurs for indices referencing the "second half" of an
 260             // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long
 261             throw new InvalidIndex(index);
 262         }
 263         return pool[index];
 264     }
 265 
 266     private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry {
 267         CPInfo info = get(index);
 268         if (info.getTag() != expected_type)
 269             throw new UnexpectedEntry(index, expected_type, info.getTag());
 270         return info;
 271     }
 272 
 273     public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
 274         return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
 275     }
 276 
 277     public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
 278         return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
 279     }
 280 
 281     public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
 282         return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
 283     }
 284 
 285     public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
 286         return getUTF8Info(index).value;
 287     }
 288 
 289     public int getUTF8Index(String value) throws EntryNotFound {
 290         for (int i = 1; i < pool.length; i++) {
 291             CPInfo info = pool[i];
 292             if (info instanceof CONSTANT_Utf8_info &&
 293                     ((CONSTANT_Utf8_info) info).value.equals(value))
 294                 return i;
 295         }
 296         throw new EntryNotFound(value);
 297     }
 298 
 299     public Iterable<CPInfo> entries() {
 300         return new Iterable<CPInfo>() {
 301             public Iterator<CPInfo> iterator() {
 302                 return new Iterator<CPInfo>() {
 303 
 304                     public boolean hasNext() {
 305                         return next < pool.length;
 306                     }
 307 
 308                     public CPInfo next() {
 309                         current = pool[next];
 310                         switch (current.getTag()) {
 311                             case CONSTANT_Double:
 312                             case CONSTANT_Long:
 313                                 next += 2;
 314                                 break;
 315                             default:
 316                                 next += 1;
 317                         }
 318                         return current;
 319                     }
 320 
 321                     public void remove() {
 322                         throw new UnsupportedOperationException();
 323                     }
 324 
 325                     private CPInfo current;
 326                     private int next = 1;
 327 
 328                 };
 329             }
 330         };
 331     }
 332 
 333     private CPInfo[] pool;
 334 
 335     public interface Visitor<R,P> {
 336         R visitClass(CONSTANT_Class_info info, P p);
 337         R visitDouble(CONSTANT_Double_info info, P p);
 338         R visitFieldref(CONSTANT_Fieldref_info info, P p);
 339         R visitFloat(CONSTANT_Float_info info, P p);
 340         R visitInteger(CONSTANT_Integer_info info, P p);
 341         R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
 342         R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p);
 343         R visitLong(CONSTANT_Long_info info, P p);
 344         R visitNameAndType(CONSTANT_NameAndType_info info, P p);
 345         R visitMethodref(CONSTANT_Methodref_info info, P p);
 346         R visitMethodHandle(CONSTANT_MethodHandle_info info, P p);
 347         R visitMethodType(CONSTANT_MethodType_info info, P p);
 348         R visitString(CONSTANT_String_info info, P p);
 349         R visitUtf8(CONSTANT_Utf8_info info, P p);
 350     }
 351 
 352     public static abstract class CPInfo {
 353         CPInfo() {
 354             this.cp = null;
 355         }
 356 
 357         CPInfo(ConstantPool cp) {
 358             this.cp = cp;
 359         }
 360 
 361         public abstract int getTag();
 362 
 363         /** The number of slots in the constant pool used by this entry.
 364          * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */
 365         public int size() {
 366             return 1;
 367         }
 368 
 369         public abstract int byteLength();
 370 
 371         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
 372 
 373         protected final ConstantPool cp;
 374     }
 375 
 376     public static abstract class CPRefInfo extends CPInfo {
 377         protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException {
 378             super(cp);
 379             this.tag = tag;
 380             class_index = cr.readUnsignedShort();
 381             name_and_type_index = cr.readUnsignedShort();
 382         }
 383 
 384         protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) {
 385             super(cp);
 386             this.tag = tag;
 387             this.class_index = class_index;
 388             this.name_and_type_index = name_and_type_index;
 389         }
 390 
 391         public int getTag() {
 392             return tag;
 393         }
 394 
 395         public int byteLength() {
 396             return 5;
 397         }
 398 
 399         public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
 400             return cp.getClassInfo(class_index);
 401         }
 402 
 403         public String getClassName() throws ConstantPoolException {
 404             return cp.getClassInfo(class_index).getName();
 405         }
 406 
 407         public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
 408             return cp.getNameAndTypeInfo(name_and_type_index);
 409         }
 410 
 411         public final int tag;
 412         public final int class_index;
 413         public final int name_and_type_index;
 414     }
 415 
 416     public static class CONSTANT_Class_info extends CPInfo {
 417         CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException {
 418             super(cp);
 419             name_index = cr.readUnsignedShort();
 420         }
 421 
 422         public CONSTANT_Class_info(ConstantPool cp, int name_index) {
 423             super(cp);
 424             this.name_index = name_index;
 425         }
 426 
 427         public int getTag() {
 428             return CONSTANT_Class;
 429         }
 430 
 431         public int  byteLength() {
 432             return 3;
 433         }
 434 
 435         /**
 436          * Get the raw value of the class referenced by this constant pool entry.
 437          * This will either be the name of the class, in internal form, or a
 438          * descriptor for an array class.
 439          * @return the raw value of the class
 440          */
 441         public String getName() throws ConstantPoolException {
 442             return cp.getUTF8Value(name_index);
 443         }
 444 
 445         /**
 446          * If this constant pool entry identifies either a class or interface type,
 447          * or a possibly multi-dimensional array of a class of interface type,
 448          * return the name of the class or interface in internal form. Otherwise,
 449          * (i.e. if this is a possibly multi-dimensional array of a primitive type),
 450          * return null.
 451          * @return the base class or interface name
 452          */
 453         public String getBaseName() throws ConstantPoolException {
 454             String name = getName();
 455             if (name.startsWith("[")) {
 456                 int index = name.indexOf("[L");
 457                 if (index == -1)
 458                     return null;
 459                 return name.substring(index + 2, name.length() - 1);
 460             } else
 461                 return name;
 462         }
 463 
 464         public int getDimensionCount() throws ConstantPoolException {
 465             String name = getName();
 466             int count = 0;
 467             while (name.charAt(count) == '[')
 468                 count++;
 469             return count;
 470         }
 471 
 472         @Override
 473         public String toString() {
 474             return "CONSTANT_Class_info[name_index: " + name_index + "]";
 475         }
 476 
 477         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 478             return visitor.visitClass(this, data);
 479         }
 480 
 481         public final int name_index;
 482     }
 483 
 484     public static class CONSTANT_Double_info extends CPInfo {
 485         CONSTANT_Double_info(ClassReader cr) throws IOException {
 486             value = cr.readDouble();
 487         }
 488 
 489         public CONSTANT_Double_info(double value) {
 490             this.value = value;
 491         }
 492 
 493         public int getTag() {
 494             return CONSTANT_Double;
 495         }
 496 
 497         public int  byteLength() {
 498             return 9;
 499         }
 500 
 501         @Override
 502         public int size() {
 503             return 2;
 504         }
 505 
 506         @Override
 507         public String toString() {
 508             return "CONSTANT_Double_info[value: " + value + "]";
 509         }
 510 
 511         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 512             return visitor.visitDouble(this, data);
 513         }
 514 
 515         public final double value;
 516     }
 517 
 518     public static class CONSTANT_Fieldref_info extends CPRefInfo {
 519         CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException {
 520             super(cp, cr, CONSTANT_Fieldref);
 521         }
 522 
 523         public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) {
 524             super(cp, CONSTANT_Fieldref, class_index, name_and_type_index);
 525         }
 526 
 527         @Override
 528         public String toString() {
 529             return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
 530         }
 531 
 532         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 533             return visitor.visitFieldref(this, data);
 534         }
 535     }
 536 
 537     public static class CONSTANT_Float_info extends CPInfo {
 538         CONSTANT_Float_info(ClassReader cr) throws IOException {
 539             value = cr.readFloat();
 540         }
 541 
 542         public CONSTANT_Float_info(float value) {
 543             this.value = value;
 544         }
 545 
 546         public int getTag() {
 547             return CONSTANT_Float;
 548         }
 549 
 550         public int byteLength() {
 551             return 5;
 552         }
 553 
 554         @Override
 555         public String toString() {
 556             return "CONSTANT_Float_info[value: " + value + "]";
 557         }
 558 
 559         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 560             return visitor.visitFloat(this, data);
 561         }
 562 
 563         public final float value;
 564     }
 565 
 566     public static class CONSTANT_Integer_info extends CPInfo {
 567         CONSTANT_Integer_info(ClassReader cr) throws IOException {
 568             value = cr.readInt();
 569         }
 570 
 571         public CONSTANT_Integer_info(int value) {
 572             this.value = value;
 573         }
 574 
 575         public int getTag() {
 576             return CONSTANT_Integer;
 577         }
 578 
 579         public int byteLength() {
 580             return 5;
 581         }
 582 
 583         @Override
 584         public String toString() {
 585             return "CONSTANT_Integer_info[value: " + value + "]";
 586         }
 587 
 588         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 589             return visitor.visitInteger(this, data);
 590         }
 591 
 592         public final int value;
 593     }
 594 
 595     public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo {
 596         CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException {
 597             super(cp, cr, CONSTANT_InterfaceMethodref);
 598         }
 599 
 600         public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
 601             super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
 602         }
 603 
 604         @Override
 605         public String toString() {
 606             return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
 607         }
 608 
 609         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 610             return visitor.visitInterfaceMethodref(this, data);
 611         }
 612     }
 613 
 614     public static class CONSTANT_InvokeDynamic_info extends CPInfo {
 615         CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException {
 616             super(cp);
 617             bootstrap_method_attr_index = cr.readUnsignedShort();
 618             name_and_type_index = cr.readUnsignedShort();
 619         }
 620 
 621         public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) {
 622             super(cp);
 623             this.bootstrap_method_attr_index = bootstrap_method_index;
 624             this.name_and_type_index = name_and_type_index;
 625         }
 626 
 627         public int getTag() {
 628             return CONSTANT_InvokeDynamic;
 629         }
 630 
 631         public int byteLength() {
 632             return 5;
 633         }
 634 
 635         @Override
 636         public String toString() {
 637             return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]";
 638         }
 639 
 640         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 641             return visitor.visitInvokeDynamic(this, data);
 642         }
 643 
 644         public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
 645             return cp.getNameAndTypeInfo(name_and_type_index);
 646         }
 647 
 648         public final int bootstrap_method_attr_index;
 649         public final int name_and_type_index;
 650     }
 651 
 652     public static class CONSTANT_Long_info extends CPInfo {
 653         CONSTANT_Long_info(ClassReader cr) throws IOException {
 654             value = cr.readLong();
 655         }
 656 
 657         public CONSTANT_Long_info(long value) {
 658             this.value = value;
 659         }
 660 
 661         public int getTag() {
 662             return CONSTANT_Long;
 663         }
 664 
 665         @Override
 666         public int size() {
 667             return 2;
 668         }
 669 
 670         public int byteLength() {
 671             return 9;
 672         }
 673 
 674         @Override
 675         public String toString() {
 676             return "CONSTANT_Long_info[value: " + value + "]";
 677         }
 678 
 679         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 680             return visitor.visitLong(this, data);
 681         }
 682 
 683         public final long value;
 684     }
 685 
 686     public static class CONSTANT_MethodHandle_info extends CPInfo {
 687         CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException {
 688             super(cp);
 689             reference_kind =  RefKind.getRefkind(cr.readUnsignedByte());
 690             reference_index = cr.readUnsignedShort();
 691         }
 692 
 693         public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) {
 694             super(cp);
 695             this.reference_kind = ref_kind;
 696             this.reference_index = member_index;
 697         }
 698 
 699         public int getTag() {
 700             return CONSTANT_MethodHandle;
 701         }
 702 
 703         public int byteLength() {
 704             return 4;
 705         }
 706 
 707         @Override
 708         public String toString() {
 709             return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]";
 710         }
 711 
 712         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 713             return visitor.visitMethodHandle(this, data);
 714         }
 715 
 716         public CPRefInfo getCPRefInfo() throws ConstantPoolException {
 717             int expected = CONSTANT_Methodref;
 718             int actual = cp.get(reference_index).getTag();
 719             // allow these tag types also:
 720             switch (actual) {
 721                 case CONSTANT_Fieldref:
 722                 case CONSTANT_InterfaceMethodref:
 723                     expected = actual;
 724             }
 725             return (CPRefInfo) cp.get(reference_index, expected);
 726         }
 727 
 728         public final RefKind reference_kind;
 729         public final int reference_index;
 730     }
 731 
 732     public static class CONSTANT_MethodType_info extends CPInfo {
 733         CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException {
 734             super(cp);
 735             descriptor_index = cr.readUnsignedShort();
 736         }
 737 
 738         public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) {
 739             super(cp);
 740             this.descriptor_index = signature_index;
 741         }
 742 
 743         public int getTag() {
 744             return CONSTANT_MethodType;
 745         }
 746 
 747         public int byteLength() {
 748             return 3;
 749         }
 750 
 751         @Override
 752         public String toString() {
 753             return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]";
 754         }
 755 
 756         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 757             return visitor.visitMethodType(this, data);
 758         }
 759 
 760         public String getType() throws ConstantPoolException {
 761             return cp.getUTF8Value(descriptor_index);
 762         }
 763 
 764         public final int descriptor_index;
 765     }
 766 
 767     public static class CONSTANT_Methodref_info extends CPRefInfo {
 768         CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException {
 769             super(cp, cr, CONSTANT_Methodref);
 770         }
 771 
 772         public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
 773             super(cp, CONSTANT_Methodref, class_index, name_and_type_index);
 774         }
 775 
 776         @Override
 777         public String toString() {
 778             return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
 779         }
 780 
 781         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 782             return visitor.visitMethodref(this, data);
 783         }
 784     }
 785 
 786     public static class CONSTANT_NameAndType_info extends CPInfo {
 787         CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
 788             super(cp);
 789             name_index = cr.readUnsignedShort();
 790             type_index = cr.readUnsignedShort();
 791         }
 792 
 793         public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) {
 794             super(cp);
 795             this.name_index = name_index;
 796             this.type_index = type_index;
 797         }
 798 
 799         public int getTag() {
 800             return CONSTANT_NameAndType;
 801         }
 802 
 803         public int byteLength() {
 804             return 5;
 805         }
 806 
 807         public String getName() throws ConstantPoolException {
 808             return cp.getUTF8Value(name_index);
 809         }
 810 
 811         public String getType() throws ConstantPoolException {
 812             return cp.getUTF8Value(type_index);
 813         }
 814 
 815         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 816             return visitor.visitNameAndType(this, data);
 817         }
 818 
 819         @Override
 820         public String toString() {
 821             return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
 822         }
 823 
 824         public final int name_index;
 825         public final int type_index;
 826     }
 827 
 828     public static class CONSTANT_String_info extends CPInfo {
 829         CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException {
 830             super(cp);
 831             string_index = cr.readUnsignedShort();
 832         }
 833 
 834         public CONSTANT_String_info(ConstantPool cp, int string_index) {
 835             super(cp);
 836             this.string_index = string_index;
 837         }
 838 
 839         public int getTag() {
 840             return CONSTANT_String;
 841         }
 842 
 843         public int byteLength() {
 844             return 3;
 845         }
 846 
 847         public String getString() throws ConstantPoolException {
 848             return cp.getUTF8Value(string_index);
 849         }
 850 
 851         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 852             return visitor.visitString(this, data);
 853         }
 854 
 855         @Override
 856         public String toString() {
 857             return "CONSTANT_String_info[class_index: " + string_index + "]";
 858         }
 859 
 860         public final int string_index;
 861     }
 862 
 863     public static class CONSTANT_Utf8_info extends CPInfo {
 864         CONSTANT_Utf8_info(ClassReader cr) throws IOException {
 865             value = cr.readUTF();
 866         }
 867 
 868         public CONSTANT_Utf8_info(String value) {
 869             this.value = value;
 870         }
 871 
 872         public int getTag() {
 873             return CONSTANT_Utf8;
 874         }
 875 
 876         public int byteLength() {
 877             class SizeOutputStream extends OutputStream {
 878                 @Override
 879                 public void write(int b) {
 880                     size++;
 881                 }
 882                 int size;
 883             }
 884             SizeOutputStream sizeOut = new SizeOutputStream();
 885             DataOutputStream out = new DataOutputStream(sizeOut);
 886             try { out.writeUTF(value); } catch (IOException ignore) { }
 887             return 1 + sizeOut.size;
 888         }
 889 
 890         @Override
 891         public String toString() {
 892             if (value.length() < 32 && isPrintableAscii(value))
 893                 return "CONSTANT_Utf8_info[value: \"" + value + "\"]";
 894             else
 895                 return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]";
 896         }
 897 
 898         static boolean isPrintableAscii(String s) {
 899             for (int i = 0; i < s.length(); i++) {
 900                 char c = s.charAt(i);
 901                 if (c < 32 || c >= 127)
 902                     return false;
 903             }
 904             return true;
 905         }
 906 
 907         public <R, D> R accept(Visitor<R, D> visitor, D data) {
 908             return visitor.visitUtf8(this, data);
 909         }
 910 
 911         public final String value;
 912     }
 913 
 914 }