public void stopMethod()

in rhino/src/main/java/org/mozilla/classfile/ClassFileWriter.java [247:411]


    public void stopMethod(int maxLocals) {
        if (itsCurrentMethod == null) throw new IllegalStateException("No method to stop");

        fixLabelGotos();

        itsMaxLocals = maxLocals;

        StackMapTable stackMap = null;
        if (GenerateStackMap) {
            finalizeSuperBlockStarts();
            stackMap = new StackMapTable();
            stackMap.generate();
        }

        int lineNumberTableLength = 0;
        if (itsLineNumberTable != null) {
            // 6 bytes for the attribute header
            // 2 bytes for the line number count
            // 4 bytes for each entry
            lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4);
        }

        int variableTableLength = 0;
        if (itsVarDescriptors != null) {
            // 6 bytes for the attribute header
            // 2 bytes for the variable count
            // 10 bytes for each entry
            variableTableLength = 6 + 2 + (itsVarDescriptors.size() * 10);
        }

        int stackMapTableLength = 0;
        if (stackMap != null) {
            int stackMapWriteSize = stackMap.computeWriteSize();
            if (stackMapWriteSize > 0) {
                stackMapTableLength = 6 + stackMapWriteSize;
            }
        }

        int attrLength =
                2
                        + // attribute_name_index
                        4
                        + // attribute_length
                        2
                        + // max_stack
                        2
                        + // max_locals
                        4
                        + // code_length
                        itsCodeBufferTop
                        + 2
                        + // exception_table_length
                        (itsExceptionTableTop * 8)
                        + 2
                        + // attributes_count
                        lineNumberTableLength
                        + variableTableLength
                        + stackMapTableLength;

        if (attrLength > 65536) {
            // See http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html,
            // section 4.10, "The amount of code per non-native, non-abstract
            // method is limited to 65536 bytes...
            throw new ClassFileFormatException("generated bytecode for method exceeds 64K limit.");
        }
        byte[] codeAttribute = new byte[attrLength];
        int index = 0;
        int codeAttrIndex = itsConstantPool.addUtf8("Code");
        index = putInt16(codeAttrIndex, codeAttribute, index);
        attrLength -= 6; // discount the attribute header
        index = putInt32(attrLength, codeAttribute, index);
        index = putInt16(itsMaxStack, codeAttribute, index);
        index = putInt16(itsMaxLocals, codeAttribute, index);
        index = putInt32(itsCodeBufferTop, codeAttribute, index);
        System.arraycopy(itsCodeBuffer, 0, codeAttribute, index, itsCodeBufferTop);
        index += itsCodeBufferTop;

        if (itsExceptionTableTop > 0) {
            index = putInt16(itsExceptionTableTop, codeAttribute, index);
            for (int i = 0; i < itsExceptionTableTop; i++) {
                ExceptionTableEntry ete = itsExceptionTable[i];
                int startPC = getLabelPC(ete.itsStartLabel);
                int endPC = getLabelPC(ete.itsEndLabel);
                int handlerPC = getLabelPC(ete.itsHandlerLabel);
                short catchType = ete.itsCatchType;
                if (startPC == -1) throw new IllegalStateException("start label not defined");
                if (endPC == -1) throw new IllegalStateException("end label not defined");
                if (handlerPC == -1) throw new IllegalStateException("handler label not defined");

                // no need to cast to short here, the putInt16 uses only
                // the short part of the int
                index = putInt16(startPC, codeAttribute, index);
                index = putInt16(endPC, codeAttribute, index);
                index = putInt16(handlerPC, codeAttribute, index);
                index = putInt16(catchType, codeAttribute, index);
            }
        } else {
            // write 0 as exception table length
            index = putInt16(0, codeAttribute, index);
        }

        int attributeCount = 0;
        if (itsLineNumberTable != null) attributeCount++;
        if (itsVarDescriptors != null) attributeCount++;
        if (stackMapTableLength > 0) {
            attributeCount++;
        }
        index = putInt16(attributeCount, codeAttribute, index);

        if (itsLineNumberTable != null) {
            int lineNumberTableAttrIndex = itsConstantPool.addUtf8("LineNumberTable");
            index = putInt16(lineNumberTableAttrIndex, codeAttribute, index);
            int tableAttrLength = 2 + (itsLineNumberTableTop * 4);
            index = putInt32(tableAttrLength, codeAttribute, index);
            index = putInt16(itsLineNumberTableTop, codeAttribute, index);
            for (int i = 0; i < itsLineNumberTableTop; i++) {
                index = putInt32(itsLineNumberTable[i], codeAttribute, index);
            }
        }

        if (itsVarDescriptors != null) {
            int variableTableAttrIndex = itsConstantPool.addUtf8("LocalVariableTable");
            index = putInt16(variableTableAttrIndex, codeAttribute, index);
            int varCount = itsVarDescriptors.size();
            int tableAttrLength = 2 + (varCount * 10);
            index = putInt32(tableAttrLength, codeAttribute, index);
            index = putInt16(varCount, codeAttribute, index);
            for (int i = 0; i < varCount; i++) {
                int[] chunk = (int[]) itsVarDescriptors.get(i);
                int nameIndex = chunk[0];
                int descriptorIndex = chunk[1];
                int startPC = chunk[2];
                int register = chunk[3];
                int length = itsCodeBufferTop - startPC;

                index = putInt16(startPC, codeAttribute, index);
                index = putInt16(length, codeAttribute, index);
                index = putInt16(nameIndex, codeAttribute, index);
                index = putInt16(descriptorIndex, codeAttribute, index);
                index = putInt16(register, codeAttribute, index);
            }
        }

        if (stackMapTableLength > 0) {
            int stackMapTableAttrIndex = itsConstantPool.addUtf8("StackMapTable");
            index = putInt16(stackMapTableAttrIndex, codeAttribute, index);
            index = stackMap.write(codeAttribute, index);
        }

        itsCurrentMethod.setCodeAttribute(codeAttribute);

        itsExceptionTable = null;
        itsExceptionTableTop = 0;
        itsLineNumberTableTop = 0;
        itsCodeBufferTop = 0;
        itsCurrentMethod = null;
        itsMaxStack = 0;
        itsStackTop = 0;
        itsLabelTableTop = 0;
        itsFixupTableTop = 0;
        itsVarDescriptors = null;
        itsSuperBlockStarts = null;
        itsSuperBlockStartsTop = 0;
        itsJumpFroms = null;
    }