📄 methodwriter.java
字号:
l.next = stack;
stack = l;
}
b = b.next;
}
}
this.maxStack = max;
} else {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
}
}
public void visitEnd() {
}
// ------------------------------------------------------------------------
// 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 <tt>i & 0x03</tt>).
*/
static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
int c = 1;
while (true) {
char car = desc.charAt(c++);
if (car == ')') {
car = desc.charAt(c);
return n << 2
| (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
} else if (car == 'L') {
while (desc.charAt(c++) != ';') {
}
n += 1;
} else if (car == '[') {
while ((car = desc.charAt(c)) == '[') {
++c;
}
if (car == 'D' || car == 'J') {
n -= 1;
}
} else if (car == 'D' || car == 'J') {
n += 2;
} else {
n += 1;
}
}
}
/**
* Adds a successor to the {@link #currentBlock currentBlock} block.
*
* @param info information about the control flow edge to be added.
* @param successor the successor block to be added to the current block.
*/
private void addSuccessor(final int info, final Label successor) {
// creates and initializes an Edge object...
Edge b = new Edge();
b.info = info;
b.successor = successor;
// ...and adds it to the successor list of the currentBlock block
b.next = currentBlock.successors;
currentBlock.successors = b;
}
/**
* Ends the current basic block. This method must be used in the case where
* the current basic block does not have any successor.
*/
private void noSuccessor() {
if (compute == FRAMES) {
Label l = new Label();
l.frame = new Frame();
l.frame.owner = l;
l.resolve(this, code.length, code.data);
previousBlock.successor = l;
previousBlock = l;
} else {
currentBlock.outputStackMax = maxStackSize;
}
currentBlock = null;
}
/**
* Finds the basic blocks that belong to a given subroutine, and marks these
* blocks as belonging to this subroutine (by using {@link Label#status} as
* a bit set (see {@link #visitMaxs}). This recursive method follows the
* control flow graph to find all the blocks that are reachable from the
* given block WITHOUT following any JSR target.
*
* @param block a block that belongs to the subroutine
* @param id the id of this subroutine
*/
private void findSubroutine(final Label block, final int id) {
// if 'block' is already marked as belonging to subroutine 'id', returns
if ((block.status & id) != 0) {
return;
}
// marks 'block' as belonging to subroutine 'id'
block.status |= id;
// calls this method recursively on each successor, except JSR targets
Edge e = block.successors;
while (e != null) {
// if 'block' is a JSR block, then 'block.successors.next' leads
// to the JSR target (see {@link #visitJumpInsn}) and must therefore
// not be followed
if ((block.status & Label.JSR) == 0 || e != block.successors.next) {
findSubroutine(e.successor, id);
}
e = e.next;
}
}
/**
* Finds the successors of the RET blocks of the specified subroutine, and
* of any nested subroutine it calls.
*
* @param id id of the subroutine whose RET block successors must be found.
* @param JSRs the JSR blocks that were followed to reach this subroutine.
* @param nJSRs number of JSR blocks in the JSRs array.
*/
private void findSubroutineSuccessors(
final int id,
final Label[] JSRs,
final int nJSRs)
{
// iterates over all the basic blocks...
Label l = labels;
while (l != null) {
// for those that belong to subroutine 'id'...
if ((l.status & id) != 0) {
if ((l.status & Label.JSR) != 0) {
// finds the subroutine to which 'l' leads by following the
// second edge of l.successors (see {@link #visitJumpInsn})
int nId = l.successors.next.successor.status & ~0xFFF;
if (nId != id) {
// calls this method recursively with l pushed onto the
// JSRs stack to find the successors of the RET blocks
// of this nested subroutine 'nId'
JSRs[nJSRs] = l;
findSubroutineSuccessors(nId, JSRs, nJSRs + 1);
}
} else if ((l.status & Label.RET) != 0) {
/*
* finds the JSR block in the JSRs stack that corresponds to
* this RET block, and updates the successors of this RET
* block accordingly. This corresponding JSR is the one that
* leads to the subroutine to which the RET block belongs.
* But the RET block can belong to several subroutines (if a
* nested subroutine returns to its parent subroutine
* implicitely, without a RET). So, in fact, the JSR that
* corresponds to this RET is the first block in the JSRs
* stack, starting from the bottom of the stack, that leads
* to a subroutine to which the RET block belongs.
*/
for (int i = 0; i < nJSRs; ++i) {
int JSRstatus = JSRs[i].successors.next.successor.status;
if (((JSRstatus & ~0xFFF) & (l.status & ~0xFFF)) != 0) {
Edge e = new Edge();
e.info = l.inputStackTop;
e.successor = JSRs[i].successors.successor;
e.next = l.successors;
l.successors = e;
break;
}
}
}
}
l = l.successor;
}
}
// ------------------------------------------------------------------------
// Utility methods: stack map frames
// ------------------------------------------------------------------------
/**
* Visits a frame that has been computed from scratch.
*
* @param f the frame that must be visited.
*/
private void visitFrame(final Frame f) {
int i, t;
int nTop = 0;
int nLocal = 0;
int nStack = 0;
int[] locals = f.inputLocals;
int[] stacks = f.inputStack;
// computes the number of locals (ignores TOP types that are just after
// a LONG or a DOUBLE, and all trailing TOP types)
for (i = 0; i < locals.length; ++i) {
t = locals[i];
if (t == Frame.TOP) {
++nTop;
} else {
nLocal += nTop + 1;
nTop = 0;
}
if (t == Frame.LONG || t == Frame.DOUBLE) {
++i;
}
}
// computes the stack size (ignores TOP types that are just after
// a LONG or a DOUBLE)
for (i = 0; i < stacks.length; ++i) {
t = stacks[i];
++nStack;
if (t == Frame.LONG || t == Frame.DOUBLE) {
++i;
}
}
// visits the frame and its content
startFrame(f.owner.position, nLocal, nStack);
for (i = 0; nLocal > 0; ++i, --nLocal) {
t = locals[i];
frame[frameIndex++] = t;
if (t == Frame.LONG || t == Frame.DOUBLE) {
++i;
}
}
for (i = 0; i < stacks.length; ++i) {
t = stacks[i];
frame[frameIndex++] = t;
if (t == Frame.LONG || t == Frame.DOUBLE) {
++i;
}
}
endFrame();
}
/**
* Starts the visit of a stack map frame.
*
* @param offset the offset of the instruction to which the frame
* corresponds.
* @param nLocal the number of local variables in the frame.
* @param nStack the number of stack elements in the frame.
*/
private void startFrame(final int offset, final int nLocal, final int nStack)
{
int n = 3 + nLocal + nStack;
if (frame == null || frame.length < n) {
frame = new int[n];
}
frame[0] = offset;
frame[1] = nLocal;
frame[2] = nStack;
frameIndex = 3;
}
/**
* Checks if the visit of the current frame {@link #frame} is finished, and
* if yes, write it in the StackMapTable attribute.
*/
private void endFrame() {
if (previousFrame != null) { // do not write the first frame
if (stackMap == null) {
stackMap = new ByteVector();
}
writeFrame();
++frameCount;
}
previousFrame = frame;
frame = null;
}
/**
* Compress and writes the current frame {@link #frame} in the StackMapTable
* attribute.
*/
private void writeFrame() {
int clocalsSize = frame[1];
int cstackSize = frame[2];
if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
stackMap.putShort(frame[0]).putShort(clocalsSize);
writeFrameTypes(3, 3 + clocalsSize);
stackMap.putShort(cstackSize);
writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize);
return;
}
int localsSize = previousFrame[1];
int type = FULL_FRAME;
int k = 0;
int delta;
if (frameCount == 0) {
delta = frame[0];
} else {
delta = frame[0] - previousFrame[0] - 1;
}
if (cstackSize == 0) {
k = clocalsSize - localsSize;
switch (k) {
case -3:
case -2:
case -1:
type = CHOP_FRAME;
localsSize = clocalsSize;
break;
case 0:
type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
break;
case 1:
case 2:
case 3:
type = APPEND_FRAME;
break;
}
} else if (clocalsSize == localsSize && cstackSize == 1) {
type = delta < 63
? SAME_LOCALS_1_STACK_ITEM_FRAME
: SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
}
if (type != FULL_FRAME) {
// verify if locals are the same
int l = 3;
for (int j = 0; j < localsSize; j++) {
if (frame[l] != previousFrame[l]) {
type = FULL_FRAME;
break;
}
l++;
}
}
switch (type) {
case SAME_FRAME:
stackMap.putByte(delta);
break;
case SAME_LOCALS_1_STACK_ITEM_FRAME:
stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
break;
case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
.putShort(delta);
writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
break;
case SA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -