📄 methodwriter.java
字号:
int source = code.length;
code.putByte(Opcodes.TABLESWITCH);
code.length += (4 - code.length % 4) % 4;
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);
}
// updates currentBlock
visitSwitchInsn(dflt, labels);
}
public void visitLookupSwitchInsn(
final Label dflt,
final int keys[],
final Label labels[])
{
// adds the instruction to the bytecode of the method
int source = code.length;
code.putByte(Opcodes.LOOKUPSWITCH);
code.length += (4 - code.length % 4) % 4;
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);
}
// updates currentBlock
visitSwitchInsn(dflt, labels);
}
private void visitSwitchInsn(final Label dflt, final Label[] labels) {
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null);
// adds current block successors
addSuccessor(Edge.NORMAL, dflt);
dflt.getFirst().status |= Label.TARGET;
for (int i = 0; i < labels.length; ++i) {
addSuccessor(Edge.NORMAL, labels[i]);
labels[i].getFirst().status |= Label.TARGET;
}
} else {
// updates current stack size (max stack size unchanged)
--stackSize;
// adds current block successors
addSuccessor(stackSize, dflt);
for (int i = 0; i < labels.length; ++i) {
addSuccessor(stackSize, labels[i]);
}
}
// ends current block
noSuccessor();
}
}
public void visitMultiANewArrayInsn(final String desc, final int dims) {
Item i = cw.newClassItem(desc);
// Label currentBlock = this.currentBlock;
if (currentBlock != null) {
if (compute == FRAMES) {
currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i);
} else {
// 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(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
}
public void visitTryCatchBlock(
final Label start,
final Label end,
final Label handler,
final String type)
{
++handlerCount;
Handler h = new Handler();
h.start = start;
h.end = end;
h.handler = handler;
h.desc = type;
h.type = type != null ? cw.newClass(type) : 0;
if (lastHandler == null) {
firstHandler = h;
} else {
lastHandler.next = h;
}
lastHandler = h;
}
public void visitLocalVariable(
final String name,
final String desc,
final String signature,
final Label start,
final Label end,
final int index)
{
if (signature != null) {
if (localVarType == null) {
localVarType = new ByteVector();
}
++localVarTypeCount;
localVarType.putShort(start.position)
.putShort(end.position - start.position)
.putShort(cw.newUTF8(name))
.putShort(cw.newUTF8(signature))
.putShort(index);
}
if (localVar == null) {
localVar = new ByteVector();
}
++localVarCount;
localVar.putShort(start.position)
.putShort(end.position - start.position)
.putShort(cw.newUTF8(name))
.putShort(cw.newUTF8(desc))
.putShort(index);
if (compute != NOTHING) {
// updates max locals
char c = desc.charAt(0);
int n = index + (c == 'J' || c == 'D' ? 2 : 1);
if (n > maxLocals) {
maxLocals = n;
}
}
}
public void visitLineNumber(final int line, final Label start) {
if (lineNumber == null) {
lineNumber = new ByteVector();
}
++lineNumberCount;
lineNumber.putShort(start.position);
lineNumber.putShort(line);
}
public void visitMaxs(final int maxStack, final int maxLocals) {
if (compute == FRAMES) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
while (handler != null) {
Label l = handler.start.getFirst();
Label h = handler.handler.getFirst();
Label e = handler.end.getFirst();
// computes the kind of the edges to 'h'
String t = handler.desc == null
? "java/lang/Throwable"
: handler.desc;
int kind = Frame.OBJECT | cw.addType(t);
// h is an exception handler
h.status |= Label.TARGET;
// adds 'h' as a successor of labels between 'start' and 'end'
while (l != e) {
// creates an edge to 'h'
Edge b = new Edge();
b.info = kind;
b.successor = h;
// adds it to the successors of 'l'
b.next = l.successors;
l.successors = b;
// goes to the next label
l = l.successor;
}
handler = handler.next;
}
// creates and visits the first (implicit) frame
Frame f = labels.frame;
Type[] args = Type.getArgumentTypes(descriptor);
f.initInputFrame(cw, access, args, this.maxLocals);
visitFrame(f);
/*
* fix point algorithm: mark the first basic block as 'changed'
* (i.e. put it in the 'changed' list) and, while there are changed
* basic blocks, choose one, mark it as unchanged, and update its
* successors (which can be changed in the process).
*/
int max = 0;
Label changed = labels;
while (changed != null) {
// removes a basic block from the list of changed basic blocks
Label l = changed;
changed = changed.next;
l.next = null;
f = l.frame;
// a reacheable jump target must be stored in the stack map
if ((l.status & Label.TARGET) != 0) {
l.status |= Label.STORE;
}
// all visited labels are reacheable, by definition
l.status |= Label.REACHABLE;
// updates the (absolute) maximum stack size
int blockMax = f.inputStack.length + l.outputStackMax;
if (blockMax > max) {
max = blockMax;
}
// updates the successors of the current basic block
Edge e = l.successors;
while (e != null) {
Label n = e.successor.getFirst();
boolean change = f.merge(cw, n.frame, e.info);
if (change && n.next == null) {
// if n has changed and is not already in the 'changed'
// list, adds it to this list
n.next = changed;
changed = n;
}
e = e.next;
}
}
this.maxStack = max;
// visits all the frames that must be stored in the stack map
Label l = labels;
while (l != null) {
f = l.frame;
if ((l.status & Label.STORE) != 0) {
visitFrame(f);
}
if ((l.status & Label.REACHABLE) == 0) {
// finds start and end of dead basic block
Label k = l.successor;
int start = l.position;
int end = (k == null ? code.length : k.position) - 1;
// if non empty basic block
if (end >= start) {
// replaces instructions with NOP ... NOP ATHROW
for (int i = start; i < end; ++i) {
code.data[i] = Opcodes.NOP;
}
code.data[end] = (byte) Opcodes.ATHROW;
// emits a frame for this unreachable block
startFrame(start, 0, 1);
frame[frameIndex++] = Frame.OBJECT
| cw.addType("java/lang/Throwable");
endFrame();
}
}
l = l.successor;
}
} else if (compute == MAXS) {
// completes the control flow graph with exception handler blocks
Handler handler = firstHandler;
while (handler != null) {
Label l = handler.start;
Label h = handler.handler;
Label e = handler.end;
// adds 'h' as a successor of labels between 'start' and 'end'
while (l != e) {
// creates an edge to 'h'
Edge b = new Edge();
b.info = Edge.EXCEPTION;
b.successor = h;
// adds it to the successors of 'l'
if ((l.status & Label.JSR) != 0) {
// if l is a JSR block, adds b after the first two edges
// to preserve the hypothesis about JSR block successors
// order (see {@link #visitJumpInsn})
b.next = l.successors.next.next;
l.successors.next.next = b;
} else {
b.next = l.successors;
l.successors = b;
}
// goes to the next label
l = l.successor;
}
handler = handler.next;
}
if (jsr) {
// completes the control flow graph with the RET successors
/*
* first step: finds the subroutines. This step determines, for
* each basic block, to which subroutine(s) it belongs, and
* stores this set as a bit set in the {@link Label#status}
* field. Subroutines are numbered with powers of two, from
* 0x1000 to 0x80000000 (so there must be at most 20 subroutines
* in a method).
*/
// finds the basic blocks that belong to the "main" subroutine
int id = 0x1000;
findSubroutine(labels, id);
// finds the basic blocks that belong to the real subroutines
Label l = labels;
while (l != null) {
if ((l.status & Label.JSR) != 0) {
// the subroutine is defined by l's TARGET, not by l
Label subroutine = l.successors.next.successor;
// if this subroutine does not have an id yet...
if ((subroutine.status & ~0xFFF) == 0) {
// ...assigns it a new id and finds its basic blocks
id = id << 1;
findSubroutine(subroutine, id);
}
}
l = l.successor;
}
// second step: finds the successors of RET blocks
findSubroutineSuccessors(0x1000, new Label[10], 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#inputStackTop} of the
* blocks in the block stack are the true (non relative) beginning
* stack sizes of these blocks.
*/
int max = 0;
Label stack = labels;
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.inputStackTop;
int blockMax = start + l.outputStackMax;
// updates the global max stack size
if (blockMax > max) {
max = blockMax;
}
// analyses the successors of the block
Edge b = l.successors;
if ((l.status & Label.JSR) != 0) {
// ignores the first edge of JSR blocks (virtual successor)
b = b.next;
}
while (b != null) {
l = b.successor;
// if this successor has not already been pushed...
if ((l.status & Label.PUSHED) == 0) {
// computes its true beginning stack size...
l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start
+ b.info;
// ...and pushes it onto the stack
l.status |= Label.PUSHED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -