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;
}