in org.eclipse.sisu.inject/src/org/eclipse/sisu/space/asm/MethodWriter.java [1403:1648]
public void visitMaxs(final int maxStack, final int maxLocals) {
if (resize) {
// replaces the temporary jump opcodes introduced by Label.resolve.
if (ClassReader.RESIZE) {
resizeInstructions();
} else {
throw new RuntimeException("Method code too large!");
}
}
if (ClassReader.FRAMES && 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 reachable jump target must be stored in the stack map
if ((l.status & Label.TARGET) != 0) {
l.status |= Label.STORE;
}
// all visited labels are reachable, 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;
}
}
// 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) {
max = Math.max(max, 1);
// 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
int frameIndex = startFrame(start, 0, 1);
frame[frameIndex] = Frame.OBJECT
| cw.addType("java/lang/Throwable");
endFrame();
// removes the start-end range from the exception
// handlers
firstHandler = Handler.remove(firstHandler, l, k);
}
}
l = l.successor;
}
handler = firstHandler;
handlerCount = 0;
while (handler != null) {
handlerCount += 1;
handler = handler.next;
}
this.maxStack = max;
} 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) {
b.next = l.successors;
l.successors = b;
} else {
// 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;
}
// goes to the next label
l = l.successor;
}
handler = handler.next;
}
if (subroutines > 0) {
// 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.
*/
// finds the basic blocks that belong to the "main" subroutine
int id = 0;
labels.visitSubroutine(null, 1, subroutines);
// 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 has not been visited yet...
if ((subroutine.status & Label.VISITED) == 0) {
// ...assigns it a new id and finds its basic blocks
id += 1;
subroutine.visitSubroutine(null, (id / 32L) << 32
| (1L << (id % 32)), subroutines);
}
}
l = l.successor;
}
// second step: finds the successors of RET blocks
l = labels;
while (l != null) {
if ((l.status & Label.JSR) != 0) {
Label L = labels;
while (L != null) {
L.status &= ~Label.VISITED2;
L = L.successor;
}
// the subroutine is defined by l's TARGET, not by l
Label subroutine = l.successors.next.successor;
subroutine.visitSubroutine(l, 0, subroutines);
}
l = l.successor;
}
}
/*
* 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;
}
// analyzes 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;
l.next = stack;
stack = l;
}
b = b.next;
}
}
this.maxStack = Math.max(maxStack, max);
} else {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
}
}