Commit 71a78ab5 authored by Eric Bruneton's avatar Eric Bruneton

Improve the fix for issue #317823, which was not using a strict equivalent of...

Improve the fix for issue #317823, which was not using a strict equivalent of the Analyzer algorithm (the labeling of the subroutines was depending on their order of appearance in the bytecode sequence).
parent 2152b6ab
......@@ -1648,22 +1648,28 @@ final class MethodWriter extends MethodVisitor {
if (hasSubroutines) {
// First step: find the subroutines. This step determines, for each basic block, to which
// subroutine(s) it belongs. Start with the main "subroutine":
short subroutineId = 1;
firstBasicBlock.markSubroutine(subroutineId);
// Then, loop over all the basic blocks to find those that belong to real subroutines.
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_START) != 0 && basicBlock.subroutineId == 0) {
// If this subroutine has not been marked yet, find its basic blocks.
subroutineId += 1;
basicBlock.markSubroutine(subroutineId);
short numSubroutines = 1;
firstBasicBlock.markSubroutine(numSubroutines);
// Then, mark the subroutines called by the main subroutine, then the subroutines called by
// those called by the main subroutine, etc.
for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
&& basicBlock.subroutineId == currentSubroutine) {
Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
if (jsrTarget.subroutineId == 0) {
// If this subroutine has not been marked yet, find its basic blocks.
jsrTarget.markSubroutine(++numSubroutines);
}
}
basicBlock = basicBlock.nextBasicBlock;
}
basicBlock = basicBlock.nextBasicBlock;
}
// Second step: find the successors in the control flow graph of each subroutine basic block
// 'r' ending with a RET instruction. These successors are the virtual successors of the basic
// blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
basicBlock = firstBasicBlock;
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
// By construction, jsr targets are stored in the second outgoing edge of basic blocks
......
......@@ -1063,4 +1063,42 @@ public class ClassWriterComputeMaxsTest {
"N42=",
"N44=N37,N42");
}
/**
* Tests a nested subroutine with implicit exit from the nested subroutine to the outer one, with
* the second subroutine coming first in the bytecode instructions sequence.
*/
@Test
public void testImplicitExitToAnotherSubroutineInverted() {
Label l1 = new Label();
Label l2 = new Label();
Label l3 = new Label();
Label l4 = new Label();
Label l5 = new Label();
GOTO(l4); // N0
// Second subroutine, returns to caller of first subroutine.
LABEL(l2); // N3
ASTORE(2);
LABEL(l3); // N4
RET(1);
// First subroutine.
LABEL(l1); // N6
ASTORE(1);
ALOAD(0);
IFNONNULL(l3);
JSR(l2); // This JSR never returns, the following code is unreachable.
ACONST_NULL(); // N14
ACONST_NULL();
ACONST_NULL();
RETURN();
// Main "subroutine".
LABEL(l4); // N18
JSR(l1);
LABEL(l5); // N21
RETURN();
assertMaxs(1, 3);
assertGraph("N0=N18", "N3=N4", "N4=N21", "N6=N3,N4", "N14=", "N18=N6", "N21=");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment