public virtual void StopMethod(short maxLocals)
{
if (itsCurrentMethod == null)
{
throw new InvalidOperationException("No method to stop");
}
FixLabelGotos();
itsMaxLocals = maxLocals;
ClassFileWriter.StackMapTable stackMap = null;
if (GenerateStackMap)
{
FinalizeSuperBlockStarts();
stackMap = new ClassFileWriter.StackMapTable(this);
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 + 4 + 2 + 2 + 4 + itsCodeBufferTop + 2 + (itsExceptionTableTop * 8) + 2 + lineNumberTableLength + variableTableLength + stackMapTableLength;
// attribute_name_index
// attribute_length
// max_stack
// max_locals
// code_length
// exception_table_length
// attributes_count
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 ClassFileWriter.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.Array.Copy(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];
short startPC = (short)GetLabelPC(ete.itsStartLabel);
short endPC = (short)GetLabelPC(ete.itsEndLabel);
short handlerPC = (short)GetLabelPC(ete.itsHandlerLabel);
short catchType = ete.itsCatchType;
if (startPC == -1)
{
throw new InvalidOperationException("start label not defined");
}
if (endPC == -1)
{
throw new InvalidOperationException("end label not defined");
}
if (handlerPC == -1)
{
throw new InvalidOperationException("handler label not defined");
}
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");
int start = index;
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;
}