1 /*
   2  * Copyright (c) 2005, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package ilib;
  25 
  26 import java.io.IOException;
  27 import java.io.File;
  28 import java.io.FileOutputStream;
  29 import java.io.DataOutputStream;
  30 import java.util.List;
  31 import java.util.Iterator;
  32 import java.util.ArrayList;
  33 
  34 public class Inject implements RuntimeConstants {
  35 
  36     public static byte[] instrumentation(Options opt,
  37                                          ClassLoader loader,
  38                                          String className,
  39                                          byte[] classfileBuffer) {
  40         ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
  41         (new Inject(className, c, loader == null, opt)).doit();
  42         return c.result();
  43     }
  44 
  45     static boolean verbose = false;
  46 
  47     final String className;
  48     final ClassReaderWriter c;
  49     final boolean isSystem;
  50     final Options options;
  51 
  52     int constantPoolCount;
  53     int methodsCount;
  54     int methodsCountPos;
  55     int profiler;
  56     int wrappedTrackerIndex = 0;
  57     int thisClassIndex = 0;
  58 
  59     TrackerInjector callInjector;
  60     TrackerInjector allocInjector;
  61     TrackerInjector defaultInjector;
  62 
  63     static interface TrackerInjector extends Injector {
  64         void reinit(int tracker);
  65         int stackSize(int currentSize);
  66     }
  67 
  68     static class SimpleInjector implements TrackerInjector {
  69         byte[] injection;
  70 
  71         public int stackSize(int currentSize) {
  72             return currentSize;
  73         }
  74 
  75         public void reinit(int tracker) {
  76             injection = new byte[3];
  77             injection[0] = (byte)opc_invokestatic;
  78             injection[1] = (byte)(tracker >> 8);
  79             injection[2] = (byte)tracker;
  80         }
  81 
  82         public byte[] bytecodes(String className, String methodName, int location) {
  83             return injection;
  84         }
  85     }
  86 
  87     static class ObjectInjector implements TrackerInjector {
  88         byte[] injection;
  89 
  90         public int stackSize(int currentSize) {
  91             return currentSize + 1;
  92         }
  93 
  94         public void reinit(int tracker) {
  95             injection = new byte[4];
  96             injection[0] = (byte)opc_dup;
  97             injection[1] = (byte)opc_invokestatic;
  98             injection[2] = (byte)(tracker >> 8);
  99             injection[3] = (byte)tracker;
 100         }
 101 
 102         public byte[] bytecodes(String className, String methodName, int location) {
 103             return injection;
 104         }
 105     }
 106 
 107     class IndexedInjector implements TrackerInjector {
 108         int counter = 0;
 109         int tracker;
 110         List<Info> infoList = new ArrayList<>();
 111 
 112         public int stackSize(int currentSize) {
 113             return currentSize + 1;
 114         }
 115 
 116         public void reinit(int tracker) {
 117             this.tracker = tracker;
 118         }
 119 
 120         void dump(File outDir, String filename) throws IOException {
 121             try (FileOutputStream fileOut =
 122                      new FileOutputStream(new File(outDir, filename));
 123                  DataOutputStream dataOut = new DataOutputStream(fileOut))
 124             {
 125                 String currentClassName = null;
 126 
 127                 dataOut.writeInt(infoList.size());
 128                 for (Iterator<Info> it = infoList.iterator(); it.hasNext(); ) {
 129                     Info info = it.next();
 130                     if (!info.className.equals(currentClassName)) {
 131                         dataOut.writeInt(123456); // class name marker
 132                         currentClassName = info.className;
 133                         dataOut.writeUTF(currentClassName);
 134                     }
 135                     dataOut.writeInt(info.location);
 136                     dataOut.writeUTF(info.methodName);
 137                 }
 138             }
 139         }
 140 
 141         public byte[] bytecodes(String className, String methodName, int location) {
 142             byte[] injection = new byte[6];
 143             int injectedIndex = options.fixedIndex != 0? options.fixedIndex : ++counter;
 144             infoList.add(new Info(counter, className, methodName, location));
 145             injection[0] = (byte)opc_sipush;
 146             injection[1] = (byte)(injectedIndex >> 8);
 147             injection[2] = (byte)injectedIndex;
 148             injection[3] = (byte)opc_invokestatic;
 149             injection[4] = (byte)(tracker >> 8);
 150             injection[5] = (byte)tracker;
 151             return injection;
 152         }
 153     }
 154 
 155     Inject(String className, ClassReaderWriter c, boolean isSystem, Options options) {
 156         this.className = className;
 157         this.c = c;
 158         this.isSystem = isSystem;
 159         this.options = options;
 160     }
 161 
 162     void doit() {
 163         int i;
 164         c.copy(4 + 2 + 2); // magic min/maj version
 165         int constantPoolCountPos = c.generatedPosition();
 166         constantPoolCount = c.copyU2();
 167         // copy old constant pool
 168         c.copyConstantPool(constantPoolCount);
 169 
 170         if (verbose) {
 171             System.out.println("ConstantPool expanded from: " +
 172                                constantPoolCount);
 173         }
 174 
 175         profiler = addClassToConstantPool(options.trackerClassName);
 176         if (options.shouldInstrumentNew || options.shouldInstrumentObjectInit) {
 177             if (options.shouldInstrumentIndexed) {
 178                 if (allocInjector == null) {
 179                     // first time - create it
 180                     allocInjector = new IndexedInjector();
 181                 }
 182                 int allocTracker = addMethodToConstantPool(profiler,
 183                                                            options.allocTrackerMethodName,
 184                                                            "(I)V");
 185                 allocInjector.reinit(allocTracker);
 186             } else if (options.shouldInstrumentObject) {
 187                 if (allocInjector == null) {
 188                     // first time - create it
 189                     allocInjector = new ObjectInjector();
 190                 }
 191                 int allocTracker = addMethodToConstantPool(profiler,
 192                                                            options.allocTrackerMethodName,
 193                                                            "(Ljava/lang/Object;)V");
 194                 allocInjector.reinit(allocTracker);
 195             } else {
 196                 if (allocInjector == null) {
 197                     // first time - create it
 198                     allocInjector = new SimpleInjector();
 199                 }
 200                 int allocTracker = addMethodToConstantPool(profiler,
 201                                                            options.allocTrackerMethodName,
 202                                                            "()V");
 203                 allocInjector.reinit(allocTracker);
 204             }
 205             defaultInjector = allocInjector;
 206         }
 207         if (options.shouldInstrumentCall) {
 208             if (options.shouldInstrumentIndexed) {
 209                 if (callInjector == null) {
 210                     // first time - create it
 211                     callInjector = new IndexedInjector();
 212                 }
 213                 int callTracker = addMethodToConstantPool(profiler,
 214                                                           options.callTrackerMethodName,
 215                                                           "(I)V");
 216                 callInjector.reinit(callTracker);
 217             } else {
 218                 if (callInjector == null) {
 219                     // first time - create it
 220                     callInjector = new SimpleInjector();
 221                 }
 222                 int callTracker = addMethodToConstantPool(profiler,
 223                                                           options.callTrackerMethodName,
 224                                                           "()V");
 225                 callInjector.reinit(callTracker);
 226             }
 227             defaultInjector = callInjector;
 228         }
 229 
 230         if (verbose) {
 231             System.out.println("To: " + constantPoolCount);
 232         }
 233 
 234         c.setSection(1);
 235 
 236         c.copy(2 + 2 + 2);  // access, this, super
 237         int interfaceCount = c.copyU2();
 238         if (verbose) {
 239             System.out.println("interfaceCount: " + interfaceCount);
 240         }
 241         c.copy(interfaceCount * 2);
 242         copyFields(); // fields
 243         copyMethods(); // methods
 244         int attrCountPos = c.generatedPosition();
 245         int attrCount = c.copyU2();
 246         if (verbose) {
 247             System.out.println("class attrCount: " + attrCount);
 248         }
 249         // copy the class attributes
 250         copyAttrs(attrCount);
 251 
 252         c.randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
 253     }
 254 
 255 
 256     void copyFields() {
 257         int count = c.copyU2();
 258         if (verbose) {
 259             System.out.println("fields count: " + count);
 260         }
 261         for (int i = 0; i < count; ++i) {
 262             c.copy(6); // access, name, descriptor
 263             int attrCount = c.copyU2();
 264             if (verbose) {
 265                 System.out.println("field attr count: " + attrCount);
 266             }
 267             copyAttrs(attrCount);
 268         }
 269     }
 270 
 271     void copyMethods() {
 272         methodsCountPos = c.generatedPosition();
 273         methodsCount = c.copyU2();
 274         int initialMethodsCount = methodsCount;
 275         if (verbose) {
 276             System.out.println("methods count: " + methodsCount);
 277         }
 278         for (int i = 0; i < initialMethodsCount; ++i) {
 279             copyMethod();
 280         }
 281     }
 282 
 283     void copyMethod() {
 284         int accessFlags = c.copyU2();// access flags
 285         if (options.shouldInstrumentNativeMethods && (accessFlags & ACC_NATIVE) != 0) {
 286             wrapNativeMethod(accessFlags);
 287             return;
 288         }
 289         int nameIndex = c.copyU2();  // name
 290         String methodName = c.constantPoolString(nameIndex);
 291         c.copyU2();                  // descriptor
 292         int attrCount = c.copyU2();  // attribute count
 293         if (verbose) {
 294             System.out.println("methods attr count: " + attrCount);
 295         }
 296         for (int i = 0; i < attrCount; ++i) {
 297             copyAttrForMethod(methodName, accessFlags);
 298         }
 299     }
 300 
 301     void wrapNativeMethod(int accessFlags) {
 302         // first, copy the native method with the name changed
 303         // accessFlags have already been copied
 304         int nameIndex = c.readU2();        // name
 305         String methodName = c.constantPoolString(nameIndex);
 306         String wrappedMethodName = options.wrappedPrefix + methodName;
 307         int wrappedNameIndex = writeCPEntryUtf8(wrappedMethodName);
 308         c.writeU2(wrappedNameIndex);       // change to the wrapped name
 309 
 310         int descriptorIndex = c.copyU2();  // descriptor index
 311 
 312         int attrCount = c.copyU2();        // attribute count
 313         // need to replicate these attributes (esp Exceptions) in wrapper
 314         // so mark this location so we can rewind
 315         c.markLocalPositionStart();
 316         for (int i = 0; i < attrCount; ++i) {
 317             copyAttrForMethod(methodName, accessFlags);
 318         }
 319         if (true) {
 320             System.err.println("   wrapped: " + methodName);
 321         }
 322 
 323         // now write the wrapper method
 324         c.writeU2(accessFlags & ~ACC_NATIVE);
 325         c.writeU2(nameIndex);           // original unwrapped name
 326         c.writeU2(descriptorIndex);     // descriptor is the same
 327 
 328         c.writeU2(attrCount + 1);       // wrapped plus a code attribute
 329         // rewind to wrapped attributes
 330         c.rewind();
 331         for (int i = 0; i < attrCount; ++i) {
 332             copyAttrForMethod(methodName, accessFlags);
 333         }
 334 
 335         // generate a Code attribute for the wrapper method
 336         int wrappedIndex = addMethodToConstantPool(getThisClassIndex(),
 337                                                    wrappedNameIndex,
 338                                                    descriptorIndex);
 339         String descriptor = c.constantPoolString(descriptorIndex);
 340         createWrapperCodeAttr(nameIndex, accessFlags, descriptor, wrappedIndex);
 341 
 342         // increment method count
 343         c.randomAccessWriteU2(methodsCountPos, ++methodsCount);
 344     }
 345 
 346     void copyAttrs(int attrCount) {
 347         for (int i = 0; i < attrCount; ++i) {
 348             copyAttr();
 349         }
 350     }
 351 
 352     void copyAttr() {
 353         c.copy(2);             // name
 354         int len = c.copyU4();  // attr len
 355         if (verbose) {
 356             System.out.println("attr len: " + len);
 357         }
 358         c.copy(len);           // attribute info
 359     }
 360 
 361     void copyAttrForMethod(String methodName, int accessFlags) {
 362         int nameIndex = c.copyU2();   // name
 363         // check for Code attr
 364         if (nameIndex == c.codeAttributeIndex) {
 365             try {
 366                 copyCodeAttr(methodName);
 367             } catch (IOException exc) {
 368                 System.err.println("Code Exception - " + exc);
 369                 System.exit(1);
 370             }
 371         } else {
 372             int len = c.copyU4();     // attr len
 373             if (verbose) {
 374                 System.out.println("method attr len: " + len);
 375             }
 376             c.copy(len);              // attribute info
 377         }
 378     }
 379 
 380     void copyAttrForCode(InjectBytecodes ib) throws IOException {
 381         int nameIndex = c.copyU2();   // name
 382 
 383         // check for Code attr
 384         if (nameIndex == c.lineNumberAttributeIndex) {
 385             ib.copyLineNumberAttr();
 386         } else if (nameIndex == c.localVarAttributeIndex) {
 387             ib.copyLocalVarAttr();
 388         } else {
 389             int len = c.copyU4();     // attr len
 390             if (verbose) {
 391                 System.out.println("code attr len: " + len);
 392             }
 393             c.copy(len);              // attribute info
 394         }
 395     }
 396 
 397     void copyCodeAttr(String methodName) throws IOException {
 398         if (verbose) {
 399             System.out.println("Code attr found");
 400         }
 401         int attrLengthPos = c.generatedPosition();
 402         int attrLength = c.copyU4();        // attr len
 403         int maxStack = c.readU2();          // max stack
 404         c.writeU2(defaultInjector == null? maxStack :
 405                   defaultInjector.stackSize(maxStack));  // big enough for injected code
 406         c.copyU2();                         // max locals
 407         int codeLengthPos = c.generatedPosition();
 408         int codeLength = c.copyU4();        // code length
 409         if (options.targetMethod != null && !options.targetMethod.equals(methodName)) {
 410             c.copy(attrLength - 8); // copy remainder minus already copied
 411             return;
 412         }
 413         if (isSystem) {
 414             if (codeLength == 1 && methodName.equals("finalize")) {
 415                 if (verbose) {
 416                     System.out.println("empty system finalizer not instrumented");
 417                 }
 418                 c.copy(attrLength - 8); // copy remainder minus already copied
 419                 return;
 420             }
 421             if (codeLength == 1 && methodName.equals("<init>")) {
 422                 if (verbose) {
 423                     System.out.println("empty system constructor not instrumented");
 424                 }
 425                 if (!options.shouldInstrumentObjectInit) {
 426                     c.copy(attrLength - 8); // copy remainder minus already copied
 427                     return;
 428                 }
 429             }
 430             if (methodName.equals("<clinit>")) {
 431                 if (verbose) {
 432                     System.out.println("system class initializer not instrumented");
 433                 }
 434                 c.copy(attrLength - 8); // copy remainder minus already copied
 435                 return;
 436             }
 437         }
 438         if (options.shouldInstrumentObjectInit
 439             && (!className.equals("java/lang/Object")
 440                 || !methodName.equals("<init>"))) {
 441             c.copy(attrLength - 8); // copy remainder minus already copied
 442             return;
 443         }
 444 
 445         InjectBytecodes ib = new InjectBytecodes(c, codeLength, className, methodName);
 446 
 447         if (options.shouldInstrumentNew) {
 448             ib.injectAfter(opc_new, allocInjector);
 449             ib.injectAfter(opc_newarray, allocInjector);
 450             ib.injectAfter(opc_anewarray, allocInjector);
 451             ib.injectAfter(opc_multianewarray, allocInjector);
 452         }
 453         if (options.shouldInstrumentCall) {
 454             ib.inject(0, callInjector.bytecodes(className, methodName, 0));
 455         }
 456         if (options.shouldInstrumentObjectInit) {
 457             ib.inject(0, allocInjector.bytecodes(className, methodName, 0));
 458         }
 459 
 460         ib.adjustOffsets();
 461 
 462         // fix up code length
 463         int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
 464         c.randomAccessWriteU4(codeLengthPos, newCodeLength);
 465         if (verbose) {
 466             System.out.println("code length old: " + codeLength +
 467                                ", new: " + newCodeLength);
 468         }
 469 
 470         ib.copyExceptionTable();
 471 
 472         int attrCount = c.copyU2();
 473         for (int i = 0; i < attrCount; ++i) {
 474             copyAttrForCode(ib);
 475         }
 476 
 477         // fix up attr length
 478         int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
 479         c.randomAccessWriteU4(attrLengthPos, newAttrLength);
 480         if (verbose) {
 481             System.out.println("attr length old: " + attrLength +
 482                                ", new: " + newAttrLength);
 483         }
 484     }
 485 
 486     int nextDescriptorIndex(String descriptor, int index) {
 487         switch (descriptor.charAt(index)) {
 488         case 'B': // byte
 489         case 'C': // char
 490         case 'I': // int
 491         case 'S': // short
 492         case 'Z': // boolean
 493         case 'F': // float
 494         case 'D': // double
 495         case 'J': // long
 496             return index + 1;
 497         case 'L': // object
 498             int i = index + 1;
 499             while (descriptor.charAt(i) != ';') {
 500                 ++i;
 501             }
 502             return i + 1;
 503         case '[': // array
 504             return nextDescriptorIndex(descriptor, index + 1);
 505         }
 506         throw new InternalError("should not reach here");
 507     }
 508 
 509     int getWrappedTrackerIndex() {
 510         if (wrappedTrackerIndex == 0) {
 511             wrappedTrackerIndex = addMethodToConstantPool(profiler,
 512                                                           options.wrappedTrackerMethodName,
 513                                                           "(Ljava/lang/String;I)V");
 514         }
 515         return wrappedTrackerIndex;
 516     }
 517 
 518     int getThisClassIndex() {
 519         if (thisClassIndex == 0) {
 520             thisClassIndex = addClassToConstantPool(className);
 521         }
 522         return thisClassIndex;
 523     }
 524 
 525     int computeMaxLocals(String descriptor, int accessFlags) {
 526         int index = 1;
 527         int slot = 0;
 528 
 529         if ((accessFlags & ACC_STATIC) == 0) {
 530             ++slot;
 531         }
 532         char type;
 533         while ((type = descriptor.charAt(index)) != ')') {
 534             switch (type) {
 535             case 'B': // byte
 536             case 'C': // char
 537             case 'I': // int
 538             case 'S': // short
 539             case 'Z': // boolean
 540             case 'F': // float
 541             case 'L': // object
 542             case '[': // array
 543                 ++slot;
 544                 break;
 545             case 'D': // double
 546             case 'J': // long
 547                 slot += 2;
 548                 break;
 549             }
 550             index = nextDescriptorIndex(descriptor, index);
 551         }
 552 
 553         return slot;
 554     }
 555 
 556 
 557     void createWrapperCodeAttr(int methodNameIndex, int accessFlags,
 558                                String descriptor, int wrappedIndex) {
 559         int maxLocals = computeMaxLocals(descriptor, accessFlags);
 560 
 561         c.writeU2(c.codeAttributeIndex);        //
 562         int attrLengthPos = c.generatedPosition();
 563         c.writeU4(0);                // attr len -- fix up below
 564         c.writeU2(maxLocals + 4);    // max stack
 565         c.writeU2(maxLocals);        // max locals
 566         int codeLengthPos = c.generatedPosition();
 567         c.writeU4(0);                // code length -- fix up below
 568 
 569         int methodStringIndex = writeCPEntryString(methodNameIndex);
 570 
 571         c.writeU1(opc_ldc_w);
 572         c.writeU2(methodStringIndex);  // send the method name
 573         c.writeU1(opc_sipush);
 574         c.writeU2(options.fixedIndex);
 575         c.writeU1(opc_invokestatic);
 576         c.writeU2(getWrappedTrackerIndex());
 577 
 578         // set-up args
 579         int index = 1;
 580         int slot = 0;
 581         if ((accessFlags & ACC_STATIC) == 0) {
 582             c.writeU1(opc_aload_0);  // this
 583             ++slot;
 584         }
 585         char type;
 586         while ((type = descriptor.charAt(index)) != ')') {
 587             switch (type) {
 588             case 'B': // byte
 589             case 'C': // char
 590             case 'I': // int
 591             case 'S': // short
 592             case 'Z': // boolean
 593                 c.writeU1(opc_iload);
 594                 c.writeU1(slot);
 595                 ++slot;
 596                 break;
 597             case 'F': // float
 598                 c.writeU1(opc_fload);
 599                 c.writeU1(slot);
 600                 ++slot;
 601                 break;
 602             case 'D': // double
 603                 c.writeU1(opc_dload);
 604                 c.writeU1(slot);
 605                 slot += 2;
 606                 break;
 607             case 'J': // long
 608                 c.writeU1(opc_lload);
 609                 c.writeU1(slot);
 610                 slot += 2;
 611                 break;
 612             case 'L': // object
 613             case '[': // array
 614                 c.writeU1(opc_aload);
 615                 c.writeU1(slot);
 616                 ++slot;
 617                 break;
 618             }
 619             index = nextDescriptorIndex(descriptor, index);
 620         }
 621 
 622         // call the wrapped version
 623         if ((accessFlags & ACC_STATIC) == 0) {
 624             c.writeU1(opc_invokevirtual);
 625         } else {
 626             c.writeU1(opc_invokestatic);
 627         }
 628         c.writeU2(wrappedIndex);
 629 
 630         // return correct type
 631         switch (descriptor.charAt(index+1)) {
 632         case 'B': // byte
 633         case 'C': // char
 634         case 'I': // int
 635         case 'S': // short
 636         case 'Z': // boolean
 637             c.writeU1(opc_ireturn);
 638             break;
 639         case 'F': // float
 640             c.writeU1(opc_freturn);
 641             break;
 642         case 'D': // double
 643             c.writeU1(opc_dreturn);
 644             break;
 645         case 'J': // long
 646             c.writeU1(opc_lreturn);
 647             break;
 648         case 'L': // object
 649         case '[': // array
 650             c.writeU1(opc_areturn);
 651             break;
 652         case 'V': // void
 653             c.writeU1(opc_return);
 654             break;
 655         }
 656 
 657         // end of code
 658 
 659         // fix up code length
 660         int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
 661         c.randomAccessWriteU4(codeLengthPos, newCodeLength);
 662 
 663         c.writeU2(0);                // exception table length
 664         c.writeU2(0);                // attribute count
 665 
 666         // fix up attr length
 667         int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
 668         c.randomAccessWriteU4(attrLengthPos, newAttrLength);
 669     }
 670 
 671 
 672     int addClassToConstantPool(String className) {
 673         int prevSection = c.setSection(0);
 674         int classNameIndex = writeCPEntryUtf8(className);
 675         int classIndex = writeCPEntryClass(classNameIndex);
 676         c.setSection(prevSection);
 677         return classIndex;
 678     }
 679 
 680     int addMethodToConstantPool(int classIndex,
 681                                 String methodName,
 682                                 String descr) {
 683         int prevSection = c.setSection(0);
 684         int methodNameIndex = writeCPEntryUtf8(methodName);
 685         int descrIndex = writeCPEntryUtf8(descr);
 686         c.setSection(prevSection);
 687         return addMethodToConstantPool(classIndex, methodNameIndex, descrIndex);
 688     }
 689 
 690     int addMethodToConstantPool(int classIndex,
 691                                 int methodNameIndex,
 692                                 int descrIndex) {
 693         int prevSection = c.setSection(0);
 694         int nameAndTypeIndex = writeCPEntryNameAndType(methodNameIndex,
 695                                                        descrIndex);
 696         int methodIndex = writeCPEntryMethodRef(classIndex, nameAndTypeIndex);
 697         c.setSection(prevSection);
 698         return methodIndex;
 699     }
 700 
 701     int writeCPEntryUtf8(String str) {
 702         int prevSection = c.setSection(0);
 703         int len = str.length();
 704         c.writeU1(CONSTANT_UTF8); // Utf8 tag
 705         c.writeU2(len);
 706         for (int i = 0; i < len; ++i) {
 707             c.writeU1(str.charAt(i));
 708         }
 709         c.setSection(prevSection);
 710         return constantPoolCount++;
 711     }
 712 
 713     int writeCPEntryString(int utf8Index) {
 714         int prevSection = c.setSection(0);
 715         c.writeU1(CONSTANT_STRING);
 716         c.writeU2(utf8Index);
 717         c.setSection(prevSection);
 718         return constantPoolCount++;
 719     }
 720 
 721     int writeCPEntryClass(int classNameIndex) {
 722         int prevSection = c.setSection(0);
 723         c.writeU1(CONSTANT_CLASS);
 724         c.writeU2(classNameIndex);
 725         c.setSection(prevSection);
 726         return constantPoolCount++;
 727     }
 728 
 729     int writeCPEntryNameAndType(int nameIndex, int descrIndex) {
 730         int prevSection = c.setSection(0);
 731         c.writeU1(CONSTANT_NAMEANDTYPE);
 732         c.writeU2(nameIndex);
 733         c.writeU2(descrIndex);
 734         c.setSection(prevSection);
 735         return constantPoolCount++;
 736     }
 737 
 738     int writeCPEntryMethodRef(int classIndex, int nameAndTypeIndex) {
 739         int prevSection = c.setSection(0);
 740         c.writeU1(CONSTANT_METHOD);
 741         c.writeU2(classIndex);
 742         c.writeU2(nameAndTypeIndex);
 743         c.setSection(prevSection);
 744         return constantPoolCount++;
 745     }
 746 }