Skip to content

Commit a541120

Browse files
committed
Improve the experimental try-loop fix
- It now properly decompiles more things, and doesn't cause extra problems and decompilation failures as a side effect. It specifically targets when if statements are built and triggers a full postdominator set calculation and general statement finding, which properly decomposes the graph.
1 parent 256929d commit a541120

File tree

8 files changed

+180
-70
lines changed

8 files changed

+180
-70
lines changed

src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
public class ClassWrapper {
2828
// Sometimes when debugging you want to be able to only analyze a specific method.
2929
// When not null, this skips processing of every method except the one with the name specified.
30-
private static final String DEBUG_METHOD_FILTER = null;
30+
private static final String DEBUG_METHOD_FILTER = "test";
3131
private final StructClass classStruct;
3232
private final Set<String> hiddenMembers = new HashSet<>();
3333
private final VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<>();

src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,14 @@ private static RootStatement graphToStatement(ControlFlowGraph graph, StructMeth
4646
return root;
4747
}
4848

49-
boolean firstIsException = false;
50-
51-
if (DecompilerContext.getOption(IFernflowerPreferences.EXPERIMENTAL_TRY_LOOP_FIX)) {
52-
// Check if the first block in the graph is covered by an exception range.
53-
// If it is, we need to avoid setting the edge type to continue, as that causes problems later down the line.
54-
55-
for (ExceptionRangeCFG exception : graph.getExceptions()) {
56-
if (exception.getProtectedRange().contains(firstblock)) {
57-
firstIsException = true;
58-
break;
59-
}
60-
}
61-
}
62-
6349
for (BasicBlock block : blocks) {
6450
Statement stat = stats.getWithKey(block.id);
6551

6652
for (BasicBlock succ : block.getSuccs()) {
6753
Statement stsucc = stats.getWithKey(succ.id);
6854

6955
int type;
70-
if (stsucc == firstst && !firstIsException) {
56+
if (stsucc == firstst) {
7157
type = StatEdge.TYPE_CONTINUE;
7258
stsucc = general;
7359
}

src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.jetbrains.java.decompiler.code.CodeConstants;
55
import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
66
import org.jetbrains.java.decompiler.main.DecompilerContext;
7+
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
78
import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
89
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
910
import org.jetbrains.java.decompiler.util.TextBuffer;
@@ -131,6 +132,14 @@ else if (next != statn) {
131132
}
132133
}
133134

135+
// Don't build a trycatch around a loop-head if statement, as we know that DoStatement should be built first.
136+
// Since CatchStatement's isHead is run after DoStatement's, we can assume that a loop was not able to be built.
137+
if (DecompilerContext.getOption(IFernflowerPreferences.EXPERIMENTAL_TRY_LOOP_FIX)) {
138+
if (head.type == Statement.TYPE_IF && head.getContinueSet().contains(head.first)) {
139+
return null;
140+
}
141+
}
142+
134143
if (DecHelper.checkStatementExceptions(lst)) {
135144
return new CatchStatement(head, next, setHandlers);
136145
}

test/org/jetbrains/java/decompiler/SingleClassesTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ private void registerLVT() {
590590

591591
private void registerTryLoop() {
592592
register(JAVA_8, "TestTryLoop");
593+
register(JAVA_8, "TestTryLoop2");
593594
register(JAVA_8, "TestTryLoopRecompile");
594595
register(JAVA_8, "TestTryLoopSimpleFinally");
595596
// TODO: Still doesn't properly decompile, loop needs to be in the try block

testData/results/pkg/TestTryLoop.dec

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package pkg;
22

33
import java.io.File;
44
import java.io.FileNotFoundException;
5+
import java.nio.file.Files;
6+
import java.nio.file.LinkOption;
57
import java.nio.file.Path;
68
import java.util.Iterator;
79
import java.util.Scanner;
10+
import java.util.ServiceConfigurationError;
811

912
public class TestTryLoop {
1013
private boolean field;
@@ -20,54 +23,91 @@ public class TestTryLoop {
2023

2124
}// 22
2225

23-
public boolean hasNext(Path param1, Iterator<File> param2) {
24-
// $FF: Couldn't be decompiled
25-
// Bytecode:
26-
// 00: aload 1
27-
// 01: bipush 0
28-
// 02: anewarray 7
29-
// 05: invokestatic java/nio/file/Files.exists (Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Z
30-
// 08: ifeq 17
31-
// 0b: aload 2
32-
// 0c: invokeinterface java/util/Iterator.next ()Ljava/lang/Object; 1
33-
// 11: checkcast java/io/File
34-
// 14: astore 3
35-
// 15: bipush 1
36-
// 16: ireturn
37-
// 17: bipush 0
38-
// 18: ireturn
39-
// 19: astore 4
40-
// 1b: getstatic java/lang/System.out Ljava/io/PrintStream;
41-
// 1e: bipush 1
42-
// 1f: invokevirtual java/io/PrintStream.println (I)V
43-
// 22: goto 00
44-
// 25: astore 4
45-
// 27: getstatic java/lang/System.out Ljava/io/PrintStream;
46-
// 2a: bipush 2
47-
// 2b: invokevirtual java/io/PrintStream.println (I)V
48-
// 2e: goto 00
26+
public boolean hasNext(Path p, Iterator<File> f) {
27+
while(true) {
28+
try {
29+
if (Files.exists(p, new LinkOption[0])) {// 28
30+
File a = (File)f.next();// 29
31+
return true;// 30
32+
}
33+
34+
return false;// 32
35+
} catch (ServiceConfigurationError var5) {// 33
36+
System.out.println(1);// 34
37+
} catch (NoClassDefFoundError var6) {// 35
38+
System.out.println(2);// 36
39+
}
40+
}
4941
}
5042
}
5143

5244
class 'pkg/TestTryLoop' {
5345
method 'test (Ljava/io/File;)V' {
54-
0 13
55-
1 13
56-
2 13
57-
3 13
58-
b 14
59-
16 16
60-
18 17
61-
1b 20
46+
0 16
47+
1 16
48+
2 16
49+
3 16
50+
b 17
51+
16 19
52+
18 20
53+
1b 23
54+
}
55+
56+
method 'hasNext (Ljava/nio/file/Path;Ljava/util/Iterator;)Z' {
57+
0 28
58+
1 28
59+
5 28
60+
6 28
61+
7 28
62+
8 28
63+
b 29
64+
c 29
65+
d 29
66+
e 29
67+
f 29
68+
10 29
69+
11 29
70+
12 29
71+
13 29
72+
14 29
73+
15 30
74+
16 30
75+
17 33
76+
18 33
77+
19 34
78+
1b 35
79+
1c 35
80+
1d 35
81+
1e 35
82+
1f 35
83+
20 35
84+
21 35
85+
25 36
86+
27 37
87+
28 37
88+
29 37
89+
2a 37
90+
2b 37
91+
2c 37
92+
2d 37
6293
}
6394
}
6495

6596
Lines mapping:
66-
16 <-> 14
67-
17 <-> 15
68-
19 <-> 17
69-
20 <-> 18
70-
22 <-> 21
97+
16 <-> 17
98+
17 <-> 18
99+
19 <-> 20
100+
20 <-> 21
101+
22 <-> 24
102+
28 <-> 29
103+
29 <-> 30
104+
30 <-> 31
105+
32 <-> 34
106+
33 <-> 35
107+
34 <-> 36
108+
35 <-> 37
109+
36 <-> 38
71110
Not mapped:
72111
18
73112
21
113+
37
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package pkg;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.util.Scanner;
6+
7+
public class TestTryLoop2 {
8+
private boolean field;
9+
10+
public void test(File file) {
11+
while(true) {
12+
try {
13+
if (!this.field) {// 13
14+
return;// 24
15+
}
16+
17+
new Scanner(file);// 14
18+
} catch (FileNotFoundException var3) {// 20
19+
var3.printStackTrace();// 21
20+
}
21+
}
22+
}
23+
}
24+
25+
class 'pkg/TestTryLoop2' {
26+
method 'test (Ljava/io/File;)V' {
27+
0 12
28+
1 12
29+
2 12
30+
3 12
31+
4 12
32+
b 16
33+
16 17
34+
18 18
35+
19 18
36+
1a 18
37+
1e 13
38+
}
39+
}
40+
41+
Lines mapping:
42+
13 <-> 13
43+
14 <-> 17
44+
20 <-> 18
45+
21 <-> 19
46+
24 <-> 14
47+
Not mapped:
48+
16
49+
19
50+
22

testData/results/pkg/TestTryLoopRecompile.dec

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ public class TestTryLoopRecompile {
1010
public void test(File file) {
1111
while(true) {
1212
try {
13-
if (!this.field) {// 13
14-
break;
13+
if (this.field) {// 13
14+
new Scanner(file);// 14
15+
continue;
1516
}
16-
17-
new Scanner(file);// 14
1817
} catch (FileNotFoundException var3) {// 17
1918
var3.printStackTrace();// 18
20-
break;
2119
}
22-
}
2320

24-
}// 21
21+
return;// 21
22+
}
23+
}
2524
}
2625

2726
class 'pkg/TestTryLoopRecompile' {
@@ -31,19 +30,19 @@ class 'pkg/TestTryLoopRecompile' {
3130
2 12
3231
3 12
3332
4 12
34-
b 16
35-
16 17
36-
18 18
37-
1b 23
33+
b 13
34+
16 16
35+
18 17
36+
1b 20
3837
}
3938
}
4039

4140
Lines mapping:
4241
13 <-> 13
43-
14 <-> 17
44-
17 <-> 18
45-
18 <-> 19
46-
21 <-> 24
42+
14 <-> 14
43+
17 <-> 17
44+
18 <-> 18
45+
21 <-> 21
4746
Not mapped:
4847
15
4948
19
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package pkg;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.util.Scanner;
6+
7+
public class TestTryLoop2 {
8+
private boolean field;
9+
10+
public void test(File file) {
11+
while (true) {
12+
try {
13+
if (this.field) {
14+
Scanner scanner = new Scanner(file);
15+
16+
continue;
17+
}
18+
19+
break;
20+
} catch (FileNotFoundException e) {
21+
e.printStackTrace();
22+
}
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)