jdk/test/java/lang/instrument/ilib/Inject.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/ilib/Inject.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,745 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package ilib;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.DataOutputStream;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+public class Inject implements RuntimeConstants {
+
+    public static byte[] instrumentation(Options opt,
+                                         ClassLoader loader,
+                                         String className,
+                                         byte[] classfileBuffer) {
+        ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
+        (new Inject(className, c, loader == null, opt)).doit();
+        return c.result();
+    }
+
+    static boolean verbose = false;
+
+    final String className;
+    final ClassReaderWriter c;
+    final boolean isSystem;
+    final Options options;
+
+    int constantPoolCount;
+    int methodsCount;
+    int methodsCountPos;
+    int profiler;
+    int wrappedTrackerIndex = 0;
+    int thisClassIndex = 0;
+
+    TrackerInjector callInjector;
+    TrackerInjector allocInjector;
+    TrackerInjector defaultInjector;
+
+    static interface TrackerInjector extends Injector {
+        void reinit(int tracker);
+        int stackSize(int currentSize);
+    }
+
+    static class SimpleInjector implements TrackerInjector {
+        byte[] injection;
+
+        public int stackSize(int currentSize) {
+            return currentSize;
+        }
+
+        public void reinit(int tracker) {
+            injection = new byte[3];
+            injection[0] = (byte)opc_invokestatic;
+            injection[1] = (byte)(tracker >> 8);
+            injection[2] = (byte)tracker;
+        }
+
+        public byte[] bytecodes(String className, String methodName, int location) {
+            return injection;
+        }
+    }
+
+    static class ObjectInjector implements TrackerInjector {
+        byte[] injection;
+
+        public int stackSize(int currentSize) {
+            return currentSize + 1;
+        }
+
+        public void reinit(int tracker) {
+            injection = new byte[4];
+            injection[0] = (byte)opc_dup;
+            injection[1] = (byte)opc_invokestatic;
+            injection[2] = (byte)(tracker >> 8);
+            injection[3] = (byte)tracker;
+        }
+
+        public byte[] bytecodes(String className, String methodName, int location) {
+            return injection;
+        }
+    }
+
+    class IndexedInjector implements TrackerInjector {
+        int counter = 0;
+        int tracker;
+        List<Info> infoList = new ArrayList<Info>();
+
+        public int stackSize(int currentSize) {
+            return currentSize + 1;
+        }
+
+        public void reinit(int tracker) {
+            this.tracker = tracker;
+        }
+
+        void dump(File outDir, String filename) throws IOException {
+            FileOutputStream fileOut = new FileOutputStream(new File(outDir, filename));
+            DataOutputStream dataOut = new DataOutputStream(fileOut);
+
+            String currentClassName = null;
+
+            dataOut.writeInt(infoList.size());
+            for (Iterator<Info> it = infoList.iterator(); it.hasNext(); ) {
+                Info info = it.next();
+                if (!info.className.equals(currentClassName)) {
+                    dataOut.writeInt(123456); // class name marker
+                    currentClassName = info.className;
+                    dataOut.writeUTF(currentClassName);
+                }
+                dataOut.writeInt(info.location);
+                dataOut.writeUTF(info.methodName);
+            }
+            dataOut.close();
+        }
+
+        public byte[] bytecodes(String className, String methodName, int location) {
+            byte[] injection = new byte[6];
+            int injectedIndex = options.fixedIndex != 0? options.fixedIndex : ++counter;
+            infoList.add(new Info(counter, className, methodName, location));
+            injection[0] = (byte)opc_sipush;
+            injection[1] = (byte)(injectedIndex >> 8);
+            injection[2] = (byte)injectedIndex;
+            injection[3] = (byte)opc_invokestatic;
+            injection[4] = (byte)(tracker >> 8);
+            injection[5] = (byte)tracker;
+            return injection;
+        }
+    }
+
+    Inject(String className, ClassReaderWriter c, boolean isSystem, Options options) {
+        this.className = className;
+        this.c = c;
+        this.isSystem = isSystem;
+        this.options = options;
+    }
+
+    void doit() {
+        int i;
+        c.copy(4 + 2 + 2); // magic min/maj version
+        int constantPoolCountPos = c.generatedPosition();
+        constantPoolCount = c.copyU2();
+        // copy old constant pool
+        c.copyConstantPool(constantPoolCount);
+
+        if (verbose) {
+            System.out.println("ConstantPool expanded from: " +
+                               constantPoolCount);
+        }
+
+        profiler = addClassToConstantPool(options.trackerClassName);
+        if (options.shouldInstrumentNew || options.shouldInstrumentObjectInit) {
+            if (options.shouldInstrumentIndexed) {
+                if (allocInjector == null) {
+                    // first time - create it
+                    allocInjector = new IndexedInjector();
+                }
+                int allocTracker = addMethodToConstantPool(profiler,
+                                                           options.allocTrackerMethodName,
+                                                           "(I)V");
+                allocInjector.reinit(allocTracker);
+            } else if (options.shouldInstrumentObject) {
+                if (allocInjector == null) {
+                    // first time - create it
+                    allocInjector = new ObjectInjector();
+                }
+                int allocTracker = addMethodToConstantPool(profiler,
+                                                           options.allocTrackerMethodName,
+                                                           "(Ljava/lang/Object;)V");
+                allocInjector.reinit(allocTracker);
+            } else {
+                if (allocInjector == null) {
+                    // first time - create it
+                    allocInjector = new SimpleInjector();
+                }
+                int allocTracker = addMethodToConstantPool(profiler,
+                                                           options.allocTrackerMethodName,
+                                                           "()V");
+                allocInjector.reinit(allocTracker);
+            }
+            defaultInjector = allocInjector;
+        }
+        if (options.shouldInstrumentCall) {
+            if (options.shouldInstrumentIndexed) {
+                if (callInjector == null) {
+                    // first time - create it
+                    callInjector = new IndexedInjector();
+                }
+                int callTracker = addMethodToConstantPool(profiler,
+                                                          options.callTrackerMethodName,
+                                                          "(I)V");
+                callInjector.reinit(callTracker);
+            } else {
+                if (callInjector == null) {
+                    // first time - create it
+                    callInjector = new SimpleInjector();
+                }
+                int callTracker = addMethodToConstantPool(profiler,
+                                                          options.callTrackerMethodName,
+                                                          "()V");
+                callInjector.reinit(callTracker);
+            }
+            defaultInjector = callInjector;
+        }
+
+        if (verbose) {
+            System.out.println("To: " + constantPoolCount);
+        }
+
+        c.setSection(1);
+
+        c.copy(2 + 2 + 2);  // access, this, super
+        int interfaceCount = c.copyU2();
+        if (verbose) {
+            System.out.println("interfaceCount: " + interfaceCount);
+        }
+        c.copy(interfaceCount * 2);
+        copyFields(); // fields
+        copyMethods(); // methods
+        int attrCountPos = c.generatedPosition();
+        int attrCount = c.copyU2();
+        if (verbose) {
+            System.out.println("class attrCount: " + attrCount);
+        }
+        // copy the class attributes
+        copyAttrs(attrCount);
+
+        c.randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
+    }
+
+
+    void copyFields() {
+        int count = c.copyU2();
+        if (verbose) {
+            System.out.println("fields count: " + count);
+        }
+        for (int i = 0; i < count; ++i) {
+            c.copy(6); // access, name, descriptor
+            int attrCount = c.copyU2();
+            if (verbose) {
+                System.out.println("field attr count: " + attrCount);
+            }
+            copyAttrs(attrCount);
+        }
+    }
+
+    void copyMethods() {
+        methodsCountPos = c.generatedPosition();
+        methodsCount = c.copyU2();
+        int initialMethodsCount = methodsCount;
+        if (verbose) {
+            System.out.println("methods count: " + methodsCount);
+        }
+        for (int i = 0; i < initialMethodsCount; ++i) {
+            copyMethod();
+        }
+    }
+
+    void copyMethod() {
+        int accessFlags = c.copyU2();// access flags
+        if (options.shouldInstrumentNativeMethods && (accessFlags & ACC_NATIVE) != 0) {
+            wrapNativeMethod(accessFlags);
+            return;
+        }
+        int nameIndex = c.copyU2();  // name
+        String methodName = c.constantPoolString(nameIndex);
+        c.copyU2();                  // descriptor
+        int attrCount = c.copyU2();  // attribute count
+        if (verbose) {
+            System.out.println("methods attr count: " + attrCount);
+        }
+        for (int i = 0; i < attrCount; ++i) {
+            copyAttrForMethod(methodName, accessFlags);
+        }
+    }
+
+    void wrapNativeMethod(int accessFlags) {
+        // first, copy the native method with the name changed
+        // accessFlags have already been copied
+        int nameIndex = c.readU2();        // name
+        String methodName = c.constantPoolString(nameIndex);
+        String wrappedMethodName = options.wrappedPrefix + methodName;
+        int wrappedNameIndex = writeCPEntryUtf8(wrappedMethodName);
+        c.writeU2(wrappedNameIndex);       // change to the wrapped name
+
+        int descriptorIndex = c.copyU2();  // descriptor index
+
+        int attrCount = c.copyU2();        // attribute count
+        // need to replicate these attributes (esp Exceptions) in wrapper
+        // so mark this location so we can rewind
+        c.markLocalPositionStart();
+        for (int i = 0; i < attrCount; ++i) {
+            copyAttrForMethod(methodName, accessFlags);
+        }
+        if (true) {
+            System.err.println("   wrapped: " + methodName);
+        }
+
+        // now write the wrapper method
+        c.writeU2(accessFlags & ~ACC_NATIVE);
+        c.writeU2(nameIndex);           // original unwrapped name
+        c.writeU2(descriptorIndex);     // descriptor is the same
+
+        c.writeU2(attrCount + 1);       // wrapped plus a code attribute
+        // rewind to wrapped attributes
+        c.rewind();
+        for (int i = 0; i < attrCount; ++i) {
+            copyAttrForMethod(methodName, accessFlags);
+        }
+
+        // generate a Code attribute for the wrapper method
+        int wrappedIndex = addMethodToConstantPool(getThisClassIndex(),
+                                                   wrappedNameIndex,
+                                                   descriptorIndex);
+        String descriptor = c.constantPoolString(descriptorIndex);
+        createWrapperCodeAttr(nameIndex, accessFlags, descriptor, wrappedIndex);
+
+        // increment method count
+        c.randomAccessWriteU2(methodsCountPos, ++methodsCount);
+    }
+
+    void copyAttrs(int attrCount) {
+        for (int i = 0; i < attrCount; ++i) {
+            copyAttr();
+        }
+    }
+
+    void copyAttr() {
+        c.copy(2);             // name
+        int len = c.copyU4();  // attr len
+        if (verbose) {
+            System.out.println("attr len: " + len);
+        }
+        c.copy(len);           // attribute info
+    }
+
+    void copyAttrForMethod(String methodName, int accessFlags) {
+        int nameIndex = c.copyU2();   // name
+        // check for Code attr
+        if (nameIndex == c.codeAttributeIndex) {
+            try {
+                copyCodeAttr(methodName);
+            } catch (IOException exc) {
+                System.err.println("Code Exception - " + exc);
+                System.exit(1);
+            }
+        } else {
+            int len = c.copyU4();     // attr len
+            if (verbose) {
+                System.out.println("method attr len: " + len);
+            }
+            c.copy(len);              // attribute info
+        }
+    }
+
+    void copyAttrForCode(InjectBytecodes ib) throws IOException {
+        int nameIndex = c.copyU2();   // name
+
+        // check for Code attr
+        if (nameIndex == c.lineNumberAttributeIndex) {
+            ib.copyLineNumberAttr();
+        } else if (nameIndex == c.localVarAttributeIndex) {
+            ib.copyLocalVarAttr();
+        } else {
+            int len = c.copyU4();     // attr len
+            if (verbose) {
+                System.out.println("code attr len: " + len);
+            }
+            c.copy(len);              // attribute info
+        }
+    }
+
+    void copyCodeAttr(String methodName) throws IOException {
+        if (verbose) {
+            System.out.println("Code attr found");
+        }
+        int attrLengthPos = c.generatedPosition();
+        int attrLength = c.copyU4();        // attr len
+        int maxStack = c.readU2();          // max stack
+        c.writeU2(defaultInjector == null? maxStack :
+                  defaultInjector.stackSize(maxStack));  // big enough for injected code
+        c.copyU2();                         // max locals
+        int codeLengthPos = c.generatedPosition();
+        int codeLength = c.copyU4();        // code length
+        if (options.targetMethod != null && !options.targetMethod.equals(methodName)) {
+            c.copy(attrLength - 8); // copy remainder minus already copied
+            return;
+        }
+        if (isSystem) {
+            if (codeLength == 1 && methodName.equals("finalize")) {
+                if (verbose) {
+                    System.out.println("empty system finalizer not instrumented");
+                }
+                c.copy(attrLength - 8); // copy remainder minus already copied
+                return;
+            }
+            if (codeLength == 1 && methodName.equals("<init>")) {
+                if (verbose) {
+                    System.out.println("empty system constructor not instrumented");
+                }
+                if (!options.shouldInstrumentObjectInit) {
+                    c.copy(attrLength - 8); // copy remainder minus already copied
+                    return;
+                }
+            }
+            if (methodName.equals("<clinit>")) {
+                if (verbose) {
+                    System.out.println("system class initializer not instrumented");
+                }
+                c.copy(attrLength - 8); // copy remainder minus already copied
+                return;
+            }
+        }
+        if (options.shouldInstrumentObjectInit
+            && (!className.equals("java/lang/Object")
+                || !methodName.equals("<init>"))) {
+            c.copy(attrLength - 8); // copy remainder minus already copied
+            return;
+        }
+
+        InjectBytecodes ib = new InjectBytecodes(c, codeLength, className, methodName);
+
+        if (options.shouldInstrumentNew) {
+            ib.injectAfter(opc_new, allocInjector);
+            ib.injectAfter(opc_newarray, allocInjector);
+            ib.injectAfter(opc_anewarray, allocInjector);
+            ib.injectAfter(opc_multianewarray, allocInjector);
+        }
+        if (options.shouldInstrumentCall) {
+            ib.inject(0, callInjector.bytecodes(className, methodName, 0));
+        }
+        if (options.shouldInstrumentObjectInit) {
+            ib.inject(0, allocInjector.bytecodes(className, methodName, 0));
+        }
+
+        ib.adjustOffsets();
+
+        // fix up code length
+        int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
+        c.randomAccessWriteU4(codeLengthPos, newCodeLength);
+        if (verbose) {
+            System.out.println("code length old: " + codeLength +
+                               ", new: " + newCodeLength);
+        }
+
+        ib.copyExceptionTable();
+
+        int attrCount = c.copyU2();
+        for (int i = 0; i < attrCount; ++i) {
+            copyAttrForCode(ib);
+        }
+
+        // fix up attr length
+        int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
+        c.randomAccessWriteU4(attrLengthPos, newAttrLength);
+        if (verbose) {
+            System.out.println("attr length old: " + attrLength +
+                               ", new: " + newAttrLength);
+        }
+    }
+
+    int nextDescriptorIndex(String descriptor, int index) {
+        switch (descriptor.charAt(index)) {
+        case 'B': // byte
+        case 'C': // char
+        case 'I': // int
+        case 'S': // short
+        case 'Z': // boolean
+        case 'F': // float
+        case 'D': // double
+        case 'J': // long
+            return index + 1;
+        case 'L': // object
+            int i = index + 1;
+            while (descriptor.charAt(i) != ';') {
+                ++i;
+            }
+            return i + 1;
+        case '[': // array
+            return nextDescriptorIndex(descriptor, index + 1);
+        }
+        throw new InternalError("should not reach here");
+    }
+
+    int getWrappedTrackerIndex() {
+        if (wrappedTrackerIndex == 0) {
+            wrappedTrackerIndex = addMethodToConstantPool(profiler,
+                                                          options.wrappedTrackerMethodName,
+                                                          "(Ljava/lang/String;I)V");
+        }
+        return wrappedTrackerIndex;
+    }
+
+    int getThisClassIndex() {
+        if (thisClassIndex == 0) {
+            thisClassIndex = addClassToConstantPool(className);
+        }
+        return thisClassIndex;
+    }
+
+    int computeMaxLocals(String descriptor, int accessFlags) {
+        int index = 1;
+        int slot = 0;
+
+        if ((accessFlags & ACC_STATIC) == 0) {
+            ++slot;
+        }
+        char type;
+        while ((type = descriptor.charAt(index)) != ')') {
+            switch (type) {
+            case 'B': // byte
+            case 'C': // char
+            case 'I': // int
+            case 'S': // short
+            case 'Z': // boolean
+            case 'F': // float
+            case 'L': // object
+            case '[': // array
+                ++slot;
+                break;
+            case 'D': // double
+            case 'J': // long
+                slot += 2;
+                break;
+            }
+            index = nextDescriptorIndex(descriptor, index);
+        }
+
+        return slot;
+    }
+
+
+    void createWrapperCodeAttr(int methodNameIndex, int accessFlags,
+                               String descriptor, int wrappedIndex) {
+        int maxLocals = computeMaxLocals(descriptor, accessFlags);
+
+        c.writeU2(c.codeAttributeIndex);        //
+        int attrLengthPos = c.generatedPosition();
+        c.writeU4(0);                // attr len -- fix up below
+        c.writeU2(maxLocals + 4);    // max stack
+        c.writeU2(maxLocals);        // max locals
+        int codeLengthPos = c.generatedPosition();
+        c.writeU4(0);                // code length -- fix up below
+
+        int methodStringIndex = writeCPEntryString(methodNameIndex);
+
+        c.writeU1(opc_ldc_w);
+        c.writeU2(methodStringIndex);  // send the method name
+        c.writeU1(opc_sipush);
+        c.writeU2(options.fixedIndex);
+        c.writeU1(opc_invokestatic);
+        c.writeU2(getWrappedTrackerIndex());
+
+        // set-up args
+        int index = 1;
+        int slot = 0;
+        if ((accessFlags & ACC_STATIC) == 0) {
+            c.writeU1(opc_aload_0);  // this
+            ++slot;
+        }
+        char type;
+        while ((type = descriptor.charAt(index)) != ')') {
+            switch (type) {
+            case 'B': // byte
+            case 'C': // char
+            case 'I': // int
+            case 'S': // short
+            case 'Z': // boolean
+                c.writeU1(opc_iload);
+                c.writeU1(slot);
+                ++slot;
+                break;
+            case 'F': // float
+                c.writeU1(opc_fload);
+                c.writeU1(slot);
+                ++slot;
+                break;
+            case 'D': // double
+                c.writeU1(opc_dload);
+                c.writeU1(slot);
+                slot += 2;
+                break;
+            case 'J': // long
+                c.writeU1(opc_lload);
+                c.writeU1(slot);
+                slot += 2;
+                break;
+            case 'L': // object
+            case '[': // array
+                c.writeU1(opc_aload);
+                c.writeU1(slot);
+                ++slot;
+                break;
+            }
+            index = nextDescriptorIndex(descriptor, index);
+        }
+
+        // call the wrapped version
+        if ((accessFlags & ACC_STATIC) == 0) {
+            c.writeU1(opc_invokevirtual);
+        } else {
+            c.writeU1(opc_invokestatic);
+        }
+        c.writeU2(wrappedIndex);
+
+        // return correct type
+        switch (descriptor.charAt(index+1)) {
+        case 'B': // byte
+        case 'C': // char
+        case 'I': // int
+        case 'S': // short
+        case 'Z': // boolean
+            c.writeU1(opc_ireturn);
+            break;
+        case 'F': // float
+            c.writeU1(opc_freturn);
+            break;
+        case 'D': // double
+            c.writeU1(opc_dreturn);
+            break;
+        case 'J': // long
+            c.writeU1(opc_lreturn);
+            break;
+        case 'L': // object
+        case '[': // array
+            c.writeU1(opc_areturn);
+            break;
+        case 'V': // void
+            c.writeU1(opc_return);
+            break;
+        }
+
+        // end of code
+
+        // fix up code length
+        int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
+        c.randomAccessWriteU4(codeLengthPos, newCodeLength);
+
+        c.writeU2(0);                // exception table length
+        c.writeU2(0);                // attribute count
+
+        // fix up attr length
+        int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
+        c.randomAccessWriteU4(attrLengthPos, newAttrLength);
+    }
+
+
+    int addClassToConstantPool(String className) {
+        int prevSection = c.setSection(0);
+        int classNameIndex = writeCPEntryUtf8(className);
+        int classIndex = writeCPEntryClass(classNameIndex);
+        c.setSection(prevSection);
+        return classIndex;
+    }
+
+    int addMethodToConstantPool(int classIndex,
+                                String methodName,
+                                String descr) {
+        int prevSection = c.setSection(0);
+        int methodNameIndex = writeCPEntryUtf8(methodName);
+        int descrIndex = writeCPEntryUtf8(descr);
+        c.setSection(prevSection);
+        return addMethodToConstantPool(classIndex, methodNameIndex, descrIndex);
+    }
+
+    int addMethodToConstantPool(int classIndex,
+                                int methodNameIndex,
+                                int descrIndex) {
+        int prevSection = c.setSection(0);
+        int nameAndTypeIndex = writeCPEntryNameAndType(methodNameIndex,
+                                                       descrIndex);
+        int methodIndex = writeCPEntryMethodRef(classIndex, nameAndTypeIndex);
+        c.setSection(prevSection);
+        return methodIndex;
+    }
+
+    int writeCPEntryUtf8(String str) {
+        int prevSection = c.setSection(0);
+        int len = str.length();
+        c.writeU1(CONSTANT_UTF8); // Utf8 tag
+        c.writeU2(len);
+        for (int i = 0; i < len; ++i) {
+            c.writeU1(str.charAt(i));
+        }
+        c.setSection(prevSection);
+        return constantPoolCount++;
+    }
+
+    int writeCPEntryString(int utf8Index) {
+        int prevSection = c.setSection(0);
+        c.writeU1(CONSTANT_STRING);
+        c.writeU2(utf8Index);
+        c.setSection(prevSection);
+        return constantPoolCount++;
+    }
+
+    int writeCPEntryClass(int classNameIndex) {
+        int prevSection = c.setSection(0);
+        c.writeU1(CONSTANT_CLASS);
+        c.writeU2(classNameIndex);
+        c.setSection(prevSection);
+        return constantPoolCount++;
+    }
+
+    int writeCPEntryNameAndType(int nameIndex, int descrIndex) {
+        int prevSection = c.setSection(0);
+        c.writeU1(CONSTANT_NAMEANDTYPE);
+        c.writeU2(nameIndex);
+        c.writeU2(descrIndex);
+        c.setSection(prevSection);
+        return constantPoolCount++;
+    }
+
+    int writeCPEntryMethodRef(int classIndex, int nameAndTypeIndex) {
+        int prevSection = c.setSection(0);
+        c.writeU1(CONSTANT_METHOD);
+        c.writeU2(classIndex);
+        c.writeU2(nameAndTypeIndex);
+        c.setSection(prevSection);
+        return constantPoolCount++;
+    }
+}