📄 methodwriter.java
字号:
* @see NOTHING
*/
private int compute;
/**
* A list of labels. This list is the list of basic blocks in the method,
* i.e. a list of Label objects linked to each other by their
* {@link Label#successor} field, in the order they are visited by
* {@link visitLabel}, and starting with the first basic block.
*/
private Label labels;
/**
* The previous basic block.
*/
private Label previousBlock;
/**
* The current basic block.
*/
private Label currentBlock;
/**
* The (relative) stack size after the last visited instruction. This size
* is relative to the beginning of the current basic block, i.e., the true
* stack size after the last visited instruction is equal to the
* {@link Label#inputStackTop beginStackSize} of the current basic block
* plus <tt>stackSize</tt>.
*/
private int stackSize;
/**
* The (relative) maximum stack size after the last visited instruction.
* This size is relative to the beginning of the current basic block, i.e.,
* the true maximum stack size after the last visited instruction is equal
* to the {@link Label#inputStackTop beginStackSize} of the current basic
* block plus <tt>stackSize</tt>.
*/
private int maxStackSize;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link MethodWriter}.
*
* @param cw the class writer in which the method must be added.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type}).
* @param signature the method's signature. May be <tt>null</tt>.
* @param exceptions the internal names of the method's exceptions. May be
* <tt>null</tt>.
* @param computeMaxs <tt>true</tt> if the maximum stack size and number
* of local variables must be automatically computed.
* @param computeFrames <tt>true</tt> if the stack map tables must be
* recomputed from scratch.
*/
MethodWriter(
final ClassWriter cw,
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions,
final boolean computeMaxs,
final boolean computeFrames)
{
if (cw.firstMethod == null) {
cw.firstMethod = this;
} else {
cw.lastMethod.next = this;
}
cw.lastMethod = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
this.descriptor = desc;
this.signature = signature;
if (exceptions != null && exceptions.length > 0) {
exceptionCount = exceptions.length;
this.exceptions = new int[exceptionCount];
for (int i = 0; i < exceptionCount; ++i) {
this.exceptions[i] = cw.newClass(exceptions[i]);
}
}
this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);
if (computeMaxs || computeFrames) {
if (computeFrames && name.equals("<init>")) {
this.access |= ACC_CONSTRUCTOR;
}
// updates maxLocals
int size = getArgumentsAndReturnSizes(descriptor) >> 2;
if ((access & Opcodes.ACC_STATIC) != 0) {
--size;
}
maxLocals = size;
// creates and visits the label for the first basic block
labels = new Label();
labels.status |= Label.PUSHED;
visitLabel(labels);
}
}
// ------------------------------------------------------------------------
// Implementation of the MethodVisitor interface
// ------------------------------------------------------------------------
public AnnotationVisitor visitAnnotationDefault() {
annd = new ByteVector();
return new AnnotationWriter(cw, false, annd, null, 0);
}
public AnnotationVisitor visitAnnotation(
final String desc,
final boolean visible)
{
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) {
aw.next = anns;
anns = aw;
} else {
aw.next = ianns;
ianns = aw;
}
return aw;
}
public AnnotationVisitor visitParameterAnnotation(
final int parameter,
final String desc,
final boolean visible)
{
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) {
if (panns == null) {
panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
}
aw.next = panns[parameter];
panns[parameter] = aw;
} else {
if (ipanns == null) {
ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
}
aw.next = ipanns[parameter];
ipanns[parameter] = aw;
}
return aw;
}
public void visitAttribute(final Attribute attr) {
if (attr.isCodeAttribute()) {
attr.next = cattrs;
cattrs = attr;
} else {
attr.next = attrs;
attrs = attr;
}
}
public void visitCode() {
}
public void visitFrame(
final int type,
final int nLocal,
final Object[] local,
final int nStack,
final Object[] stack)
{
if (compute == FRAMES) {
return;
}
if (type == Opcodes.F_NEW) {
startFrame(code.length, nLocal, nStack);
for (int i = 0; i < nLocal; ++i) {
if (local[i] instanceof String) {
frame[frameIndex++] = Frame.OBJECT
| cw.addType((String) local[i]);
} else if (local[i] instanceof Integer) {
frame[frameIndex++] = ((Integer) local[i]).intValue();
} else {
frame[frameIndex++] = Frame.UNINITIALIZED
| cw.addUninitializedType("",
((Label) local[i]).position);
}
}
for (int i = 0; i < nStack; ++i) {
if (stack[i] instanceof String) {
frame[frameIndex++] = Frame.OBJECT
| cw.addType((String) stack[i]);
} else if (stack[i] instanceof Integer) {
frame[frameIndex++] = ((Integer) stack[i]).intValue();
} else {
frame[frameIndex++] = Frame.UNINITIALIZED
| cw.addUninitializedType("",
((Label) stack[i]).position);
}
}
endFrame();
} else {
int delta;
if (stackMap == null) {
stackMap = new ByteVector();
delta = code.length;
} else {
delta = code.length - previousFrameOffset - 1;
}
switch (type) {
case Opcodes.F_FULL:
stackMap.putByte(FULL_FRAME)
.putShort(delta)
.putShort(nLocal);
for (int i = 0; i < nLocal; ++i) {
writeFrameType(local[i]);
}
stackMap.putShort(nStack);
for (int i = 0; i < nStack; ++i) {
writeFrameType(stack[i]);
}
break;
case Opcodes.F_APPEND:
stackMap.putByte(SAME_FRAME_EXTENDED + nLocal)
.putShort(delta);
for (int i = 0; i < nLocal; ++i) {
writeFrameType(local[i]);
}
break;
case Opcodes.F_CHOP:
stackMap.putByte(SAME_FRAME_EXTENDED - nLocal)
.putShort(delta);
break;
case Opcodes.F_SAME:
if (delta < 64) {
stackMap.putByte(delta);
} else {
stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
}
break;
case Opcodes.F_SAME1:
if (delta < 64) {
stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
} else {
stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
.putShort(delta);
}
writeFrameType(stack[0]);
break;
}
previousFrameOffset = code.length;
++frameCount;
}
}
public void visitInsn(final int opcode) {
// adds the instruction to the bytecode of the method
code.putByte(opcode);
// update currentBlock
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(opcode, 0, null, null);
} else {
// updates current and max stack sizes
int size = stackSize + Frame.SIZE[opcode];
if (size > maxStackSize) {
maxStackSize = size;
}
stackSize = size;
}
// if opcode == ATHROW or xRETURN, ends current block (no successor)
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
|| opcode == Opcodes.ATHROW)
{
noSuccessor();
}
}
}
public void visitIntInsn(final int opcode, final int operand) {
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(opcode, operand, null, null);
} else if (opcode != Opcodes.NEWARRAY) {
// updates current and max stack sizes only for NEWARRAY
// (stack size variation = 0 for BIPUSH or SIPUSH)
int size = stackSize + 1;
if (size > maxStackSize) {
maxStackSize = size;
}
stackSize = size;
}
}
// adds the instruction to the bytecode of the method
if (opcode == Opcodes.SIPUSH) {
code.put12(opcode, operand);
} else { // BIPUSH or NEWARRAY
code.put11(opcode, operand);
}
}
public void visitVarInsn(final int opcode, final int var) {
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(opcode, var, null, null);
} else {
// updates current and max stack sizes
if (opcode == Opcodes.RET) {
// no stack change, but end of current block (no successor)
currentBlock.status |= Label.RET;
// save 'stackSize' here for future use
// (see {@link #findSubroutineSuccessors})
currentBlock.inputStackTop = stackSize;
noSuccessor();
} else { // xLOAD or xSTORE
int size = stackSize + Frame.SIZE[opcode];
if (size > maxStackSize) {
maxStackSize = size;
}
stackSize = size;
}
}
}
if (compute != NOTHING) {
// updates max locals
int n;
if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
|| opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE)
{
n = var + 2;
} else {
n = var + 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -