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