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 { ...@@ -1648,22 +1648,28 @@ final class MethodWriter extends MethodVisitor {
if (hasSubroutines) { if (hasSubroutines) {
// First step: find the subroutines. This step determines, for each basic block, to which // First step: find the subroutines. This step determines, for each basic block, to which
// subroutine(s) it belongs. Start with the main "subroutine": // subroutine(s) it belongs. Start with the main "subroutine":
short subroutineId = 1; short numSubroutines = 1;
firstBasicBlock.markSubroutine(subroutineId); firstBasicBlock.markSubroutine(numSubroutines);
// Then, loop over all the basic blocks to find those that belong to real subroutines. // Then, mark the subroutines called by the main subroutine, then the subroutines called by
Label basicBlock = firstBasicBlock; // those called by the main subroutine, etc.
while (basicBlock != null) { for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_START) != 0 && basicBlock.subroutineId == 0) { Label basicBlock = firstBasicBlock;
// If this subroutine has not been marked yet, find its basic blocks. while (basicBlock != null) {
subroutineId += 1; if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
basicBlock.markSubroutine(subroutineId); && 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 // 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 // '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'. // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
basicBlock = firstBasicBlock; Label basicBlock = firstBasicBlock;
while (basicBlock != null) { while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
// By construction, jsr targets are stored in the second outgoing edge of basic blocks // By construction, jsr targets are stored in the second outgoing edge of basic blocks
......
...@@ -1063,4 +1063,42 @@ public class ClassWriterComputeMaxsTest { ...@@ -1063,4 +1063,42 @@ public class ClassWriterComputeMaxsTest {
"N42=", "N42=",
"N44=N37,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