📄 codewriter.java
字号:
} else {
size = stackSize - (argSize >> 2) + (argSize & 0x03);
}
// updates current and max stack sizes
if (size > maxStackSize) {
maxStackSize = size;
}
stackSize = size;
}
// adds the instruction to the bytecode of the method
if (itf) {
if (!computeMaxs) {
if (argSize == 0) {
argSize = getArgumentsAndReturnSizes(desc);
i.intVal = argSize;
}
}
code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
} else {
code.put12(opcode, i.index);
}
}
public void visitJumpInsn (final int opcode, final Label label) {
if (CHECK) {
if (label.owner == null) {
label.owner = this;
} else if (label.owner != this) {
throw new IllegalArgumentException();
}
}
if (computeMaxs) {
if (opcode == Constants.GOTO) {
// no stack change, but end of current block (with one new successor)
if (currentBlock != null) {
currentBlock.maxStackSize = maxStackSize;
addSuccessor(stackSize, label);
currentBlock = null;
}
} else if (opcode == Constants.JSR) {
if (currentBlock != null) {
addSuccessor(stackSize + 1, label);
}
} else {
// updates current stack size (max stack size unchanged because stack
// size variation always negative in this case)
stackSize += SIZE[opcode];
if (currentBlock != null) {
addSuccessor(stackSize, label);
}
}
}
// adds the instruction to the bytecode of the method
if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
// case of a backward jump with an offset < -32768. In this case we
// automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx <l>
// with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode
// of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the
// instruction just after the GOTO_W.
if (opcode == Constants.GOTO) {
code.putByte(200); // GOTO_W
} else if (opcode == Constants.JSR) {
code.putByte(201); // JSR_W
} else {
code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
code.putShort(8); // jump offset
code.putByte(200); // GOTO_W
}
label.put(this, code, code.length - 1, true);
} else {
// case of a backward jump with an offset >= -32768, or of a forward jump
// with, of course, an unknown offset. In these cases we store the offset
// in 2 bytes (which will be increased in resizeInstructions, if needed).
code.putByte(opcode);
label.put(this, code, code.length - 1, false);
}
}
public void visitLabel (final Label label) {
if (CHECK) {
if (label.owner == null) {
label.owner = this;
} else if (label.owner != this) {
throw new IllegalArgumentException();
}
}
if (computeMaxs) {
if (currentBlock != null) {
// ends current block (with one new successor)
currentBlock.maxStackSize = maxStackSize;
addSuccessor(stackSize, label);
}
// begins a new current block,
// resets the relative current and max stack sizes
currentBlock = label;
stackSize = 0;
maxStackSize = 0;
}
// resolves previous forward references to label, if any
resize |= label.resolve(this, code.length, code.data);
}
public void visitLdcInsn (final Object cst) {
Item i = cw.newConstItem(cst);
if (computeMaxs) {
int size;
// computes the stack size variation
if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
size = stackSize + 2;
} else {
size = stackSize + 1;
}
// updates current and max stack sizes
if (size > maxStackSize) {
maxStackSize = size;
}
stackSize = size;
}
// adds the instruction to the bytecode of the method
int index = i.index;
if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
code.put12(20 /*LDC2_W*/, index);
} else if (index >= 256) {
code.put12(19 /*LDC_W*/, index);
} else {
code.put11(Constants.LDC, index);
}
}
public void visitIincInsn (final int var, final int increment) {
if (computeMaxs) {
// updates max locals only (no stack change)
int n = var + 1;
if (n > maxLocals) {
maxLocals = n;
}
}
// adds the instruction to the bytecode of the method
if ((var > 255) || (increment > 127) || (increment < -128)) {
code.putByte(196 /*WIDE*/).put12(Constants.IINC, var).putShort(increment);
} else {
code.putByte(Constants.IINC).put11(var, increment);
}
}
public void visitTableSwitchInsn (
final int min,
final int max,
final Label dflt,
final Label labels[])
{
if (computeMaxs) {
// updates current stack size (max stack size unchanged)
--stackSize;
// ends current block (with many new successors)
if (currentBlock != null) {
currentBlock.maxStackSize = maxStackSize;
addSuccessor(stackSize, dflt);
for (int i = 0; i < labels.length; ++i) {
addSuccessor(stackSize, labels[i]);
}
currentBlock = null;
}
}
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Constants.TABLESWITCH);
while (code.length % 4 != 0) {
code.putByte(0);
}
dflt.put(this, code, source, true);
code.putInt(min).putInt(max);
for (int i = 0; i < labels.length; ++i) {
labels[i].put(this, code, source, true);
}
}
public void visitLookupSwitchInsn (
final Label dflt,
final int keys[],
final Label labels[])
{
if (computeMaxs) {
// updates current stack size (max stack size unchanged)
--stackSize;
// ends current block (with many new successors)
if (currentBlock != null) {
currentBlock.maxStackSize = maxStackSize;
addSuccessor(stackSize, dflt);
for (int i = 0; i < labels.length; ++i) {
addSuccessor(stackSize, labels[i]);
}
currentBlock = null;
}
}
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Constants.LOOKUPSWITCH);
while (code.length % 4 != 0) {
code.putByte(0);
}
dflt.put(this, code, source, true);
code.putInt(labels.length);
for (int i = 0; i < labels.length; ++i) {
code.putInt(keys[i]);
labels[i].put(this, code, source, true);
}
}
public void visitMultiANewArrayInsn (final String desc, final int dims) {
if (computeMaxs) {
// updates current stack size (max stack size unchanged because stack
// size variation always negative or null)
stackSize += 1 - dims;
}
// adds the instruction to the bytecode of the method
code.put12(Constants.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims);
}
public void visitTryCatchBlock (
final Label start,
final Label end,
final Label handler,
final String type)
{
if (CHECK) {
if (start.owner != this || end.owner != this || handler.owner != this) {
throw new IllegalArgumentException();
}
if (!start.resolved || !end.resolved || !handler.resolved) {
throw new IllegalArgumentException();
}
}
if (computeMaxs) {
// pushes handler block onto the stack of blocks to be visited
if (!handler.pushed) {
handler.beginStackSize = 1;
handler.pushed = true;
handler.next = blockStack;
blockStack = handler;
}
}
++catchCount;
if (catchTable == null) {
catchTable = new ByteVector();
}
catchTable.putShort(start.position);
catchTable.putShort(end.position);
catchTable.putShort(handler.position);
catchTable.putShort(type != null ? cw.newClass(type) : 0);
}
public void visitMaxs (final int maxStack, final int maxLocals) {
if (computeMaxs) {
// true (non relative) max stack size
int max = 0;
// control flow analysis algorithm: while the block stack is not empty,
// pop a block from this stack, update the max stack size, compute
// the true (non relative) begin stack size of the successors of this
// block, and push these successors onto the stack (unless they have
// already been pushed onto the stack). Note: by hypothesis, the {@link
// Label#beginStackSize} of the blocks in the block stack are the true
// (non relative) beginning stack sizes of these blocks.
Label stack = blockStack;
while (stack != null) {
// pops a block from the stack
Label l = stack;
stack = stack.next;
// computes the true (non relative) max stack size of this block
int start = l.beginStackSize;
int blockMax = start + l.maxStackSize;
// updates the global max stack size
if (blockMax > max) {
max = blockMax;
}
// analyses the successors of the block
Edge b = l.successors;
while (b != null) {
l = b.successor;
// if this successor has not already been pushed onto the stack...
if (!l.pushed) {
// computes the true beginning stack size of this successor block
l.beginStackSize = start + b.stackSize;
// pushes this successor onto the stack
l.pushed = true;
l.next = stack;
stack = l;
}
b = b.next;
}
}
this.maxStack = max;
// releases all the Edge objects used by this CodeWriter
synchronized (SIZE) {
// appends the [head ... tail] list at the beginning of the pool list
if (tail != null) {
tail.poolNext = pool;
pool = head;
}
}
} else {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
}
}
public void visitLocalVariable (
final String name,
final String desc,
final Label start,
final Label end,
final int index)
{
if (CHECK) {
if (start.owner != this || !start.resolved) {
throw new IllegalArgumentException();
}
if (end.owner != this || !end.resolved) {
throw new IllegalArgumentException();
}
}
if (localVar == null) {
cw.newUTF8("LocalVariableTable");
localVar = new ByteVector();
}
++localVarCount;
localVar.putShort(start.position);
localVar.putShort(end.position - start.position);
localVar.putShort(cw.newUTF8(name));
localVar.putShort(cw.newUTF8(desc));
localVar.putShort(index);
}
public void visitLineNumber (final int line, final Label start) {
if (CHECK) {
if (start.owner != this || !start.resolved) {
throw new IllegalArgumentException();
}
}
if (lineNumber == null) {
cw.newUTF8("LineNumberTable");
lineNumber = new ByteVector();
}
++lineNumberCount;
lineNumber.putShort(start.position);
lineNumber.putShort(line);
}
public void visitAttribute (final Attribute attr) {
attr.next = cattrs;
cattrs = attr;
}
// --------------------------------------------------------------------------
// Utility methods: control flow analysis algorithm
// --------------------------------------------------------------------------
/**
* Computes the size of the arguments and of the return value of a method.
*
* @param desc the descriptor of a method.
* @return the size of the arguments of the method (plus one for the implicit
* this argument), argSize, and the size of its return value, retSize,
* packed into a single int i = <tt>(argSize << 2) | retSize</tt>
* (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -