From 976434e0e47682e85c7fe8120854c1703d3e3790 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:24:07 -0400 Subject: [PATCH 01/29] Start 1.13.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4706c66b22..3c2cf90be7 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ allprojects { group = 'org.vineflower' base.archivesName = 'vineflower' -version = '1.12.0' +version = '1.13.0' def ENV = System.getenv() version = version + (ENV.GITHUB_ACTIONS ? "" : "+local") From 7aef7f869a11b85a1a06e50247b5899fd0cac59a Mon Sep 17 00:00:00 2001 From: coehlrich Date: Mon, 4 May 2026 01:20:14 +1200 Subject: [PATCH 02/29] Fix a bunch of variables not getting their LVTs (#567) --- .../results/pkg/TestNullableOperator.dec | 23 +++--- .../testData/results/pkg/TestSynchronized.dec | 6 +- .../results/pkg/TestTailrecFunctions.dec | 8 +- .../results/pkg/TestTryCatchFinally.dec | 8 +- .../testData/results/pkg/TestTryFinally.dec | 25 +++--- .../results/pkg/TestTryFinallyExpressions.dec | 60 +++++++------- .../results/pkg/TestTryLoopSimpleFinally.dec | 8 +- .../testData/results/pkg/TestTryReturn.dec | 78 ++++++++++--------- .../testData/results/pkg/TestTrySplit.dec | 8 +- .../modules/decompiler/ExprProcessor.java | 2 +- testData/results/JsHurt.dec | 2 +- testData/results/TestEclipseSwitchString.dec | 39 +++++----- testData/results/TestHotjava.dec | 23 +++--- testData/results/TestJava1Synchronized.dec | 35 +++++---- testData/results/TestJsr.dec | 11 +-- testData/results/pkg/TestCaseClasses.dec | 6 +- .../results/pkg/TestComplexIfElseChain.dec | 8 +- .../pkg/TestFinallyBlockVariableUse.dec | 2 +- testData/results/pkg/TestFinallyVarDef.dec | 30 +++---- testData/results/pkg/TestIrreducible.dec | 52 ++++++------- testData/results/pkg/TestLoopFinally.dec | 18 ++--- .../results/pkg/TestNamedSuspendFun2Kt.dec | 45 +++++------ .../pkg/TestPatternMatchSwitchString.dec | 7 +- testData/results/pkg/TestPatternMatching.dec | 21 ++--- .../results/pkg/TestPatternMatching17.dec | 21 ++--- .../results/pkg/TestPatternMatching17Fake.dec | 8 +- ...TestPatternMatching17FakeLoopsInverted.dec | 25 +++--- .../pkg/TestPatternMatching17FakeNew.dec | 8 +- .../results/pkg/TestPatternMatchingFake.dec | 8 +- .../TestPatternMatchingFakeLoopsInverted.dec | 23 +++--- .../pkg/TestPatternMatchingFakeNew.dec | 8 +- .../pkg/TestPatternMatchingVariableScope.dec | 29 +++---- testData/results/pkg/TestRecordPatterns6.dec | 4 +- testData/results/pkg/TestRecordPatterns7.dec | 37 +++++---- testData/results/pkg/TestRecordPatterns8.dec | 4 +- .../results/pkg/TestStringSwitchTypes.dec | 13 ++-- testData/results/pkg/TestSwitchFinally.dec | 46 +++++------ .../pkg/TestSwitchPatternMatching16.dec | 8 +- .../TestSwitchPatternMatchingInstanceof1.dec | 6 +- .../TestSwitchPatternMatchingInstanceof2.dec | 6 +- .../TestSwitchPatternMatchingInstanceof4.dec | 20 ++--- .../pkg/TestSwitchPatternMatchingJ25.dec | 12 +-- .../pkg/TestSwitchStringHashcodeCollision.dec | 7 +- .../pkg/TestSynchronizedUnprotected.dec | 7 +- testData/results/pkg/TestTryCatchFinally.dec | 8 +- testData/results/pkg/TestTryFinally.dec | 23 +++--- .../results/pkg/TestTryLoopSimpleFinally.dec | 8 +- testData/results/pkg/TestTryReturn.dec | 62 ++++++++------- testData/results/pkg/TestTrySplit.dec | 8 +- .../pkg/TestTryWithResourcesAfterSwitch.dec | 16 ++-- .../pkg/TestTryWithResourcesFinallyJ16.dec | 16 ++-- .../results/pkg/TestTryWithResourcesJ16.dec | 8 +- .../pkg/TestTryWithResourcesManyJ16.dec | 8 +- .../pkg/TestTryWithResourcesMultiJ16.dec | 24 +++--- .../pkg/TestTryWithResourcesNestedJ16.dec | 16 ++-- .../pkg/TestTryWithResourcesNestedLoop.dec | 2 +- .../pkg/TestTryWithResourcesOuterJ16.dec | 8 +- .../pkg/TestTryWithResourcesReturn.dec | 20 ++--- .../pkg/TestTryWithResourcesReturnJ16.dec | 4 +- testData/results/pkg/TestUnknownCastJ17.dec | 10 +-- testData/results/pkg/TestVarRedef.dec | 4 +- 61 files changed, 561 insertions(+), 509 deletions(-) diff --git a/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec b/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec index bf3052ed5b..91a429ebe2 100644 --- a/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec +++ b/plugins/kotlin/testData/results/pkg/TestNullableOperator.dec @@ -52,7 +52,7 @@ public class TestNullableOperator { } else { throw Exception() } - } + }// 30 public fun test6(x: Int?): Int { if (x != null) {// 33 @@ -68,7 +68,7 @@ public class TestNullableOperator { if (x != null) {// 41 System.out.println(x)// 43 } - } + }// 44 } class 'pkg/TestNullableOperator' { @@ -116,8 +116,8 @@ class 'pkg/TestNullableOperator' { 5 36 6 36 7 36 - 8 36 13 38 + 14 36 } method 'test4 (Ljava/lang/Exception;)V' { @@ -139,8 +139,8 @@ class 'pkg/TestNullableOperator' { 5 50 6 50 7 50 - 8 54 13 52 + 14 54 } method 'test6 (Ljava/lang/Integer;)I' { @@ -151,16 +151,18 @@ class 'pkg/TestNullableOperator' { 5 58 6 58 7 58 - 8 58 c 62 d 62 - e 59 + e 58 f 59 10 59 + 11 59 12 59 13 59 14 59 + 15 59 16 60 + 17 60 } method 'test6_1 (Ljava/lang/Integer;)V' { @@ -172,12 +174,14 @@ class 'pkg/TestNullableOperator' { 6 68 7 68 c 70 - d 68 e 68 f 68 + 10 68 11 68 12 68 13 68 + 14 68 + 15 70 } } @@ -190,11 +194,10 @@ Lines mapping: 25 <-> 44 26 <-> 47 29 <-> 50 +30 <-> 55 33 <-> 58 35 <-> 60 37 <-> 61 41 <-> 68 43 <-> 69 -Not mapped: -30 -44 +44 <-> 71 diff --git a/plugins/kotlin/testData/results/pkg/TestSynchronized.dec b/plugins/kotlin/testData/results/pkg/TestSynchronized.dec index 7886c813db..ccbc989643 100644 --- a/plugins/kotlin/testData/results/pkg/TestSynchronized.dec +++ b/plugins/kotlin/testData/results/pkg/TestSynchronized.dec @@ -5,7 +5,7 @@ public class TestSynchronized { synchronized (this) {// 5 System.out.println("Hello")// 6 } - } + }// 8 } class 'pkg/TestSynchronized' { @@ -21,13 +21,13 @@ class 'pkg/TestSynchronized' { d 5 e 5 f 5 - 17 7 + 1f 7 } } Lines mapping: 5 <-> 5 6 <-> 6 +8 <-> 8 Not mapped: 7 -8 diff --git a/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec b/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec index e36d5cc9b9..f23dedce62 100644 --- a/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec +++ b/plugins/kotlin/testData/results/pkg/TestTailrecFunctions.dec @@ -21,7 +21,7 @@ public class TestTailrecFunctions { } finally { this.testFinally()// 13 } - }// 14 + }// 15 public tailrec fun testFinallyReturn(): Int { try { @@ -133,11 +133,11 @@ class 'pkg/TestTailrecFunctions' { } method 'testFinally ()V' { - 5 23 9 21 a 21 b 21 c 21 + f 23 } method 'testFinallyReturn ()I' { @@ -318,7 +318,7 @@ Lines mapping: 5 <-> 7 6 <-> 10 13 <-> 22 -14 <-> 24 +15 <-> 24 21 <-> 30 27 <-> 36 29 <-> 37 @@ -339,7 +339,7 @@ Lines mapping: 53 <-> 97 Not mapped: 10 -15 +14 18 26 34 diff --git a/plugins/kotlin/testData/results/pkg/TestTryCatchFinally.dec b/plugins/kotlin/testData/results/pkg/TestTryCatchFinally.dec index b67bdd8112..50c2340e58 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryCatchFinally.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryCatchFinally.dec @@ -34,7 +34,7 @@ public class TestTryCatchFinally { System.out.println("Finally")// 52 } - return -1// 53 54 + return -1// 54 } public fun testEmptyCatch(msg: String?) { @@ -100,7 +100,7 @@ class 'pkg/TestTryCatchFinally' { 8 29 9 29 a 29 - b 29 + 16 29 17 30 18 31 19 31 @@ -114,7 +114,6 @@ class 'pkg/TestTryCatchFinally' { 22 31 23 31 24 31 - 2e 36 32 33 33 33 34 33 @@ -124,6 +123,7 @@ class 'pkg/TestTryCatchFinally' { 39 33 3a 33 3d 36 + 3e 36 } method 'testEmptyCatch (Ljava/lang/String;)V' { @@ -162,7 +162,6 @@ Lines mapping: 49 <-> 31 50 <-> 32 52 <-> 34 -53 <-> 37 54 <-> 37 59 <-> 42 60 <-> 43 @@ -174,5 +173,6 @@ Not mapped: 23 32 47 +53 58 63 diff --git a/plugins/kotlin/testData/results/pkg/TestTryFinally.dec b/plugins/kotlin/testData/results/pkg/TestTryFinally.dec index ca0d655eac..8fa817f5a8 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryFinally.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryFinally.dec @@ -7,7 +7,7 @@ public class TestTryFinally { } finally { val var2: Long = 5L// 8 } - }// 9 + }// 10 public fun test1() { try { @@ -16,8 +16,8 @@ public class TestTryFinally { System.out.println("Finally")// 16 } - System.out.println("Bye")// 17 19 - } + System.out.println("Bye")// 19 + }// 20 public fun test2(i: Int) { try { @@ -44,11 +44,11 @@ class 'pkg/TestTryFinally' { 7 5 8 5 9 5 - e 9 12 7 13 7 14 7 15 7 + 18 9 } method 'test1 ()V' { @@ -60,8 +60,6 @@ class 'pkg/TestTryFinally' { 7 13 8 13 9 13 - 13 18 - 14 18 17 15 18 15 19 15 @@ -73,9 +71,12 @@ class 'pkg/TestTryFinally' { 22 18 23 18 24 18 - 27 18 + 25 18 + 26 18 28 18 29 18 + 2a 18 + 2b 19 } method 'test2 (I)V' { @@ -122,11 +123,11 @@ class 'pkg/TestTryFinally' { Lines mapping: 6 <-> 6 8 <-> 8 -9 <-> 10 +10 <-> 10 14 <-> 14 16 <-> 16 -17 <-> 19 19 <-> 19 +20 <-> 20 25 <-> 24 27 <-> 26 28 <-> 27 @@ -136,8 +137,8 @@ Lines mapping: 35 <-> 34 Not mapped: 5 -10 +9 13 -20 +17 24 -32 \ No newline at end of file +32 diff --git a/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec b/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec index aa973c72f4..3345132bfa 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryFinallyExpressions.dec @@ -13,8 +13,8 @@ public class TestTryFinallyExpressions { System.out.println("bye")// 10 } - System.out.print(var2)// 7 11 - } + System.out.print(var2)// 7 + }// 12 public fun test1(a: String, b: String) { val x: java.lang.String = a// 15 @@ -29,8 +29,8 @@ public class TestTryFinallyExpressions { ; } - val var7: java.lang.String = var4// 19 - var6 = var10000// 20 + val var7: java.lang.String = var4// 19 20 + var6 = var10000 var var10001: java.lang.String try { @@ -41,8 +41,8 @@ public class TestTryFinallyExpressions { System.out.println(a)// 23 } - var10000.test0("$var10001$var4")// 24 - }// 16 + var10000.test0("$var10001$var4")// 16 + }// 25 public fun test2(a: String, b: String) { var var19: java.lang.String = a// 28 @@ -82,8 +82,8 @@ public class TestTryFinallyExpressions { System.out.println(var19)// 49 } - var10000.test1(var10001, var4)// 29 50 - } + var10000.test1(var10001, var4)// 29 + }// 51 } class 'pkg/TestTryFinallyExpressions' { @@ -97,7 +97,6 @@ class 'pkg/TestTryFinallyExpressions' { d 10 e 10 f 10 - 19 15 1d 12 1e 12 1f 12 @@ -106,12 +105,15 @@ class 'pkg/TestTryFinallyExpressions' { 23 12 24 12 25 12 - 29 15 + 28 15 2a 15 2b 15 + 2c 15 2d 15 2e 15 2f 15 + 30 15 + 31 16 } method 'test1 (Ljava/lang/String;Ljava/lang/String;)V' { @@ -132,12 +134,12 @@ class 'pkg/TestTryFinallyExpressions' { 1b 26 1c 26 1d 26 - 20 31 - 21 31 2a 31 2b 31 - 2c 32 - 2d 32 + 2c 31 + 2d 31 + 2e 32 + 2f 32 31 36 32 36 33 37 @@ -152,8 +154,6 @@ class 'pkg/TestTryFinallyExpressions' { 3c 38 3d 38 3e 38 - 46 43 - 47 43 4b 40 4c 40 4d 40 @@ -166,7 +166,12 @@ class 'pkg/TestTryFinallyExpressions' { 57 43 58 43 59 43 - 5c 44 + 5a 43 + 5b 43 + 5c 43 + 5d 43 + 5e 43 + 5f 44 } method 'test2 (Ljava/lang/String;Ljava/lang/String;)V' { @@ -254,8 +259,6 @@ class 'pkg/TestTryFinallyExpressions' { af 79 b0 79 b1 79 - ba 84 - bb 84 bf 81 c0 81 c1 81 @@ -266,6 +269,9 @@ class 'pkg/TestTryFinallyExpressions' { ca 84 cb 84 cc 84 + cd 84 + ce 84 + cf 85 } } @@ -273,15 +279,15 @@ Lines mapping: 7 <-> 16 8 <-> 11 10 <-> 13 -11 <-> 16 +12 <-> 17 15 <-> 20 -16 <-> 45 +16 <-> 44 17 <-> 27 19 <-> 32 -20 <-> 33 +20 <-> 32 21 <-> 39 23 <-> 41 -24 <-> 44 +25 <-> 45 28 <-> 48 29 <-> 85 30 <-> 55 @@ -299,9 +305,9 @@ Lines mapping: 46 <-> 71 47 <-> 80 49 <-> 82 -50 <-> 85 +51 <-> 86 Not mapped: -12 -25 -51 +11 +24 +50 53 diff --git a/plugins/kotlin/testData/results/pkg/TestTryLoopSimpleFinally.dec b/plugins/kotlin/testData/results/pkg/TestTryLoopSimpleFinally.dec index b529acbc4c..567dc02eac 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryLoopSimpleFinally.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryLoopSimpleFinally.dec @@ -37,7 +37,7 @@ public class TestTryLoopSimpleFinally { } finally { System.out.println("Finally")// 39 } - }// 40 + }// 41 } class 'pkg/TestTryLoopSimpleFinally' { @@ -95,7 +95,6 @@ class 'pkg/TestTryLoopSimpleFinally' { 36 34 37 34 39 34 - 46 39 4b 37 4c 37 4d 37 @@ -104,6 +103,7 @@ class 'pkg/TestTryLoopSimpleFinally' { 51 37 52 37 53 37 + 57 39 } } @@ -122,9 +122,9 @@ Lines mapping: 33 <-> 32 36 <-> 35 39 <-> 38 -40 <-> 40 +41 <-> 40 Not mapped: 13 21 27 -41 +40 diff --git a/plugins/kotlin/testData/results/pkg/TestTryReturn.dec b/plugins/kotlin/testData/results/pkg/TestTryReturn.dec index d73ae2f28b..ace9a9835e 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryReturn.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryReturn.dec @@ -15,8 +15,8 @@ public class TestTryReturn { public fun testFinally(supplier: Supplier): Boolean { try { - val var10000: Any = supplier.get()// 17 - return var10000 as java.lang.Boolean + val var10000: Any = supplier.get() + return var10000 as java.lang.Boolean// 17 } finally { System.out.println("Finally")// 19 } @@ -33,8 +33,8 @@ public class TestTryReturn { System.out.println("Finally")// 31 } - System.out.println("suc")// 32 34 - } + System.out.println("suc")// 34 + }// 35 public fun testFinally2(supplier: Supplier): Boolean { var var6: Boolean @@ -44,7 +44,7 @@ public class TestTryReturn { System.out.println("Finally")// 42 } - return var6// 43 45 + return var6// 45 } public fun testFinally3(b: Boolean, c: Boolean, a: Int, supplier: Supplier): Boolean { @@ -53,8 +53,8 @@ public class TestTryReturn { if (a > 0) {// 54 return a == 1// 55 } else { - val var10000: Any = supplier.get()// 58 - return var10000 as java.lang.Boolean + val var10000: Any = supplier.get() + return var10000 as java.lang.Boolean// 58 } } else { return c && supplier.get() as java.lang.Boolean// 51 @@ -72,7 +72,7 @@ public class TestTryReturn { System.out.println("Finally")// 69 } - return var6// 70 72 + return var6// 72 } public fun testFinally5(supplier: Supplier): Boolean { @@ -170,7 +170,7 @@ public class TestTryReturn { public fun testVarWrong() { try { System.out.println("Hi")// 175 - return// 185 + return// 186 } catch (var6: Exception) {// 176 if (var6 == null) {// 177 System.out.println(var6)// 180 @@ -195,7 +195,7 @@ public class TestTryReturn { try { System.out.println(var4)// 196 - return// 206 + return// 207 } catch (var14: Exception) {// 197 } finally { System.out.println(var13)// 201 @@ -219,8 +219,8 @@ public class TestTryReturn { return// 214 } - System.out.println("post")// 217 219 - } + System.out.println("post")// 219 + }// 220 } class 'pkg/TestTryReturn' { @@ -259,7 +259,7 @@ class 'pkg/TestTryReturn' { 16 18 17 18 18 18 - 19 18 + 24 18 26 20 27 20 28 20 @@ -295,8 +295,6 @@ class 'pkg/TestTryReturn' { 1d 28 1e 28 29 29 - 33 35 - 34 35 37 32 38 32 39 32 @@ -308,9 +306,12 @@ class 'pkg/TestTryReturn' { 42 35 43 35 44 35 - 47 35 + 45 35 + 46 35 48 35 49 35 + 4a 35 + 4b 36 } method 'testFinally2 (Ljava/util/function/Supplier;)Z' { @@ -327,7 +328,6 @@ class 'pkg/TestTryReturn' { 13 41 14 41 15 41 - 1f 46 23 43 24 43 25 43 @@ -337,6 +337,7 @@ class 'pkg/TestTryReturn' { 2a 43 2b 43 2e 46 + 2f 46 } method 'testFinally3 (ZZILjava/util/function/Supplier;)Z' { @@ -364,7 +365,7 @@ class 'pkg/TestTryReturn' { 1d 59 1e 59 1f 59 - 25 59 + 32 59 33 52 34 52 35 52 @@ -374,7 +375,7 @@ class 'pkg/TestTryReturn' { 39 53 3a 53 3b 53 - 41 53 + 4e 53 4f 55 50 55 51 55 @@ -388,7 +389,7 @@ class 'pkg/TestTryReturn' { 5f 56 60 56 61 56 - 62 56 + 6f 56 72 62 73 62 74 62 @@ -413,7 +414,6 @@ class 'pkg/TestTryReturn' { 13 69 14 69 15 69 - 1f 74 23 71 24 71 25 71 @@ -423,6 +423,7 @@ class 'pkg/TestTryReturn' { 2a 71 2b 71 2e 74 + 2f 74 } method 'testFinally5 (Ljava/util/function/Supplier;)Z' { @@ -636,7 +637,6 @@ class 'pkg/TestTryReturn' { 9 171 a 171 b 171 - f 172 12 173 13 174 14 174 @@ -654,6 +654,7 @@ class 'pkg/TestTryReturn' { 30 179 31 179 32 179 + 35 172 } method 'testInvalidUse ()V' { @@ -686,7 +687,6 @@ class 'pkg/TestTryReturn' { 41 200 42 200 43 200 - 4e 197 52 203 53 203 54 203 @@ -694,6 +694,7 @@ class 'pkg/TestTryReturn' { 56 203 57 203 58 203 + 5b 197 } method 'returnInCatch ()V' { @@ -705,8 +706,6 @@ class 'pkg/TestTryReturn' { 7 210 8 210 9 210 - 13 221 - 14 221 16 212 17 213 18 213 @@ -728,9 +727,12 @@ class 'pkg/TestTryReturn' { 37 221 38 221 39 221 - 3c 221 + 3a 221 + 3b 221 3d 221 3e 221 + 3f 221 + 40 222 } } @@ -738,27 +740,25 @@ Lines mapping: 9 <-> 9 10 <-> 11 11 <-> 12 -17 <-> 18 +17 <-> 19 19 <-> 21 24 <-> 26 27 <-> 29 28 <-> 30 31 <-> 33 -32 <-> 36 34 <-> 36 +35 <-> 37 40 <-> 42 42 <-> 44 -43 <-> 47 45 <-> 47 50 <-> 52 51 <-> 60 54 <-> 53 55 <-> 54 -58 <-> 56 +58 <-> 57 60 <-> 63 67 <-> 70 69 <-> 72 -70 <-> 75 72 <-> 75 78 <-> 81 79 <-> 82 @@ -800,7 +800,7 @@ Lines mapping: 180 <-> 176 181 <-> 177 184 <-> 180 -185 <-> 173 +186 <-> 173 189 <-> 185 190 <-> 204 192 <-> 190 @@ -811,24 +811,26 @@ Lines mapping: 198 <-> 206 201 <-> 201 205 <-> 204 -206 <-> 198 +207 <-> 198 211 <-> 211 212 <-> 213 213 <-> 214 214 <-> 219 216 <-> 216 -217 <-> 222 219 <-> 222 +220 <-> 223 Not mapped: 8 16 26 -35 +32 38 39 +43 49 65 66 +70 76 77 84 @@ -852,10 +854,10 @@ Not mapped: 164 173 174 -186 +185 191 195 202 -207 +206 210 -220 +217 diff --git a/plugins/kotlin/testData/results/pkg/TestTrySplit.dec b/plugins/kotlin/testData/results/pkg/TestTrySplit.dec index 11ebe622e8..f501f25999 100644 --- a/plugins/kotlin/testData/results/pkg/TestTrySplit.dec +++ b/plugins/kotlin/testData/results/pkg/TestTrySplit.dec @@ -4,7 +4,7 @@ public class TestTrySplit { public fun test() { try { Any() - return// 17 + return// 18 } catch (var5: ArithmeticException) {// 8 Companion.throwMyException(var5.getMessage())// 13 } finally { @@ -44,7 +44,6 @@ public class TestTrySplit { class 'pkg/TestTrySplit' { method 'test ()V' { - 14 6 17 7 19 8 1a 8 @@ -65,6 +64,7 @@ class 'pkg/TestTrySplit' { 35 10 36 10 37 10 + 3a 6 } method 'testFlat ()V' { @@ -130,7 +130,7 @@ Lines mapping: 13 <-> 9 14 <-> 13 16 <-> 11 -17 <-> 7 +18 <-> 7 22 <-> 16 27 <-> 23 32 <-> 24 @@ -147,7 +147,7 @@ Not mapped: 6 7 9 -18 +17 21 23 24 diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index 2409184cb3..fa11313f6a 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -215,7 +215,7 @@ public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, Stru for (int i = 0; i < seq.length(); i++) { Instruction instr = seq.getInstr(i); - Integer bytecode_offset = block.getOldOffset(i); + int bytecode_offset = instr.startOffset; BitSet bytecode_offsets = null; if (bytecode_offset >= 0) { bytecode_offsets = new BitSet(); diff --git a/testData/results/JsHurt.dec b/testData/results/JsHurt.dec index 817cb39df0..e7a7ddd675 100644 --- a/testData/results/JsHurt.dec +++ b/testData/results/JsHurt.dec @@ -17,12 +17,12 @@ class 'JsHurt' { method 'main ([Ljava/lang/String;)V' { 0 2 1 2 - 5 10 6 10 7 10 8 10 9 10 a 10 + b 10 c 5 d 5 e 5 diff --git a/testData/results/TestEclipseSwitchString.dec b/testData/results/TestEclipseSwitchString.dec index 5580b36c69..87d8ca19f7 100644 --- a/testData/results/TestEclipseSwitchString.dec +++ b/testData/results/TestEclipseSwitchString.dec @@ -10,7 +10,7 @@ public class TestEclipseSwitchString { } System.out.println("Test");// 7 - return 0;// 8 15 + return 0;// 15 } public int test1(String var1) { @@ -23,7 +23,7 @@ public class TestEclipseSwitchString { } System.out.println("Test");// 21 - return 0;// 22 30 + return 0;// 30 } public int test2(String var1) { @@ -47,7 +47,7 @@ public class TestEclipseSwitchString { } System.out.println("Test");// 36 - return 0;// 37 45 + return 0;// 45 } public int testHashcodeCollision(String var1) { @@ -58,7 +58,7 @@ public class TestEclipseSwitchString { return 2;// 56 default: System.out.println("Test");// 51 - return 0;// 52 58 + return 0;// 58 } } @@ -70,7 +70,7 @@ public class TestEclipseSwitchString { } System.out.println("Test");// 64 - return 0;// 65 70 + return 0;// 70 } public int testHashcodeCollision2(String var1) { @@ -91,7 +91,7 @@ public class TestEclipseSwitchString { } System.out.println("Test");// 76 - return 0;// 77 83 + return 0;// 83 } } @@ -136,12 +136,12 @@ class 'pkg/TestEclipseSwitchString' { 3a 11 3b 11 3c 11 - 3d 12 40 6 41 6 42 8 43 8 44 12 + 45 12 } method 'test1 (Ljava/lang/String;)I' { @@ -194,12 +194,12 @@ class 'pkg/TestEclipseSwitchString' { 4e 24 4f 24 50 24 - 51 25 54 18 55 18 56 21 57 21 58 25 + 59 25 } method 'test2 (Ljava/lang/String;)I' { @@ -277,7 +277,6 @@ class 'pkg/TestEclipseSwitchString' { 4e 48 4f 48 50 48 - 51 49 54 33 55 33 56 33 @@ -289,6 +288,7 @@ class 'pkg/TestEclipseSwitchString' { 5c 34 5d 34 5e 49 + 5f 49 } method 'testHashcodeCollision (Ljava/lang/String;)I' { @@ -323,12 +323,12 @@ class 'pkg/TestEclipseSwitchString' { 2f 59 30 59 31 59 - 32 60 35 55 36 55 37 57 38 57 39 60 + 3a 60 } method 'testHashcodeCollision1 (Ljava/lang/String;)I' { @@ -363,10 +363,10 @@ class 'pkg/TestEclipseSwitchString' { 2f 71 30 71 31 71 - 32 72 35 68 36 68 37 72 + 38 72 } method 'testHashcodeCollision2 (Ljava/lang/String;)I' { @@ -419,7 +419,6 @@ class 'pkg/TestEclipseSwitchString' { 2f 92 30 92 31 92 - 32 93 35 85 36 85 37 85 @@ -431,42 +430,44 @@ class 'pkg/TestEclipseSwitchString' { 3d 88 3e 88 3f 93 + 40 93 } } Lines mapping: 5 <-> 5 7 <-> 12 -8 <-> 13 10 <-> 7 12 <-> 9 15 <-> 13 19 <-> 17 21 <-> 25 -22 <-> 26 24 <-> 19 27 <-> 22 30 <-> 26 34 <-> 30 36 <-> 49 -37 <-> 50 39 <-> 34 42 <-> 35 45 <-> 50 49 <-> 54 51 <-> 60 -52 <-> 61 54 <-> 56 56 <-> 58 58 <-> 61 62 <-> 66 64 <-> 72 -65 <-> 73 68 <-> 69 70 <-> 73 74 <-> 77 76 <-> 93 -77 <-> 94 79 <-> 86 81 <-> 89 -83 <-> 94 \ No newline at end of file +83 <-> 94 +Not mapped: +8 +22 +37 +52 +65 +77 diff --git a/testData/results/TestHotjava.dec b/testData/results/TestHotjava.dec index 1b7bdef6c9..d42498dc8a 100644 --- a/testData/results/TestHotjava.dec +++ b/testData/results/TestHotjava.dec @@ -56,14 +56,15 @@ class 'TestHotjava' { 5 7 6 7 7 7 - d 9 - e 9 - f 9 - 12 9 + b 11 13 9 14 9 15 9 - 18 11 + 16 9 + 17 9 + 18 9 + 19 9 + 1a 9 } method 'testMonitor1 ()V' { @@ -108,14 +109,14 @@ class 'TestHotjava' { 9 28 a 28 b 28 - 13 30 - 14 30 - 15 30 - 18 30 - 19 30 1a 30 1b 30 1c 30 + 1d 30 + 1e 30 + 1f 30 + 20 30 + 21 30 26 33 } } @@ -133,4 +134,4 @@ Lines mapping: 27 <-> 27 28 <-> 29 29 <-> 29 -31 <-> 31 \ No newline at end of file +31 <-> 31 diff --git a/testData/results/TestJava1Synchronized.dec b/testData/results/TestJava1Synchronized.dec index 918ff71ef7..c1e3c94a4b 100644 --- a/testData/results/TestJava1Synchronized.dec +++ b/testData/results/TestJava1Synchronized.dec @@ -3,14 +3,14 @@ public class TestJava1Synchronized { synchronized (this) {// 3 if (var1 == 0) {// 4 System.out.println("0");// 5 - return; + return;// 6 } System.out.println("1");// 9 } System.out.println("2");// 12 - } + }// 2 public void test2(int var1) { synchronized (this) {// 16 @@ -58,6 +58,7 @@ class 'TestJava1Synchronized' { d 4 e 4 f 4 + 13 5 14 8 15 8 16 8 @@ -66,15 +67,15 @@ class 'TestJava1Synchronized' { 19 8 1a 8 1b 8 - 1e 11 - 1f 11 - 20 11 - 26 5 29 11 2a 11 + 2b 11 2c 11 2d 11 2e 11 + 2f 11 + 30 11 + 31 12 } method 'test2 (I)V' { @@ -116,14 +117,15 @@ class 'TestJava1Synchronized' { 9 25 a 25 b 25 - 19 28 - 1a 28 - 1b 28 - 1e 28 + 17 30 1f 28 20 28 21 28 - 24 30 + 22 28 + 23 28 + 24 28 + 25 28 + 26 28 } method 'test4 ()V' { @@ -135,9 +137,10 @@ class 'TestJava1Synchronized' { 5 34 6 34 7 34 - d 36 + b 40 13 36 - 14 36 + 15 36 + 16 36 17 37 18 37 19 37 @@ -147,14 +150,15 @@ class 'TestJava1Synchronized' { 1d 37 1e 37 20 38 - 21 40 } } Lines mapping: +2 <-> 13 3 <-> 3 4 <-> 4 5 <-> 5 +6 <-> 6 9 <-> 9 12 <-> 12 16 <-> 16 @@ -168,6 +172,3 @@ Lines mapping: 35 <-> 35 37 <-> 37 38 <-> 38 -Not mapped: -2 -6 \ No newline at end of file diff --git a/testData/results/TestJsr.dec b/testData/results/TestJsr.dec index 671f9fd4f3..dffa511ce6 100644 --- a/testData/results/TestJsr.dec +++ b/testData/results/TestJsr.dec @@ -18,14 +18,15 @@ class 'TestJsr' { 5 3 6 3 7 3 - d 5 - e 5 - f 5 - 12 5 + b 7 13 5 14 5 15 5 - 18 7 + 16 5 + 17 5 + 18 5 + 19 5 + 1a 5 } } diff --git a/testData/results/pkg/TestCaseClasses.dec b/testData/results/pkg/TestCaseClasses.dec index 101e0ef018..dd584c2f82 100644 --- a/testData/results/pkg/TestCaseClasses.dec +++ b/testData/results/pkg/TestCaseClasses.dec @@ -251,9 +251,6 @@ class 'pkg/Option1' { 8 57 9 57 a 57 - b 57 - c 57 - d 57 12 59 13 59 14 59 @@ -263,6 +260,9 @@ class 'pkg/Option1' { 18 59 1c 59 1d 57 + 1e 57 + 1f 57 + 20 57 } method 'productElementName (I)Ljava/lang/String;' { diff --git a/testData/results/pkg/TestComplexIfElseChain.dec b/testData/results/pkg/TestComplexIfElseChain.dec index 05b8b0b8d3..1db27ffec0 100644 --- a/testData/results/pkg/TestComplexIfElseChain.dec +++ b/testData/results/pkg/TestComplexIfElseChain.dec @@ -52,7 +52,7 @@ public class TestComplexIfElseChain { } else if (result != 6 && result != 7) {// 52 if (result == 8 || result == 9) {// 54 System.out.println("e");// 55 - return;// 56 + return;// 59 } } else { System.out.println("d");// 53 @@ -614,7 +614,7 @@ class 'pkg/TestComplexIfElseChain' { 75 53 76 53 77 53 - 78 54 + 7e 54 } method 'testInLoop2 ()V' { @@ -1757,7 +1757,7 @@ Lines mapping: 53 <-> 58 54 <-> 53 55 <-> 54 -56 <-> 55 +59 <-> 55 62 <-> 64 65 <-> 67 67 <-> 68 @@ -1898,8 +1898,8 @@ Lines mapping: 277 <-> 286 281 <-> 290 Not mapped: +56 58 -59 81 95 97 diff --git a/testData/results/pkg/TestFinallyBlockVariableUse.dec b/testData/results/pkg/TestFinallyBlockVariableUse.dec index 214044aef1..1a89617287 100644 --- a/testData/results/pkg/TestFinallyBlockVariableUse.dec +++ b/testData/results/pkg/TestFinallyBlockVariableUse.dec @@ -53,7 +53,7 @@ class 'pkg/TestFinallyBlockVariableUse' { 13 10 14 10 15 10 - 18 10 + 48 10 49 11 4b 12 4c 12 diff --git a/testData/results/pkg/TestFinallyVarDef.dec b/testData/results/pkg/TestFinallyVarDef.dec index 97f7e3d928..0cb5abd2ef 100644 --- a/testData/results/pkg/TestFinallyVarDef.dec +++ b/testData/results/pkg/TestFinallyVarDef.dec @@ -9,8 +9,8 @@ public class TestFinallyVarDef { } byte var5; - System.out.println(var5);// 10 12 - } + System.out.println(var5);// 12 + }// 13 public void test2() { int i = 2;// 16 @@ -21,8 +21,8 @@ public class TestFinallyVarDef { int var5 = 5;// 20 } - System.out.println(i);// 21 23 - } + System.out.println(i);// 23 + }// 24 } class 'pkg/TestFinallyVarDef' { @@ -35,15 +35,16 @@ class 'pkg/TestFinallyVarDef' { 5 5 6 5 7 5 - a 11 - b 11 - c 11 e 7 f 7 12 11 + 13 11 + 14 11 15 11 16 11 17 11 + 18 11 + 19 12 } method 'test2 ()V' { @@ -57,28 +58,29 @@ class 'pkg/TestFinallyVarDef' { 7 18 8 18 9 18 - c 23 - d 23 - e 23 10 20 11 20 14 23 + 15 23 + 16 23 17 23 18 23 19 23 + 1a 23 + 1b 24 } } Lines mapping: 7 <-> 6 9 <-> 8 -10 <-> 12 12 <-> 12 +13 <-> 13 16 <-> 16 18 <-> 19 20 <-> 21 -21 <-> 24 23 <-> 24 +24 <-> 25 Not mapped: -13 -24 \ No newline at end of file +10 +21 diff --git a/testData/results/pkg/TestIrreducible.dec b/testData/results/pkg/TestIrreducible.dec index e95957de17..0a53b39ff1 100644 --- a/testData/results/pkg/TestIrreducible.dec +++ b/testData/results/pkg/TestIrreducible.dec @@ -6,19 +6,19 @@ public final class TestIrreducible { // $VF: Irreducible bytecode was duplicated to produce valid code public static void test() { if (field == 1) {// 24 25 26 - System.out.println("2"); + System.out.println("2");// 44 45 46 } else { System.out.println("x is not 1");// 29 30 31 if (field != 0) {// 32 33 System.out.println("x is not 0");// 36 37 38 - System.out.println("1"); - System.out.println("2");// 44 45 46 + System.out.println("1");// 40 41 42 + System.out.println("2"); } } while (true) { System.out.println("3");// 48 49 50 - System.out.println("1");// 40 41 42 + System.out.println("1"); System.out.println("2"); } } @@ -55,22 +55,22 @@ class 'pkg/TestIrreducible' { 20 12 21 12 22 12 - 23 20 - 24 20 - 25 20 - 26 20 - 27 20 - 28 20 - 29 20 - 2a 20 - 2b 14 - 2c 14 - 2d 14 - 2e 14 - 2f 14 - 30 14 - 31 14 - 32 14 + 23 13 + 24 13 + 25 13 + 26 13 + 27 13 + 28 13 + 29 13 + 2a 13 + 2b 8 + 2c 8 + 2d 8 + 2e 8 + 2f 8 + 30 8 + 31 8 + 32 8 33 19 34 19 35 19 @@ -94,12 +94,12 @@ Lines mapping: 36 <-> 13 37 <-> 13 38 <-> 13 -40 <-> 21 -41 <-> 21 -42 <-> 21 -44 <-> 15 -45 <-> 15 -46 <-> 15 +40 <-> 14 +41 <-> 14 +42 <-> 14 +44 <-> 9 +45 <-> 9 +46 <-> 9 48 <-> 20 49 <-> 20 50 <-> 20 diff --git a/testData/results/pkg/TestLoopFinally.dec b/testData/results/pkg/TestLoopFinally.dec index ed18d4ae1d..c025c78894 100644 --- a/testData/results/pkg/TestLoopFinally.dec +++ b/testData/results/pkg/TestLoopFinally.dec @@ -6,7 +6,7 @@ import java.util.Scanner; public class TestLoopFinally { public void test() { - for (int i = 0; i < 10; i++) {// 9 20 + for (int i = 0; i < 10; i++) {// 9 try { System.out.println(i);// 11 } finally { @@ -310,9 +310,6 @@ class 'pkg/TestLoopFinally' { c 10 d 10 e 10 - 27 8 - 28 8 - 29 8 2b 12 2c 12 2d 12 @@ -334,6 +331,9 @@ class 'pkg/TestLoopFinally' { 40 17 41 17 42 17 + 45 8 + 46 8 + 47 8 4b 21 4c 21 4d 21 @@ -469,7 +469,7 @@ class 'pkg/TestLoopFinally' { 3 66 4 66 5 67 - 6 67 + 10 67 11 70 12 70 13 70 @@ -485,7 +485,7 @@ class 'pkg/TestLoopFinally' { 1d 71 1e 71 1f 72 - 20 72 + 2a 72 2b 75 2c 75 2d 75 @@ -501,7 +501,7 @@ class 'pkg/TestLoopFinally' { 37 76 38 76 39 77 - 3a 77 + 44 77 4e 80 4f 80 50 80 @@ -532,7 +532,7 @@ class 'pkg/TestLoopFinally' { 4 93 5 93 6 94 - 7 94 + 11 94 1b 97 1c 97 1d 97 @@ -872,7 +872,6 @@ Lines mapping: 13 <-> 13 15 <-> 14 19 <-> 18 -20 <-> 9 23 <-> 22 24 <-> 23 27 <-> 26 @@ -973,6 +972,7 @@ Lines mapping: 289 <-> 293 Not mapped: 16 +20 42 56 85 diff --git a/testData/results/pkg/TestNamedSuspendFun2Kt.dec b/testData/results/pkg/TestNamedSuspendFun2Kt.dec index 398a9d062c..9b9cb73e64 100644 --- a/testData/results/pkg/TestNamedSuspendFun2Kt.dec +++ b/testData/results/pkg/TestNamedSuspendFun2Kt.dec @@ -134,8 +134,8 @@ public final class TestNamedSuspendFun2Kt { } try { - int var22 = ((Number)var23).intValue(); - if (var22 == 0) { + int x = ((Number)var23).intValue(); + if (x == 0) { break; } } catch (Throwable var20) { @@ -334,7 +334,6 @@ class 'pkg/TestNamedSuspendFun2Kt' { 98 103 99 103 9a 103 - 9d 104 a0 98 a1 97 a2 97 @@ -356,25 +355,25 @@ class 'pkg/TestNamedSuspendFun2Kt' { b3 106 b4 106 b5 106 - bc 124 - bd 122 - be 122 - bf 122 - c0 122 - c1 122 - c2 123 - c3 123 - c4 123 - c5 123 - c6 123 - c7 124 - c8 124 - c9 124 - cb 124 - cc 124 - cd 124 - ce 124 - cf 124 + bc 75 + bd 73 + be 73 + bf 73 + c0 73 + c1 73 + c2 74 + c3 74 + c4 74 + c5 74 + c6 74 + c7 75 + c8 75 + c9 75 + cb 75 + cc 75 + cd 75 + ce 75 + cf 75 d0 76 d1 76 d2 76 @@ -395,6 +394,8 @@ class 'pkg/TestNamedSuspendFun2Kt' { e3 104 e4 104 e5 104 + e6 104 + e7 104 ec 113 ed 113 f1 113 diff --git a/testData/results/pkg/TestPatternMatchSwitchString.dec b/testData/results/pkg/TestPatternMatchSwitchString.dec index d386d93e63..920c7c2ab8 100644 --- a/testData/results/pkg/TestPatternMatchSwitchString.dec +++ b/testData/results/pkg/TestPatternMatchSwitchString.dec @@ -10,7 +10,7 @@ public class TestPatternMatchSwitchString { case "c": case "d": this.field = s;// 8 - return; + return;// 11 case null: default: throw new RuntimeException("illegal");// 9 @@ -75,10 +75,10 @@ class 'pkg/TestPatternMatchSwitchString' { 2e 11 2f 11 30 11 - 31 12 38 15 39 15 3d 15 + 3e 12 } method 'test1 (Ljava/lang/String;)V' { @@ -149,10 +149,9 @@ Lines mapping: 7 <-> 7 8 <-> 12 9 <-> 16 +11 <-> 13 14 <-> 21 15 <-> 24 16 <-> 28 17 <-> 32 19 <-> 34 -Not mapped: -11 \ No newline at end of file diff --git a/testData/results/pkg/TestPatternMatching.dec b/testData/results/pkg/TestPatternMatching.dec index ab68ad6ec2..0a656b6cf7 100644 --- a/testData/results/pkg/TestPatternMatching.dec +++ b/testData/results/pkg/TestPatternMatching.dec @@ -41,14 +41,14 @@ public class TestPatternMatching { strx; System.out.println(strx.hashCode());// 41 - } + }// 42 public void testInvertedLoopUnused(Object obj) { while (!(obj instanceof String str)) {// 45 System.out.println("Oh no");// 46 obj = obj.toString();// 47 } - } + }// 49 public void testCompoundLoop(Object obj) { while (obj instanceof String str && str.contains("hi")) {// 52 @@ -224,9 +224,6 @@ class 'pkg/TestPatternMatching' { 7 36 8 36 d 36 - e 42 - f 42 - 10 42 11 37 12 37 13 37 @@ -241,11 +238,16 @@ class 'pkg/TestPatternMatching' { 1c 38 1d 38 21 42 + 22 42 + 23 42 24 42 25 42 26 42 27 42 - 28 43 + 28 42 + 29 42 + 2a 42 + 2b 43 } method 'testInvertedLoopUnused (Ljava/lang/Object;)V' { @@ -257,7 +259,6 @@ class 'pkg/TestPatternMatching' { 7 46 8 46 d 46 - e 50 11 47 12 47 13 47 @@ -271,6 +272,7 @@ class 'pkg/TestPatternMatching' { 1b 48 1c 48 1d 48 + 21 50 } method 'testCompoundLoop (Ljava/lang/Object;)V' { @@ -513,9 +515,11 @@ Lines mapping: 38 <-> 38 39 <-> 39 41 <-> 43 +42 <-> 44 45 <-> 47 46 <-> 48 47 <-> 49 +49 <-> 51 52 <-> 54 53 <-> 55 55 <-> 57 @@ -544,6 +548,3 @@ Lines mapping: 100 <-> 95 101 <-> 96 103 <-> 98 -Not mapped: -42 -49 diff --git a/testData/results/pkg/TestPatternMatching17.dec b/testData/results/pkg/TestPatternMatching17.dec index 1e0756c51e..3cab84c1c4 100644 --- a/testData/results/pkg/TestPatternMatching17.dec +++ b/testData/results/pkg/TestPatternMatching17.dec @@ -47,7 +47,7 @@ public class TestPatternMatching17 { String str = (String)obj; System.out.println(str.hashCode());// 41 - } + }// 42 public void testInvertedLoopUnused(Object obj) { while (!(obj instanceof String)) {// 45 @@ -56,7 +56,7 @@ public class TestPatternMatching17 { } String str = (String)obj; - } + }// 49 public void testCompoundLoop(Object obj) { while (obj instanceof String str && str.contains("hi")) {// 52 @@ -323,9 +323,6 @@ class 'pkg/TestPatternMatching17' { 9 47 a 47 b 47 - c 48 - d 48 - e 48 f 43 10 43 11 43 @@ -340,11 +337,16 @@ class 'pkg/TestPatternMatching17' { 1a 44 1b 44 1f 48 + 20 48 + 21 48 22 48 23 48 24 48 25 48 - 26 49 + 26 48 + 27 48 + 28 48 + 29 49 } method 'testInvertedLoopUnused (Ljava/lang/Object;)V' { @@ -360,7 +362,6 @@ class 'pkg/TestPatternMatching17' { 9 57 a 57 b 57 - c 58 f 53 10 53 11 53 @@ -374,6 +375,7 @@ class 'pkg/TestPatternMatching17' { 19 54 1a 54 1b 54 + 1f 58 } method 'testCompoundLoop (Ljava/lang/Object;)V' { @@ -920,9 +922,11 @@ Lines mapping: 38 <-> 44 39 <-> 45 41 <-> 49 +42 <-> 50 45 <-> 53 46 <-> 54 47 <-> 55 +49 <-> 59 52 <-> 62 53 <-> 63 55 <-> 65 @@ -996,6 +1000,3 @@ Lines mapping: 183 <-> 181 184 <-> 182 187 <-> 185 -Not mapped: -42 -49 diff --git a/testData/results/pkg/TestPatternMatching17Fake.dec b/testData/results/pkg/TestPatternMatching17Fake.dec index d7d14fcd8b..3ffe14a70b 100644 --- a/testData/results/pkg/TestPatternMatching17Fake.dec +++ b/testData/results/pkg/TestPatternMatching17Fake.dec @@ -205,9 +205,6 @@ class 'pkg/TestPatternMatching17Fake' { 5 36 6 36 b 36 - c 37 - d 37 - e 37 f 39 10 39 11 40 @@ -218,10 +215,15 @@ class 'pkg/TestPatternMatching17Fake' { 16 40 17 40 1b 37 + 1c 37 + 1d 37 1e 37 1f 37 20 37 21 37 + 22 37 + 23 37 + 24 37 25 42 } diff --git a/testData/results/pkg/TestPatternMatching17FakeLoopsInverted.dec b/testData/results/pkg/TestPatternMatching17FakeLoopsInverted.dec index 736fd23056..c7639009ee 100644 --- a/testData/results/pkg/TestPatternMatching17FakeLoopsInverted.dec +++ b/testData/results/pkg/TestPatternMatching17FakeLoopsInverted.dec @@ -15,7 +15,7 @@ public class TestPatternMatching17FakeLoopsInverted { } String x = (String)o; - } + }// 16 void test3(Object o) { while (o.hashCode() >= 0 && !(o instanceof String)) {// 19 @@ -140,9 +140,9 @@ public class TestPatternMatching17FakeLoopsInverted { } String x = (String)o; - String var4 = (String)o;// 134 - System.out.println(var4.hashCode() + var4.length());// 135 - } + String u = (String)o;// 134 + System.out.println(u.hashCode() + u.length());// 135 + }// 136 void test3A(Object o) { while (o.hashCode() >= 0 && !(o instanceof String)) {// 139 @@ -256,7 +256,6 @@ class 'pkg/TestPatternMatching17FakeLoopsInverted' { 9 16 a 16 b 16 - c 17 f 12 10 12 11 12 @@ -269,6 +268,7 @@ class 'pkg/TestPatternMatching17FakeLoopsInverted' { 18 13 19 13 1a 13 + 1e 17 } method 'test3 (Ljava/lang/Object;)V' { @@ -800,7 +800,6 @@ class 'pkg/TestPatternMatching17FakeLoopsInverted' { 9 141 a 141 b 141 - c 142 f 137 10 137 11 137 @@ -816,18 +815,24 @@ class 'pkg/TestPatternMatching17FakeLoopsInverted' { 1e 142 1f 142 20 142 - 22 143 + 21 142 + 22 142 23 143 24 143 + 25 143 26 143 27 143 28 143 + 29 143 2a 143 2b 143 2c 143 + 2d 143 2e 143 2f 143 30 143 + 31 143 + 32 144 } method 'test3A (Ljava/lang/Object;)V' { @@ -1196,6 +1201,7 @@ Lines mapping: 12 <-> 12 13 <-> 13 14 <-> 14 +16 <-> 18 19 <-> 21 20 <-> 22 21 <-> 23 @@ -1266,6 +1272,7 @@ Lines mapping: 132 <-> 139 134 <-> 143 135 <-> 144 +136 <-> 145 139 <-> 148 140 <-> 149 141 <-> 150 @@ -1311,7 +1318,6 @@ Lines mapping: Not mapped: 8 15 -16 22 29 38 @@ -1326,10 +1332,9 @@ Not mapped: 106 124 133 -136 142 152 162 172 183 -193 \ No newline at end of file +193 diff --git a/testData/results/pkg/TestPatternMatching17FakeNew.dec b/testData/results/pkg/TestPatternMatching17FakeNew.dec index 5af13ae78f..71f776ef94 100644 --- a/testData/results/pkg/TestPatternMatching17FakeNew.dec +++ b/testData/results/pkg/TestPatternMatching17FakeNew.dec @@ -623,9 +623,6 @@ class 'pkg/TestPatternMatching17FakeNew' { 5 113 6 113 b 113 - c 114 - d 114 - e 114 f 116 10 116 11 117 @@ -636,10 +633,15 @@ class 'pkg/TestPatternMatching17FakeNew' { 16 117 17 117 1b 114 + 1c 114 + 1d 114 1e 114 1f 114 20 114 21 114 + 22 114 + 23 114 + 24 114 25 119 } diff --git a/testData/results/pkg/TestPatternMatchingFake.dec b/testData/results/pkg/TestPatternMatchingFake.dec index b0ecc1adce..78917c3736 100644 --- a/testData/results/pkg/TestPatternMatchingFake.dec +++ b/testData/results/pkg/TestPatternMatchingFake.dec @@ -205,9 +205,6 @@ class 'pkg/TestPatternMatchingFake' { 7 36 8 36 d 36 - e 37 - f 37 - 10 37 11 39 12 39 13 40 @@ -218,10 +215,15 @@ class 'pkg/TestPatternMatchingFake' { 18 40 19 40 1d 37 + 1e 37 + 1f 37 20 37 21 37 22 37 23 37 + 24 37 + 25 37 + 26 37 27 42 } diff --git a/testData/results/pkg/TestPatternMatchingFakeLoopsInverted.dec b/testData/results/pkg/TestPatternMatchingFakeLoopsInverted.dec index cde37bc8c9..edf8d52eac 100644 --- a/testData/results/pkg/TestPatternMatchingFakeLoopsInverted.dec +++ b/testData/results/pkg/TestPatternMatchingFakeLoopsInverted.dec @@ -13,7 +13,7 @@ public class TestPatternMatchingFakeLoopsInverted { String s = (String)o;// 13 System.out.println(s);// 14 } - } + }// 16 void test3(Object o) { while (o.hashCode() >= 0 && !(o instanceof String)) {// 19 @@ -137,9 +137,9 @@ public class TestPatternMatchingFakeLoopsInverted { System.out.println(s);// 132 } - String var5 = (String)o;// 134 - System.out.println(var5.hashCode() + var5.length());// 135 - } + String u = (String)o;// 134 + System.out.println(u.hashCode() + u.length());// 135 + }// 136 void test3A(Object o) { while (o.hashCode() >= 0 && !(o instanceof String)) {// 139 @@ -249,7 +249,6 @@ class 'pkg/TestPatternMatchingFakeLoopsInverted' { 7 11 8 11 d 11 - e 15 11 12 12 12 13 12 @@ -262,6 +261,7 @@ class 'pkg/TestPatternMatchingFakeLoopsInverted' { 1a 13 1b 13 1c 13 + 20 15 } method 'test3 (Ljava/lang/Object;)V' { @@ -789,7 +789,6 @@ class 'pkg/TestPatternMatchingFakeLoopsInverted' { 7 134 8 134 d 134 - e 139 11 135 12 135 13 135 @@ -805,18 +804,24 @@ class 'pkg/TestPatternMatchingFakeLoopsInverted' { 20 139 21 139 22 139 - 24 140 + 23 139 + 24 139 25 140 26 140 + 27 140 28 140 29 140 2a 140 + 2b 140 2c 140 2d 140 2e 140 + 2f 140 30 140 31 140 32 140 + 33 140 + 34 141 } method 'test3A (Ljava/lang/Object;)V' { @@ -1185,6 +1190,7 @@ Lines mapping: 12 <-> 12 13 <-> 13 14 <-> 14 +16 <-> 16 19 <-> 19 20 <-> 20 21 <-> 21 @@ -1255,6 +1261,7 @@ Lines mapping: 132 <-> 137 134 <-> 140 135 <-> 141 +136 <-> 142 139 <-> 145 140 <-> 146 141 <-> 147 @@ -1300,7 +1307,6 @@ Lines mapping: Not mapped: 8 15 -16 22 29 38 @@ -1315,7 +1321,6 @@ Not mapped: 106 124 133 -136 142 152 162 diff --git a/testData/results/pkg/TestPatternMatchingFakeNew.dec b/testData/results/pkg/TestPatternMatchingFakeNew.dec index 74bb4af6e6..a7c66e37a0 100644 --- a/testData/results/pkg/TestPatternMatchingFakeNew.dec +++ b/testData/results/pkg/TestPatternMatchingFakeNew.dec @@ -623,9 +623,6 @@ class 'pkg/TestPatternMatchingFakeNew' { 7 113 8 113 d 113 - e 114 - f 114 - 10 114 11 116 12 116 13 117 @@ -636,10 +633,15 @@ class 'pkg/TestPatternMatchingFakeNew' { 18 117 19 117 1d 114 + 1e 114 + 1f 114 20 114 21 114 22 114 23 114 + 24 114 + 25 114 + 26 114 27 119 } diff --git a/testData/results/pkg/TestPatternMatchingVariableScope.dec b/testData/results/pkg/TestPatternMatchingVariableScope.dec index b1952a7b26..c536cf1f24 100644 --- a/testData/results/pkg/TestPatternMatchingVariableScope.dec +++ b/testData/results/pkg/TestPatternMatchingVariableScope.dec @@ -176,9 +176,6 @@ class 'pkg/TestPatternMatchingVariableScope' { 7 31 8 31 d 31 - e 32 - f 32 - 10 32 11 34 12 34 13 34 @@ -186,9 +183,12 @@ class 'pkg/TestPatternMatchingVariableScope' { 15 34 16 34 1a 32 + 1b 32 + 1c 32 1d 32 1e 32 1f 32 + 20 32 21 37 24 37 25 37 @@ -197,14 +197,14 @@ class 'pkg/TestPatternMatchingVariableScope' { 28 37 29 37 2e 37 - 2f 40 - 30 40 - 31 40 39 38 3a 40 + 3b 40 + 3c 40 3d 40 3e 40 3f 40 + 40 40 41 42 44 42 45 42 @@ -213,9 +213,6 @@ class 'pkg/TestPatternMatchingVariableScope' { 48 42 49 42 4e 42 - 4f 47 - 50 47 - 51 47 52 43 53 43 54 43 @@ -223,9 +220,12 @@ class 'pkg/TestPatternMatchingVariableScope' { 56 43 57 43 5b 47 + 5c 47 + 5d 47 5e 47 5f 47 60 47 + 61 47 62 51 63 51 64 51 @@ -261,9 +261,6 @@ class 'pkg/TestPatternMatchingVariableScope' { 84 58 85 58 8a 58 - 8b 63 - 8c 63 - 8d 63 8e 59 8f 59 90 59 @@ -279,13 +276,19 @@ class 'pkg/TestPatternMatchingVariableScope' { 9a 60 9b 60 9f 63 + a0 63 + a1 63 a2 63 a3 63 a4 63 - a8 64 + a5 63 + a6 64 a9 64 aa 64 ab 64 + ac 64 + ad 64 + ae 64 b3 64 b4 65 b5 65 diff --git a/testData/results/pkg/TestRecordPatterns6.dec b/testData/results/pkg/TestRecordPatterns6.dec index 0bebbd9c81..95740eef53 100644 --- a/testData/results/pkg/TestRecordPatterns6.dec +++ b/testData/results/pkg/TestRecordPatterns6.dec @@ -114,8 +114,8 @@ class 'pkg/TestRecordPatterns6' { 2b 13 46 14 47 14 - 48 14 - 49 14 + 50 14 + 51 14 64 15 65 15 66 15 diff --git a/testData/results/pkg/TestRecordPatterns7.dec b/testData/results/pkg/TestRecordPatterns7.dec index debc2604a7..e154074b4f 100644 --- a/testData/results/pkg/TestRecordPatterns7.dec +++ b/testData/results/pkg/TestRecordPatterns7.dec @@ -22,7 +22,7 @@ public class TestRecordPatterns7 { default -> 0;// 13 } ); - } + }// 15 record A(TestRecordPatterns7.C c, int i, TestRecordPatterns7.B b2) { } @@ -115,24 +115,28 @@ class 'pkg/TestRecordPatterns7' { 99 15 a3 15 a4 15 - a5 15 - a6 15 - ad 16 - ae 16 - af 15 - b1 17 - b2 15 - b4 18 - b5 15 - b7 19 - b8 15 - ba 20 - bb 15 + ad 15 + ae 15 + af 16 + b0 16 + b1 15 + b2 17 + b3 17 + b4 15 + b5 18 + b6 18 + b7 15 + b8 19 + b9 19 + ba 15 + bb 20 + bc 20 + bd 15 c1 21 c5 13 c6 13 c7 13 - c8 24 + d9 24 } } @@ -143,5 +147,4 @@ Lines mapping: 11 <-> 14 12 <-> 16 13 <-> 22 -Not mapped: -15 +15 <-> 25 diff --git a/testData/results/pkg/TestRecordPatterns8.dec b/testData/results/pkg/TestRecordPatterns8.dec index 8a85290b11..e2914cac0a 100644 --- a/testData/results/pkg/TestRecordPatterns8.dec +++ b/testData/results/pkg/TestRecordPatterns8.dec @@ -318,11 +318,11 @@ class 'pkg/TestRecordPatterns8' { 28 187 29 187 2a 187 - 2b 188 3f 190 40 191 41 191 42 188 + 43 188 } method 'get (Ljava/lang/String;)Lpkg/TestRecordPatterns8$Sealed;' { @@ -348,4 +348,4 @@ Lines mapping: 102 <-> 250 Not mapped: 68 -82 \ No newline at end of file +82 diff --git a/testData/results/pkg/TestStringSwitchTypes.dec b/testData/results/pkg/TestStringSwitchTypes.dec index be95cfb2db..687d3da338 100644 --- a/testData/results/pkg/TestStringSwitchTypes.dec +++ b/testData/results/pkg/TestStringSwitchTypes.dec @@ -44,7 +44,7 @@ public class TestStringSwitchTypes { return 2;// 48 default: System.out.println("Test");// 43 - return 0;// 44 51 + return 0;// 51 } } @@ -68,7 +68,7 @@ public class TestStringSwitchTypes { return 1;// 74 default: System.out.println("Test");// 69 - return 0;// 70 77 + return 0;// 77 } } } @@ -239,12 +239,12 @@ class 'pkg/TestStringSwitchTypes' { 5d 45 5e 45 5f 45 - 60 46 63 41 64 41 65 43 66 43 67 46 + 68 46 } method 'testSplitDup (Ljava/lang/String;)I' { @@ -335,12 +335,12 @@ class 'pkg/TestStringSwitchTypes' { 5d 69 5e 69 5f 69 - 60 70 63 65 64 65 65 67 66 67 67 70 + 68 70 } } @@ -364,7 +364,6 @@ Lines mapping: 37 <-> 35 41 <-> 40 43 <-> 46 -44 <-> 47 46 <-> 42 48 <-> 44 51 <-> 47 @@ -375,7 +374,9 @@ Lines mapping: 62 <-> 59 67 <-> 64 69 <-> 70 -70 <-> 71 72 <-> 66 74 <-> 68 77 <-> 71 +Not mapped: +44 +70 diff --git a/testData/results/pkg/TestSwitchFinally.dec b/testData/results/pkg/TestSwitchFinally.dec index 668465ae88..5a661181b5 100644 --- a/testData/results/pkg/TestSwitchFinally.dec +++ b/testData/results/pkg/TestSwitchFinally.dec @@ -13,7 +13,7 @@ public class TestSwitchFinally { System.out.println("b");// 16 } - }// 17 + }// 18 public void test1(int i) { try { @@ -30,7 +30,7 @@ public class TestSwitchFinally { System.out.println("b");// 35 } - }// 36 + }// 37 public void test2(int i) { try { @@ -43,7 +43,7 @@ public class TestSwitchFinally { System.out.println("b");// 50 } } - }// 51 + }// 52 public int test3(int i) { try { @@ -56,7 +56,7 @@ public class TestSwitchFinally { break;// 64 case 1: System.out.println("1");// 66 - System.out.println("c");// 67 80 + System.out.println("c");// 80 return 0;// 81 default: System.out.println("Default");// 69 @@ -65,7 +65,7 @@ public class TestSwitchFinally { System.out.println("b");// 72 } - System.out.println("d");// 74 76 + System.out.println("d");// 76 return 1;// 77 } } @@ -79,7 +79,6 @@ class 'pkg/TestSwitchFinally' { 4 5 5 5 6 5 - 34 15 38 7 39 7 3a 7 @@ -124,6 +123,7 @@ class 'pkg/TestSwitchFinally' { 61 13 62 13 63 13 + 66 15 } method 'test1 (I)V' { @@ -134,7 +134,6 @@ class 'pkg/TestSwitchFinally' { 4 19 5 19 6 19 - 47 32 4b 21 4c 21 4d 21 @@ -197,6 +196,7 @@ class 'pkg/TestSwitchFinally' { 88 30 89 30 8a 30 + 8d 32 } method 'test2 (I)V' { @@ -207,7 +207,6 @@ class 'pkg/TestSwitchFinally' { 4 36 5 36 6 36 - 2c 45 30 38 31 38 32 38 @@ -244,6 +243,7 @@ class 'pkg/TestSwitchFinally' { 51 42 52 42 53 42 + 56 45 } method 'test3 (I)I' { @@ -254,9 +254,6 @@ class 'pkg/TestSwitchFinally' { 4 49 5 49 6 49 - 52 67 - 53 67 - 54 67 56 51 57 51 58 51 @@ -308,9 +305,6 @@ class 'pkg/TestSwitchFinally' { 88 57 89 57 8a 57 - 8b 58 - 8c 58 - 8d 58 8e 61 8f 61 90 61 @@ -329,16 +323,24 @@ class 'pkg/TestSwitchFinally' { 9d 64 a0 67 a1 67 + a2 67 a3 67 a4 67 a5 67 + a6 67 + a7 67 a8 68 + a9 68 aa 58 ab 58 + ac 58 ad 58 ae 58 af 58 + b0 58 + b1 58 b2 59 + b3 59 } } @@ -348,7 +350,7 @@ Lines mapping: 10 <-> 9 12 <-> 11 16 <-> 14 -17 <-> 16 +18 <-> 16 22 <-> 20 24 <-> 22 26 <-> 23 @@ -356,28 +358,28 @@ Lines mapping: 29 <-> 26 31 <-> 28 35 <-> 31 -36 <-> 33 +37 <-> 33 41 <-> 37 43 <-> 39 45 <-> 40 47 <-> 42 50 <-> 43 -51 <-> 46 +52 <-> 46 57 <-> 50 59 <-> 52 61 <-> 53 63 <-> 55 64 <-> 56 66 <-> 58 -67 <-> 59 69 <-> 62 72 <-> 65 -74 <-> 68 76 <-> 68 77 <-> 69 80 <-> 59 81 <-> 60 Not mapped: -18 -37 -52 +17 +36 +51 +67 +74 diff --git a/testData/results/pkg/TestSwitchPatternMatching16.dec b/testData/results/pkg/TestSwitchPatternMatching16.dec index 725f8dec4f..ebbf18afd0 100644 --- a/testData/results/pkg/TestSwitchPatternMatching16.dec +++ b/testData/results/pkg/TestSwitchPatternMatching16.dec @@ -108,9 +108,6 @@ class 'pkg/TestSwitchPatternMatching16' { 73 10 7a 11 7b 11 - 7c 12 - 7d 12 - 7e 12 83 19 84 19 85 20 @@ -139,9 +136,12 @@ class 'pkg/TestSwitchPatternMatching16' { a4 12 a5 12 a6 12 + a7 12 + a8 12 a9 12 aa 12 ab 12 + ac 12 ad 13 ae 13 af 14 @@ -178,4 +178,4 @@ Lines mapping: 38 <-> 26 Not mapped: 27 -34 +34 \ No newline at end of file diff --git a/testData/results/pkg/TestSwitchPatternMatchingInstanceof1.dec b/testData/results/pkg/TestSwitchPatternMatchingInstanceof1.dec index caa9380ed7..546c7b6293 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingInstanceof1.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingInstanceof1.dec @@ -60,14 +60,14 @@ class 'pkg/TestSwitchPatternMatchingInstanceof1' { 38 5 3d 5 3e 5 - 3f 6 - 40 6 - 41 6 47 6 48 6 + 49 6 4a 6 4b 6 4c 6 + 4d 6 + 4e 6 4f 7 56 8 57 8 diff --git a/testData/results/pkg/TestSwitchPatternMatchingInstanceof2.dec b/testData/results/pkg/TestSwitchPatternMatchingInstanceof2.dec index e0cc87675c..261b0e9740 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingInstanceof2.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingInstanceof2.dec @@ -61,14 +61,14 @@ class 'pkg/TestSwitchPatternMatchingInstanceof2' { 39 5 3f 5 40 5 - 41 6 - 42 6 - 43 6 49 6 4a 6 + 4b 6 4c 6 4d 6 4e 6 + 4f 6 + 50 6 51 7 58 8 59 8 diff --git a/testData/results/pkg/TestSwitchPatternMatchingInstanceof4.dec b/testData/results/pkg/TestSwitchPatternMatchingInstanceof4.dec index 3052179720..c59b940fcd 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingInstanceof4.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingInstanceof4.dec @@ -61,19 +61,21 @@ class 'pkg/TestSwitchPatternMatchingInstanceof4' { 47 5 4d 5 4e 5 - 4f 6 - 50 6 - 51 6 57 6 58 6 - 5c 6 - 5d 6 - 61 6 - 62 6 - 63 6 + 59 6 + 5a 6 + 5b 6 + 5f 6 + 60 6 64 6 65 6 66 6 + 67 6 + 68 6 + 69 6 + 6a 6 + 6b 6 6c 7 6f 9 70 9 @@ -91,4 +93,4 @@ Lines mapping: 5 <-> 5 6 <-> 6 7 <-> 10 -9 <-> 12 +9 <-> 12 \ No newline at end of file diff --git a/testData/results/pkg/TestSwitchPatternMatchingJ25.dec b/testData/results/pkg/TestSwitchPatternMatchingJ25.dec index 2d6285c6a3..5c9625d93b 100644 --- a/testData/results/pkg/TestSwitchPatternMatchingJ25.dec +++ b/testData/results/pkg/TestSwitchPatternMatchingJ25.dec @@ -356,11 +356,11 @@ class 'pkg/TestSwitchPatternMatchingJ25' { 23 51 54 52 55 52 - 56 52 - 57 52 5e 52 5f 52 60 52 + 61 52 + 62 52 66 53 6a 51 } @@ -397,18 +397,18 @@ class 'pkg/TestSwitchPatternMatchingJ25' { 2b 58 43 59 44 59 - 45 59 - 46 59 4d 59 4e 59 4f 59 + 50 59 + 51 59 6c 60 6d 60 - 6e 60 - 6f 60 76 60 77 60 78 60 + 79 60 + 7a 60 85 61 86 58 } diff --git a/testData/results/pkg/TestSwitchStringHashcodeCollision.dec b/testData/results/pkg/TestSwitchStringHashcodeCollision.dec index e802167736..b85a5d652e 100644 --- a/testData/results/pkg/TestSwitchStringHashcodeCollision.dec +++ b/testData/results/pkg/TestSwitchStringHashcodeCollision.dec @@ -10,7 +10,7 @@ public class TestSwitchStringHashcodeCollision { return 2;// 14 default: System.out.println("Test");// 8 - return 0;// 9 16 + return 0;// 16 } } } @@ -60,19 +60,20 @@ class 'pkg/TestSwitchStringHashcodeCollision' { 6d 11 6e 11 6f 11 - 70 12 73 6 74 6 75 9 76 9 77 12 + 78 12 } } Lines mapping: 6 <-> 5 8 <-> 12 -9 <-> 13 11 <-> 7 14 <-> 10 16 <-> 13 +Not mapped: +9 diff --git a/testData/results/pkg/TestSynchronizedUnprotected.dec b/testData/results/pkg/TestSynchronizedUnprotected.dec index 302e375871..60b0599e78 100644 --- a/testData/results/pkg/TestSynchronizedUnprotected.dec +++ b/testData/results/pkg/TestSynchronizedUnprotected.dec @@ -18,7 +18,7 @@ public final class TestSynchronizedUnprotected { System.out.println("Boom");// 6 Unit var4 = Unit.INSTANCE;// 5 7 } - } + }// 8 } class 'pkg/TestSynchronizedUnprotected' { @@ -40,7 +40,7 @@ class 'pkg/TestSynchronizedUnprotected' { 12 18 13 18 14 18 - 17 20 + 1f 20 } } @@ -48,5 +48,4 @@ Lines mapping: 5 <-> 19 6 <-> 18 7 <-> 19 -Not mapped: -8 \ No newline at end of file +8 <-> 21 diff --git a/testData/results/pkg/TestTryCatchFinally.dec b/testData/results/pkg/TestTryCatchFinally.dec index 4e3a1a0573..fa543ed3ff 100644 --- a/testData/results/pkg/TestTryCatchFinally.dec +++ b/testData/results/pkg/TestTryCatchFinally.dec @@ -33,7 +33,7 @@ public class TestTryCatchFinally { System.out.println("Finally");// 55 } - return -1;// 56 57 + return -1;// 57 } } @@ -89,7 +89,7 @@ class 'pkg/TestTryCatchFinally' { 1 28 2 28 3 28 - 4 28 + e 28 f 29 10 30 11 30 @@ -103,7 +103,6 @@ class 'pkg/TestTryCatchFinally' { 26 30 27 30 28 30 - 31 35 35 32 36 32 37 32 @@ -113,6 +112,7 @@ class 'pkg/TestTryCatchFinally' { 3b 32 3c 32 3f 35 + 40 35 } } @@ -131,9 +131,9 @@ Lines mapping: 52 <-> 30 53 <-> 31 55 <-> 33 -56 <-> 36 57 <-> 36 Not mapped: 25 32 35 +56 diff --git a/testData/results/pkg/TestTryFinally.dec b/testData/results/pkg/TestTryFinally.dec index d224d33d14..5d1a7aa18c 100644 --- a/testData/results/pkg/TestTryFinally.dec +++ b/testData/results/pkg/TestTryFinally.dec @@ -7,7 +7,7 @@ public class TestTryFinally { } finally { long var4 = 5L;// 8 } - }// 9 + }// 10 public void test1() { try { @@ -16,8 +16,8 @@ public class TestTryFinally { System.out.println("Finally");// 16 } - System.out.println("Bye");// 17 19 - } + System.out.println("Bye");// 19 + }// 20 public void test2(int i) { try { @@ -44,12 +44,12 @@ class 'pkg/TestTryFinally' { 5 5 6 5 7 5 - c 9 10 7 11 7 12 7 13 7 14 7 + 17 9 } method 'test1 ()V' { @@ -61,9 +61,6 @@ class 'pkg/TestTryFinally' { 5 13 6 13 7 13 - 10 18 - 11 18 - 12 18 14 15 15 15 16 15 @@ -74,9 +71,13 @@ class 'pkg/TestTryFinally' { 1b 15 1e 18 1f 18 + 20 18 21 18 22 18 23 18 + 24 18 + 25 18 + 26 19 } method 'test2 (I)V' { @@ -123,11 +124,11 @@ class 'pkg/TestTryFinally' { Lines mapping: 6 <-> 6 8 <-> 8 -9 <-> 10 +10 <-> 10 14 <-> 14 16 <-> 16 -17 <-> 19 19 <-> 19 +20 <-> 20 25 <-> 24 27 <-> 26 28 <-> 27 @@ -136,6 +137,6 @@ Lines mapping: 34 <-> 33 35 <-> 34 Not mapped: -10 -20 +9 +17 32 diff --git a/testData/results/pkg/TestTryLoopSimpleFinally.dec b/testData/results/pkg/TestTryLoopSimpleFinally.dec index 717795224f..2267828b90 100644 --- a/testData/results/pkg/TestTryLoopSimpleFinally.dec +++ b/testData/results/pkg/TestTryLoopSimpleFinally.dec @@ -35,7 +35,7 @@ public class TestTryLoopSimpleFinally { } finally { System.out.println("Finally");// 38 } - }// 39 + }// 40 } class 'pkg/TestTryLoopSimpleFinally' { @@ -89,7 +89,6 @@ class 'pkg/TestTryLoopSimpleFinally' { 28 32 29 32 2b 32 - 37 37 3c 35 3d 35 3e 35 @@ -98,6 +97,7 @@ class 'pkg/TestTryLoopSimpleFinally' { 41 35 42 35 43 35 + 47 37 } } @@ -115,9 +115,9 @@ Lines mapping: 32 <-> 30 35 <-> 33 38 <-> 36 -39 <-> 38 +40 <-> 38 Not mapped: 17 22 36 -40 \ No newline at end of file +39 diff --git a/testData/results/pkg/TestTryReturn.dec b/testData/results/pkg/TestTryReturn.dec index 8603dafb41..9d7467801b 100644 --- a/testData/results/pkg/TestTryReturn.dec +++ b/testData/results/pkg/TestTryReturn.dec @@ -35,8 +35,8 @@ public class TestTryReturn { return;// 28 } - System.out.println("suc");// 32 34 - } + System.out.println("suc");// 34 + }// 35 public boolean testFinally2(Supplier supplier) { boolean b; @@ -46,7 +46,7 @@ public class TestTryReturn { System.out.println("Finally");// 42 } - return b;// 43 45 + return b;// 45 } public boolean testFinally3(boolean b, boolean c, int a, Supplier supplier) { @@ -70,7 +70,7 @@ public class TestTryReturn { System.out.println("Finally");// 69 } - return b;// 70 72 + return b;// 72 } public boolean testFinally5(Supplier supplier) { @@ -183,7 +183,7 @@ public class TestTryReturn { public void testVarWrong() { try { System.out.println("Hi");// 164 - return;// 174 + return;// 175 } catch (Exception var2) {// 165 if (var2 == null) {// 166 System.out.println(var2);// 169 @@ -209,7 +209,7 @@ public class TestTryReturn { try { System.out.println(var4);// 185 - return;// 195 + return;// 196 } catch (Exception var5) {// 186 } finally { System.out.println(var15);// 190 @@ -233,8 +233,8 @@ public class TestTryReturn { return;// 203 } - System.out.println("post");// 206 208 - } + System.out.println("post");// 208 + }// 209 } class 'pkg/TestTryReturn' { @@ -264,7 +264,7 @@ class 'pkg/TestTryReturn' { 9 16 a 16 b 16 - c 16 + 16 16 18 18 19 18 1a 18 @@ -297,9 +297,6 @@ class 'pkg/TestTryReturn' { 15 27 16 27 1f 34 - 28 37 - 29 37 - 2a 37 2c 31 2d 31 2e 31 @@ -310,9 +307,13 @@ class 'pkg/TestTryReturn' { 33 31 36 37 37 37 + 38 37 39 37 3a 37 3b 37 + 3c 37 + 3d 37 + 3e 38 } method 'testFinally2 (Ljava/util/function/Supplier;)Z' { @@ -326,7 +327,6 @@ class 'pkg/TestTryReturn' { a 43 b 43 c 43 - 15 48 19 45 1a 45 1b 45 @@ -336,6 +336,7 @@ class 'pkg/TestTryReturn' { 1f 45 20 45 23 48 + 24 48 } method 'testFinally3 (ZZILjava/util/function/Supplier;)Z' { @@ -360,7 +361,7 @@ class 'pkg/TestTryReturn' { 15 56 16 56 17 56 - 1d 56 + 29 56 2a 54 2b 54 2c 54 @@ -403,7 +404,6 @@ class 'pkg/TestTryReturn' { c 67 d 67 e 67 - 17 72 1b 69 1c 69 1d 69 @@ -413,6 +413,7 @@ class 'pkg/TestTryReturn' { 21 69 22 69 25 72 + 26 72 } method 'testFinally5 (Ljava/util/function/Supplier;)Z' { @@ -577,7 +578,6 @@ class 'pkg/TestTryReturn' { 5 184 6 184 7 184 - b 185 e 186 f 187 10 187 @@ -596,6 +596,7 @@ class 'pkg/TestTryReturn' { 25 192 26 192 27 192 + 2b 185 } method 'testInvalidUse ()V' { @@ -629,7 +630,6 @@ class 'pkg/TestTryReturn' { 3d 214 3e 214 3f 214 - 4a 211 4f 217 50 217 51 217 @@ -637,6 +637,7 @@ class 'pkg/TestTryReturn' { 53 217 54 217 55 217 + 59 211 } method 'returnInCatch ()V' { @@ -648,9 +649,6 @@ class 'pkg/TestTryReturn' { 5 224 6 224 7 224 - 10 235 - 11 235 - 12 235 13 226 14 227 15 227 @@ -671,9 +669,13 @@ class 'pkg/TestTryReturn' { 2d 229 30 235 31 235 + 32 235 33 235 34 235 35 235 + 36 235 + 37 235 + 38 236 } } @@ -687,11 +689,10 @@ Lines mapping: 27 <-> 28 28 <-> 35 31 <-> 32 -32 <-> 38 34 <-> 38 +35 <-> 39 40 <-> 44 42 <-> 46 -43 <-> 49 45 <-> 49 50 <-> 54 51 <-> 57 @@ -702,7 +703,6 @@ Lines mapping: 65 <-> 65 67 <-> 68 69 <-> 70 -70 <-> 73 72 <-> 73 76 <-> 77 78 <-> 80 @@ -739,7 +739,7 @@ Lines mapping: 169 <-> 189 170 <-> 190 173 <-> 193 -174 <-> 186 +175 <-> 186 178 <-> 198 179 <-> 199 181 <-> 204 @@ -750,24 +750,26 @@ Lines mapping: 187 <-> 220 190 <-> 215 194 <-> 218 -195 <-> 212 +196 <-> 212 200 <-> 225 201 <-> 227 202 <-> 228 203 <-> 233 205 <-> 230 -206 <-> 236 208 <-> 236 +209 <-> 237 Not mapped: 20 -35 +32 +43 61 +70 84 103 118 153 157 -175 +174 191 -196 -209 +195 +206 diff --git a/testData/results/pkg/TestTrySplit.dec b/testData/results/pkg/TestTrySplit.dec index f484856c2a..d738cd6cb3 100644 --- a/testData/results/pkg/TestTrySplit.dec +++ b/testData/results/pkg/TestTrySplit.dec @@ -6,7 +6,7 @@ public class TestTrySplit { try { obj = new Object();// 7 - return;// 17 + return;// 18 } catch (ArithmeticException ex) {// 8 if (obj != null) {// 9 System.out.println("a");// 10 @@ -28,7 +28,6 @@ class 'pkg/TestTrySplit' { 0 4 1 4 9 7 - 12 8 15 9 16 10 17 10 @@ -58,6 +57,7 @@ class 'pkg/TestTrySplit' { 38 16 39 16 3a 16 + 3d 8 } method 'throwMyException (Ljava/lang/String;)V' { @@ -75,7 +75,7 @@ Lines mapping: 13 <-> 15 14 <-> 19 16 <-> 17 -17 <-> 9 +18 <-> 9 21 <-> 22 Not mapped: -18 \ No newline at end of file +17 diff --git a/testData/results/pkg/TestTryWithResourcesAfterSwitch.dec b/testData/results/pkg/TestTryWithResourcesAfterSwitch.dec index 99c45b0a1d..af104a7afd 100644 --- a/testData/results/pkg/TestTryWithResourcesAfterSwitch.dec +++ b/testData/results/pkg/TestTryWithResourcesAfterSwitch.dec @@ -21,7 +21,7 @@ public class TestTryWithResourcesAfterSwitch { System.out.println("f");// 23 } } - }// 24 + }// 25 public void test2() { ElementType vvv3 = ElementType.METHOD;// 28 @@ -38,7 +38,7 @@ public class TestTryWithResourcesAfterSwitch { System.out.println("f");// 42 } } - }// 43 + }// 44 } class 'pkg/TestTryWithResourcesAfterSwitch' { @@ -92,7 +92,6 @@ class 'pkg/TestTryWithResourcesAfterSwitch' { 63 18 64 18 65 18 - bf 23 c4 20 c5 20 c6 20 @@ -101,6 +100,7 @@ class 'pkg/TestTryWithResourcesAfterSwitch' { c9 20 ca 20 cb 20 + cf 23 } method 'test2 ()V' { @@ -149,7 +149,6 @@ class 'pkg/TestTryWithResourcesAfterSwitch' { 5e 35 5f 35 60 35 - b5 40 ba 37 bb 37 bc 37 @@ -158,6 +157,7 @@ class 'pkg/TestTryWithResourcesAfterSwitch' { bf 37 c0 37 c1 37 + c5 40 } } @@ -170,7 +170,7 @@ Lines mapping: 20 <-> 18 21 <-> 19 23 <-> 21 -24 <-> 24 +25 <-> 24 28 <-> 27 29 <-> 28 30 <-> 29 @@ -178,9 +178,9 @@ Lines mapping: 39 <-> 35 40 <-> 36 42 <-> 38 -43 <-> 41 +44 <-> 41 Not mapped: 22 -25 +24 41 -44 +43 diff --git a/testData/results/pkg/TestTryWithResourcesFinallyJ16.dec b/testData/results/pkg/TestTryWithResourcesFinallyJ16.dec index 02601177c3..27f6590264 100644 --- a/testData/results/pkg/TestTryWithResourcesFinallyJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesFinallyJ16.dec @@ -11,7 +11,7 @@ public class TestTryWithResourcesFinallyJ16 { } finally { System.out.println("Hello");// 12 } - }// 13 + }// 14 public void testFunc(File file) throws FileNotFoundException { try (Scanner scanner = this.create(file)) {// 17 @@ -19,7 +19,7 @@ public class TestTryWithResourcesFinallyJ16 { } finally { System.out.println("Hello");// 20 } - }// 21 + }// 22 private Scanner create(File file) throws FileNotFoundException { return new Scanner(file);// 25 @@ -34,7 +34,6 @@ class 'pkg/TestTryWithResourcesFinallyJ16' { a 9 b 9 c 9 - 2f 13 34 11 35 11 36 11 @@ -43,6 +42,7 @@ class 'pkg/TestTryWithResourcesFinallyJ16' { 39 11 3a 11 3b 11 + 3f 13 } method 'testFunc (Ljava/io/File;)V' { @@ -56,7 +56,6 @@ class 'pkg/TestTryWithResourcesFinallyJ16' { 7 17 8 17 9 17 - 34 21 39 19 3a 19 3b 19 @@ -65,6 +64,7 @@ class 'pkg/TestTryWithResourcesFinallyJ16' { 3e 19 3f 19 40 19 + 44 21 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { @@ -77,14 +77,14 @@ Lines mapping: 9 <-> 9 10 <-> 10 12 <-> 12 -13 <-> 14 +14 <-> 14 17 <-> 17 18 <-> 18 20 <-> 20 -21 <-> 22 +22 <-> 22 25 <-> 25 Not mapped: 11 -14 +13 19 -22 +21 diff --git a/testData/results/pkg/TestTryWithResourcesJ16.dec b/testData/results/pkg/TestTryWithResourcesJ16.dec index acdbbbebe4..f5f1b737f9 100644 --- a/testData/results/pkg/TestTryWithResourcesJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesJ16.dec @@ -9,7 +9,7 @@ public class TestTryWithResourcesJ16 { try (Scanner scanner = new Scanner(file)) {// 11 scanner.next();// 12 } - }// 13 + }// 14 public void testFunc(File file) throws FileNotFoundException { try (Scanner scanner = this.create(file)) {// 17 @@ -30,7 +30,7 @@ class 'pkg/TestTryWithResourcesJ16' { a 9 b 9 c 9 - 12 11 + 27 11 } method 'testFunc (Ljava/io/File;)V' { @@ -56,11 +56,11 @@ class 'pkg/TestTryWithResourcesJ16' { Lines mapping: 11 <-> 9 12 <-> 10 -13 <-> 12 +14 <-> 12 17 <-> 15 18 <-> 16 20 <-> 18 23 <-> 21 Not mapped: -14 +13 19 diff --git a/testData/results/pkg/TestTryWithResourcesManyJ16.dec b/testData/results/pkg/TestTryWithResourcesManyJ16.dec index 56b5698eb4..4b4c7fa195 100644 --- a/testData/results/pkg/TestTryWithResourcesManyJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesManyJ16.dec @@ -19,7 +19,7 @@ public class TestTryWithResourcesManyJ16 { System.out.println(s4.nextLine());// 19 System.out.println(s5.nextLine());// 20 } - }// 21 + }// 22 } class 'pkg/TestTryWithResourcesManyJ16' { @@ -90,7 +90,7 @@ class 'pkg/TestTryWithResourcesManyJ16' { 62 19 63 19 64 19 - df 21 + f4 21 } } @@ -105,7 +105,7 @@ Lines mapping: 18 <-> 18 19 <-> 19 20 <-> 20 -21 <-> 22 +22 <-> 22 Not mapped: 9 -22 +21 diff --git a/testData/results/pkg/TestTryWithResourcesMultiJ16.dec b/testData/results/pkg/TestTryWithResourcesMultiJ16.dec index 19bd4edff2..bb5399ffe4 100644 --- a/testData/results/pkg/TestTryWithResourcesMultiJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesMultiJ16.dec @@ -14,7 +14,7 @@ public class TestTryWithResourcesMultiJ16 { scanner.next();// 11 writer.write("hello");// 12 } - }// 13 + }// 14 public void testMulti2(File file) throws IOException { try ( @@ -24,7 +24,7 @@ public class TestTryWithResourcesMultiJ16 { scanner.next();// 19 writer.write("hello");// 20 } - }// 22 + }// 23 public void testMulti2Fake(File file) throws IOException { try (Scanner scanner = new Scanner(file)) {// 26 @@ -48,7 +48,7 @@ public class TestTryWithResourcesMultiJ16 { System.out.println("??");// 43 } } - }// 46 + }// 47 } class 'pkg/TestTryWithResourcesMultiJ16' { @@ -67,7 +67,7 @@ class 'pkg/TestTryWithResourcesMultiJ16' { 1a 14 1b 14 1c 14 - 3d 16 + 52 16 } method 'testMulti2 (Ljava/io/File;)V' { @@ -85,7 +85,7 @@ class 'pkg/TestTryWithResourcesMultiJ16' { 1a 24 1b 24 1c 24 - 3d 26 + 52 26 } method 'testMulti2Fake (Ljava/io/File;)V' { @@ -135,7 +135,7 @@ class 'pkg/TestTryWithResourcesMultiJ16' { 26 47 27 47 28 47 - 49 50 + 5e 50 } } @@ -143,12 +143,12 @@ Lines mapping: 10 <-> 11 11 <-> 14 12 <-> 15 -13 <-> 17 +14 <-> 17 17 <-> 21 18 <-> 22 19 <-> 24 20 <-> 25 -22 <-> 27 +23 <-> 27 26 <-> 30 27 <-> 31 28 <-> 32 @@ -162,12 +162,12 @@ Lines mapping: 40 <-> 46 42 <-> 47 43 <-> 48 -46 <-> 51 +47 <-> 51 Not mapped: -14 +13 21 -23 +22 31 33 45 -47 \ No newline at end of file +46 diff --git a/testData/results/pkg/TestTryWithResourcesNestedJ16.dec b/testData/results/pkg/TestTryWithResourcesNestedJ16.dec index 1cbbf63be5..5c1df15e27 100644 --- a/testData/results/pkg/TestTryWithResourcesNestedJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesNestedJ16.dec @@ -14,7 +14,7 @@ public class TestTryWithResourcesNestedJ16 { ) { scanner.next();// 14 } - }// 18 + }// 19 public void testNestedFinally(File file) throws IOException { try (Scanner scanner = new Scanner(file)) {// 22 @@ -34,7 +34,7 @@ public class TestTryWithResourcesNestedJ16 { } finally { System.out.println(1);// 37 } - }// 38 + }// 39 } class 'pkg/TestTryWithResourcesNestedJ16' { @@ -53,7 +53,7 @@ class 'pkg/TestTryWithResourcesNestedJ16' { 27 14 28 14 29 14 - 87 16 + 9c 16 } method 'testNestedFinally (Ljava/io/File;)V' { @@ -92,7 +92,6 @@ class 'pkg/TestTryWithResourcesNestedJ16' { bf 31 c0 31 c1 31 - e5 36 ea 34 eb 34 ec 34 @@ -100,6 +99,7 @@ class 'pkg/TestTryWithResourcesNestedJ16' { ee 34 ef 34 f0 34 + f4 36 } } @@ -109,7 +109,7 @@ Lines mapping: 12 <-> 12 13 <-> 13 14 <-> 15 -18 <-> 17 +19 <-> 17 22 <-> 20 23 <-> 21 24 <-> 22 @@ -119,12 +119,12 @@ Lines mapping: 31 <-> 29 34 <-> 32 37 <-> 35 -38 <-> 37 +39 <-> 37 Not mapped: 15 16 17 -19 +18 27 29 30 @@ -132,4 +132,4 @@ Not mapped: 33 35 36 -39 +38 diff --git a/testData/results/pkg/TestTryWithResourcesNestedLoop.dec b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec index f22b3b6402..fdf5c2d0c1 100644 --- a/testData/results/pkg/TestTryWithResourcesNestedLoop.dec +++ b/testData/results/pkg/TestTryWithResourcesNestedLoop.dec @@ -187,7 +187,7 @@ class 'pkg/TestTryWithResourcesNestedLoop' { ba 29 c0 30 c1 30 - c5 30 + 132 30 212 35 213 35 } diff --git a/testData/results/pkg/TestTryWithResourcesOuterJ16.dec b/testData/results/pkg/TestTryWithResourcesOuterJ16.dec index 7d79c350af..bf84792c0c 100644 --- a/testData/results/pkg/TestTryWithResourcesOuterJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesOuterJ16.dec @@ -104,7 +104,7 @@ public class TestTryWithResourcesOuterJ16 { ) { scanner.next();// 98 } - }// 100 + }// 101 private Scanner create(File file) throws FileNotFoundException { return new Scanner(file);// 104 @@ -250,7 +250,7 @@ class 'pkg/TestTryWithResourcesOuterJ16' { c 104 d 104 e 104 - 38 106 + 4d 106 } method 'create (Ljava/io/File;)Ljava/util/Scanner;' { @@ -308,7 +308,7 @@ Lines mapping: 96 <-> 102 97 <-> 103 98 <-> 105 -100 <-> 107 +101 <-> 107 104 <-> 110 Not mapped: 15 @@ -325,4 +325,4 @@ Not mapped: 89 92 99 -101 +100 diff --git a/testData/results/pkg/TestTryWithResourcesReturn.dec b/testData/results/pkg/TestTryWithResourcesReturn.dec index 58f4c54024..49a2ef230e 100644 --- a/testData/results/pkg/TestTryWithResourcesReturn.dec +++ b/testData/results/pkg/TestTryWithResourcesReturn.dec @@ -280,7 +280,7 @@ class 'pkg/TestTryWithResourcesReturn' { 4 9 8 9 b 10 - c 10 + 2e 10 } method 'test2 (Ljava/io/File;)Ljava/util/Scanner;' { @@ -295,7 +295,7 @@ class 'pkg/TestTryWithResourcesReturn' { 11 16 12 16 13 17 - 14 17 + 36 17 62 18 63 19 64 19 @@ -313,7 +313,7 @@ class 'pkg/TestTryWithResourcesReturn' { 4 25 8 25 b 26 - c 26 + 2e 26 5a 27 5b 28 5c 28 @@ -339,7 +339,7 @@ class 'pkg/TestTryWithResourcesReturn' { c 36 10 36 13 37 - 14 37 + 36 37 62 38 63 39 64 39 @@ -373,7 +373,7 @@ class 'pkg/TestTryWithResourcesReturn' { 19 48 1a 48 1b 49 - 1c 49 + 3e 49 6a 50 6b 51 6c 51 @@ -402,7 +402,7 @@ class 'pkg/TestTryWithResourcesReturn' { 11 58 12 58 19 58 - 1a 58 + 3c 58 68 59 69 60 6a 60 @@ -424,7 +424,7 @@ class 'pkg/TestTryWithResourcesReturn' { 4 66 5 66 8 67 - 9 67 + 2b 67 } method 'testFinally (Ljava/io/File;)Ljava/util/Scanner;' { @@ -471,7 +471,7 @@ class 'pkg/TestTryWithResourcesReturn' { 28 227 29 227 2a 228 - 2b 228 + 75 228 76 231 77 231 78 231 @@ -556,7 +556,7 @@ class 'pkg/TestTryWithResourcesReturn' { 26 251 27 251 28 251 - 29 251 + 73 251 74 254 75 254 76 254 @@ -587,7 +587,7 @@ class 'pkg/TestTryWithResourcesReturn' { 14 263 15 263 16 263 - 17 263 + 3e 263 3f 266 40 266 41 266 diff --git a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec index e00a458572..535f9e09f0 100644 --- a/testData/results/pkg/TestTryWithResourcesReturnJ16.dec +++ b/testData/results/pkg/TestTryWithResourcesReturnJ16.dec @@ -589,7 +589,7 @@ class 'pkg/TestTryWithResourcesReturnJ16' { 4 207 8 207 9 208 - 27 208 + 28 208 } method 'testFake (Ljava/io/File;)Ljava/lang/String;' { @@ -765,4 +765,4 @@ Not mapped: 151 160 169 -178 \ No newline at end of file +178 diff --git a/testData/results/pkg/TestUnknownCastJ17.dec b/testData/results/pkg/TestUnknownCastJ17.dec index f38cb03fd1..7bec2acf88 100644 --- a/testData/results/pkg/TestUnknownCastJ17.dec +++ b/testData/results/pkg/TestUnknownCastJ17.dec @@ -33,7 +33,7 @@ public class TestUnknownCastJ17 { System.out.println(vvv1);// 18 } - yield 140;// 19 + yield 140; } }; --var19 <= 395; var19 -= 6) {// 20 int vvv6 = -91;// 21 @@ -128,9 +128,6 @@ class 'pkg/TestUnknownCastJ17' { 5d 27 5e 27 5f 27 - 67 35 - 68 35 - 69 35 6c 32 6d 32 6e 32 @@ -138,6 +135,9 @@ class 'pkg/TestUnknownCastJ17' { 70 32 71 32 72 32 + 76 35 + 77 35 + 78 35 7a 37 7b 37 7c 37 @@ -253,7 +253,6 @@ Lines mapping: 16 <-> 20 17 <-> 31 18 <-> 33 -19 <-> 36 20 <-> 38 21 <-> 39 22 <-> 40 @@ -274,5 +273,6 @@ Lines mapping: 52 <-> 70 54 <-> 72 Not mapped: +19 26 49 diff --git a/testData/results/pkg/TestVarRedef.dec b/testData/results/pkg/TestVarRedef.dec index 547c23223f..e3ec9faf09 100644 --- a/testData/results/pkg/TestVarRedef.dec +++ b/testData/results/pkg/TestVarRedef.dec @@ -46,7 +46,7 @@ class 'pkg/TestVarRedef' { 4 16 5 16 6 17 - 9 17 + 17 17 1f 20 24 21 28 21 @@ -65,7 +65,7 @@ class 'pkg/TestVarRedef' { 35 23 36 23 37 23 - 3c 23 + 4c 23 4d 24 52 25 56 25 From e6f4d0bb4872026a30021c92d3fed0fa56ec579b Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 9 May 2026 10:24:05 +0200 Subject: [PATCH 03/29] Add broken test cases See #573, #574, #575, #582 --- .../java/decompiler/SingleClassesTest.java | 12 + testData/results/pkg/TestForEachInSwitch.dec | 118 ++++++++ .../pkg/TestStringConcatObjectAppend.dec | 77 +++++ .../pkg/TestStringConcatObjectAppendJ25.dec | 77 +++++ .../TestSwitchExpressionAssignmentOrder.dec | 275 ++++++++++++++++++ .../pkg/TestStringConcatObjectAppend.java | 19 ++ .../TestSwitchExpressionAssignmentOrder.java | 43 +++ .../pkg/TestStringConcatObjectAppendJ25.java | 19 ++ testData/src/java8/pkg/TestArrayArg.java | 8 + .../src/java8/pkg/TestDanglingBoxingCall.java | 24 ++ .../src/java8/pkg/TestForEachInSwitch.java | 54 ++++ .../src/java8/pkg/TestSharedVarIndex.java | 26 ++ 12 files changed, 752 insertions(+) create mode 100644 testData/results/pkg/TestForEachInSwitch.dec create mode 100644 testData/results/pkg/TestStringConcatObjectAppend.dec create mode 100644 testData/results/pkg/TestStringConcatObjectAppendJ25.dec create mode 100644 testData/results/pkg/TestSwitchExpressionAssignmentOrder.dec create mode 100644 testData/src/java11/pkg/TestStringConcatObjectAppend.java create mode 100644 testData/src/java16/pkg/TestSwitchExpressionAssignmentOrder.java create mode 100644 testData/src/java25/pkg/TestStringConcatObjectAppendJ25.java create mode 100644 testData/src/java8/pkg/TestForEachInSwitch.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 2d27082823..115f55669f 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -445,6 +445,8 @@ private void registerDefault() { register(JAVA_16, "TestSwitchExpressionPPMM"); register(JAVA_16, "TestSwitchExpressionNested1"); register(JAVA_16, "TestSwitchExprInvoc"); + // TODO: Wrong variable analysis + register(JAVA_16, "TestSwitchExpressionAssignmentOrder"); register(JAVA_16, "TestAccidentalSwitchExpression"); @@ -654,6 +656,7 @@ private void registerDefault() { // seems also is a bug in stack vars processing, disable main loop stackvars to replicate register(JAVA_8_NODEBUG, "TestCompoundAssignmentReplace"); + // TODO: types are merged; issue #574 register(JAVA_8, "TestSharedVarIndex"); // NOTE: regular fernflower fails to merge the variables here, leading to incorrect results in both @@ -745,6 +748,7 @@ private void registerDefault() { register(JAVA_8, "TestNumberCasts"); // TODO: Disambiguate only the required parameters register(JAVA_8, "TestNumberDisambiguation"); + // TODO: Dangling unboxing calls are still elided; issue #575 register(JAVA_8, "TestDanglingBoxingCall"); register(JAVA_21, "TestSwitchOnEnumJ21", "ext/TestEnum2"); // Test switch-on-enum decompilation when enum does not exist in the classpath @@ -830,7 +834,14 @@ private void registerDefault() { register(JAVA_17, "TestStringSwitchTypes"); + // TODO: Fix issue #543 + register(JAVA_8, "TestForEachInSwitch"); + register(JAVA_16, "TestSwitchExpressionIfBlocks"); + + // TODO: String type info is lost; does not recompile; issue #573 + register(JAVA_11, "TestStringConcatObjectAppend"); + register(JAVA_25, "TestStringConcatObjectAppendJ25"); } private void registerEntireClassPath() { @@ -926,6 +937,7 @@ private void registerJavaRuntime() { // TODO: wrong cast in lambda for array register(JAVA_8, "TestArrayGenerics"); register(JAVA_8, "TestEmptyLambda"); + // TODO: test5b is missing a required cast in the output; issue #582 register(JAVA_8, "TestArrayArg"); register(JAVA_8, "TestGenericLattice"); // TODO: parsing failure diff --git a/testData/results/pkg/TestForEachInSwitch.dec b/testData/results/pkg/TestForEachInSwitch.dec new file mode 100644 index 0000000000..4179cca813 --- /dev/null +++ b/testData/results/pkg/TestForEachInSwitch.dec @@ -0,0 +1,118 @@ +package pkg; + +import java.util.ArrayList; + +public class TestForEachInSwitch { + private static final int GUEST_CHECKOUT = 1; + private static final int REGISTERED_USER = 2; + private static final int SUBSCRIPTION_RENEWAL = 3; + private static final int EXPRESS_DELIVERY = 4; + private static final int INTERNATIONAL_SHIPPING = 5; + + public void processTransactionDetails(int param1, ArrayList param2) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: aload 2 + // 01: invokevirtual java/util/ArrayList.iterator ()Ljava/util/Iterator; + // 04: astore 3 + // 05: aload 3 + // 06: invokeinterface java/util/Iterator.hasNext ()Z 1 + // 0b: ifeq c3 + // 0e: aload 3 + // 0f: invokeinterface java/util/Iterator.next ()Ljava/lang/Object; 1 + // 14: checkcast pkg/TestForEachInSwitch$OrderData + // 17: astore 4 + // 19: iload 1 + // 1a: tableswitch 166 1 5 34 34 84 125 125 + // 3c: new java/util/HashSet + // 3f: dup + // 40: invokespecial java/util/HashSet. ()V + // 43: astore 5 + // 45: aload 5 + // 47: invokevirtual java/util/HashSet.iterator ()Ljava/util/Iterator; + // 4a: astore 6 + // 4c: aload 6 + // 4e: invokeinterface java/util/Iterator.hasNext ()Z 1 + // 53: ifeq 6b + // 56: aload 6 + // 58: invokeinterface java/util/Iterator.next ()Ljava/lang/Object; 1 + // 5d: checkcast pkg/TestForEachInSwitch$ProductItem + // 60: astore 7 + // 62: aload 0 + // 63: aload 7 + // 65: invokespecial pkg/TestForEachInSwitch.updateInventoryLog (Lpkg/TestForEachInSwitch$ProductItem;)V + // 68: goto 4c + // 6b: goto c0 + // 6e: aload 4 + // 70: invokevirtual pkg/TestForEachInSwitch$OrderData.getPurchasedItems ()[Lpkg/TestForEachInSwitch$ProductItem; + // 73: astore 5 + // 75: aload 5 + // 77: arraylength + // 78: istore 6 + // 7a: bipush 0 + // 7b: istore 7 + // 7d: iload 7 + // 7f: iload 6 + // 81: if_icmpge 97 + // 84: aload 5 + // 86: iload 7 + // 88: aaload + // 89: astore 8 + // 8b: aload 0 + // 8c: aload 8 + // 8e: invokespecial pkg/TestForEachInSwitch.updateInventoryLog (Lpkg/TestForEachInSwitch$ProductItem;)V + // 91: iinc 7 1 + // 94: goto 7d + // 97: aload 4 + // 99: invokevirtual pkg/TestForEachInSwitch$OrderData.getPurchasedItems ()[Lpkg/TestForEachInSwitch$ProductItem; + // 9c: astore 5 + // 9e: aload 5 + // a0: arraylength + // a1: istore 6 + // a3: bipush 0 + // a4: istore 7 + // a6: iload 7 + // a8: iload 6 + // aa: if_icmpge c0 + // ad: aload 5 + // af: iload 7 + // b1: aaload + // b2: astore 8 + // b4: aload 0 + // b5: aload 8 + // b7: invokespecial pkg/TestForEachInSwitch.updateInventoryLog (Lpkg/TestForEachInSwitch$ProductItem;)V + // ba: iinc 7 1 + // bd: goto a6 + // c0: goto 05 + // c3: return + } + + private void updateInventoryLog(TestForEachInSwitch.ProductItem item) { + }// 44 + + static class OrderData { + public TestForEachInSwitch.ProductItem[] getPurchasedItems() { + return null;// 51 + } + } + + static class ProductItem { + } +} + +class 'pkg/TestForEachInSwitch' { + method 'updateInventoryLog (Lpkg/TestForEachInSwitch$ProductItem;)V' { + 0 90 + } +} + +class 'pkg/TestForEachInSwitch$OrderData' { + method 'getPurchasedItems ()[Lpkg/TestForEachInSwitch$ProductItem;' { + 0 94 + 1 94 + } +} + +Lines mapping: +44 <-> 91 +51 <-> 95 diff --git a/testData/results/pkg/TestStringConcatObjectAppend.dec b/testData/results/pkg/TestStringConcatObjectAppend.dec new file mode 100644 index 0000000000..ec680fbae3 --- /dev/null +++ b/testData/results/pkg/TestStringConcatObjectAppend.dec @@ -0,0 +1,77 @@ +package pkg; + +import java.util.Vector; + +public class TestStringConcatObjectAppend { + public static void store(Vector values) { + String text = "";// 7 + + for (int i = 0; i < values.size(); i++) {// 8 + text = text + values.elementAt(i) + ";";// 9 + } + + sink(text);// 11 + sink(String.valueOf(text));// 12 + }// 13 + + private static void sink(String value) { + }// 18 +} + +class 'pkg/TestStringConcatObjectAppend' { + method 'store (Ljava/util/Vector;)V' { + 0 6 + 1 6 + 2 6 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + 8 8 + 9 8 + a 8 + b 8 + c 8 + d 9 + e 9 + f 9 + 10 9 + 11 9 + 12 9 + 13 9 + 14 9 + 15 9 + 16 9 + 17 9 + 18 9 + 19 8 + 1a 8 + 1b 8 + 1f 12 + 20 12 + 21 12 + 22 12 + 23 13 + 24 13 + 25 13 + 26 13 + 27 13 + 28 13 + 29 13 + 2a 14 + } + + method 'sink (Ljava/lang/String;)V' { + 0 17 + } +} + +Lines mapping: +7 <-> 7 +8 <-> 9 +9 <-> 10 +11 <-> 13 +12 <-> 14 +13 <-> 15 +18 <-> 18 diff --git a/testData/results/pkg/TestStringConcatObjectAppendJ25.dec b/testData/results/pkg/TestStringConcatObjectAppendJ25.dec new file mode 100644 index 0000000000..ede75a69fd --- /dev/null +++ b/testData/results/pkg/TestStringConcatObjectAppendJ25.dec @@ -0,0 +1,77 @@ +package pkg; + +import java.util.Vector; + +public class TestStringConcatObjectAppendJ25 { + public static void store(Vector values) { + String text = "";// 7 + + for (int i = 0; i < values.size(); i++) {// 8 + text = text + values.elementAt(i) + ";";// 9 + } + + sink(text);// 11 + sink(String.valueOf(text));// 12 + }// 13 + + private static void sink(String value) { + }// 18 +} + +class 'pkg/TestStringConcatObjectAppendJ25' { + method 'store (Ljava/util/Vector;)V' { + 0 6 + 1 6 + 2 6 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + 8 8 + 9 8 + a 8 + b 8 + c 8 + d 9 + e 9 + f 9 + 10 9 + 11 9 + 12 9 + 16 9 + 17 9 + 18 9 + 19 9 + 1a 9 + 1b 9 + 1c 8 + 1d 8 + 1e 8 + 22 12 + 23 12 + 24 12 + 25 12 + 26 13 + 27 13 + 28 13 + 29 13 + 2a 13 + 2b 13 + 2c 13 + 2d 14 + } + + method 'sink (Ljava/lang/String;)V' { + 0 17 + } +} + +Lines mapping: +7 <-> 7 +8 <-> 9 +9 <-> 10 +11 <-> 13 +12 <-> 14 +13 <-> 15 +18 <-> 18 diff --git a/testData/results/pkg/TestSwitchExpressionAssignmentOrder.dec b/testData/results/pkg/TestSwitchExpressionAssignmentOrder.dec new file mode 100644 index 0000000000..d3d0dfe076 --- /dev/null +++ b/testData/results/pkg/TestSwitchExpressionAssignmentOrder.dec @@ -0,0 +1,275 @@ +package pkg; + +public class TestSwitchExpressionAssignmentOrder { + public int test1(int i1) { + int v = 5;// 5 + byte var3; + + return v + (var3 = this.test1(i1)) + switch (var3) {// 6 + case 0 -> 1;// 7 + case 1 -> 2;// 8 + default -> 0;// 9 + }; + } + + // $VF: Variable merging failed for merge VarExprent[2,0]: {var2}. Code has semantic differences! + public int test2(int i1) { + int v = 5;// 14 + v = i1; + + return v + i1 + switch (v) {// 15 + case 0 -> 1;// 16 + case 1 -> 2;// 17 + default -> 0;// 18 + }; + } + + public int test3(int i1) { + int v = 5;// 23 + int o = 3; + if (i1 > 0) {// 24 + v = i1; + + o = v + i1 + switch (v) {// 25 + case 0 -> 1;// 26 + case 1 -> v = 2;// 27 + default -> 0;// 28 + }; + } + + return v - 3;// 31 + } + + public int test4(int i1) { + int v = 5;// 36 + byte var4; + int o = var4; + + return (var4 = i1 + v) + var4 + switch (v = v + var4) {// 37 + case 0 -> o;// 38 + case 1 -> { + byte var6; + yield var6 = (byte)2;// 39 + } + default -> 0;// 40 + }; + } +} + +class 'pkg/TestSwitchExpressionAssignmentOrder' { + method 'test1 (I)I' { + 0 4 + 1 4 + 2 7 + 3 7 + 4 7 + 5 7 + 6 7 + 7 7 + 9 7 + a 7 + b 7 + c 7 + d 7 + e 7 + f 7 + 10 7 + 11 7 + 12 7 + 13 7 + 14 7 + 15 7 + 16 7 + 17 7 + 18 7 + 19 7 + 1a 7 + 1b 7 + 1c 7 + 1d 7 + 1e 7 + 1f 7 + 20 7 + 21 7 + 22 7 + 23 7 + 24 7 + 25 7 + 26 7 + 27 7 + 28 8 + 2c 9 + 30 10 + 31 7 + 32 7 + } + + method 'test2 (I)I' { + 0 16 + 1 16 + 2 19 + 3 17 + 5 17 + 6 19 + 7 19 + 8 19 + 9 19 + a 19 + b 19 + c 19 + d 19 + e 19 + f 19 + 10 19 + 11 19 + 12 19 + 13 19 + 14 19 + 15 19 + 16 19 + 17 19 + 18 19 + 19 19 + 1a 19 + 1b 19 + 1c 19 + 1d 19 + 1e 19 + 1f 19 + 20 19 + 21 19 + 22 19 + 23 19 + 24 20 + 28 21 + 2c 22 + 2d 19 + 2e 19 + } + + method 'test3 (I)I' { + 0 27 + 1 27 + 2 28 + 3 28 + 4 29 + 5 29 + 6 29 + 7 29 + 8 32 + 9 30 + b 30 + c 32 + d 32 + e 32 + f 32 + 10 32 + 11 32 + 12 32 + 13 32 + 14 32 + 15 32 + 16 32 + 17 32 + 18 32 + 19 32 + 1a 32 + 1b 32 + 1c 32 + 1d 32 + 1e 32 + 1f 32 + 20 32 + 21 32 + 22 32 + 23 32 + 24 32 + 25 32 + 26 32 + 27 32 + 28 33 + 2c 34 + 2e 34 + 32 35 + 33 32 + 34 32 + 35 39 + 36 39 + 37 39 + 38 39 + } + + method 'test4 (I)I' { + 0 43 + 1 43 + 2 47 + 3 47 + 4 47 + 6 47 + 7 45 + 9 45 + a 47 + b 47 + c 47 + d 47 + f 47 + 10 47 + 11 47 + 12 47 + 13 47 + 14 47 + 15 47 + 16 47 + 17 47 + 18 47 + 19 47 + 1a 47 + 1b 47 + 1c 47 + 1d 47 + 1e 47 + 1f 47 + 20 47 + 21 47 + 22 47 + 23 47 + 24 47 + 25 47 + 26 47 + 27 47 + 28 47 + 29 47 + 2a 47 + 2b 47 + 2c 48 + 30 51 + 32 51 + 36 53 + 37 47 + 38 47 + } +} + +Lines mapping: +5 <-> 5 +6 <-> 8 +7 <-> 9 +8 <-> 10 +9 <-> 11 +14 <-> 17 +15 <-> 20 +16 <-> 21 +17 <-> 22 +18 <-> 23 +23 <-> 28 +24 <-> 30 +25 <-> 33 +26 <-> 34 +27 <-> 35 +28 <-> 36 +31 <-> 40 +36 <-> 44 +37 <-> 48 +38 <-> 49 +39 <-> 52 +40 <-> 54 diff --git a/testData/src/java11/pkg/TestStringConcatObjectAppend.java b/testData/src/java11/pkg/TestStringConcatObjectAppend.java new file mode 100644 index 0000000000..709f73b05a --- /dev/null +++ b/testData/src/java11/pkg/TestStringConcatObjectAppend.java @@ -0,0 +1,19 @@ +package pkg; + +import java.util.Vector; + +public class TestStringConcatObjectAppend { + public static void store(Vector values) { + String text = ""; + for (int i = 0; i < values.size(); i++) { + text = text + values.elementAt(i) + ";"; + } + sink(text); + sink(String.valueOf(text)); + } + + + + private static void sink(String value) { + } +} \ No newline at end of file diff --git a/testData/src/java16/pkg/TestSwitchExpressionAssignmentOrder.java b/testData/src/java16/pkg/TestSwitchExpressionAssignmentOrder.java new file mode 100644 index 0000000000..f78b951cbb --- /dev/null +++ b/testData/src/java16/pkg/TestSwitchExpressionAssignmentOrder.java @@ -0,0 +1,43 @@ +package pkg; + +public class TestSwitchExpressionAssignmentOrder { + public int test1(int i1) { + int v = 5; + return v + (v = test1(i1)) + switch (v) { + case 0 -> 1; + case 1 -> 2; + default -> 0; + }; + } + + public int test2(int i1) { + int v = 5; + return v + (v = i1) + switch (v) { + case 0 -> 1; + case 1 -> 2; + default -> 0; + }; + } + + public int test3(int i1) { + int v = 5, o = 3; + if (i1 > 0) { + o = v + (v = i1) + switch (v) { + case 0 -> 1; + case 1 -> v = 2; + default -> 0; + }; + } + return v - 3; + } + + + public int test4(int i1) { + int v = 5, o; + return (i1 += v) + (o = i1) + switch (v += i1) { + case 0 -> o; + case 1 -> v = 2; + default -> 0; + }; + } +} diff --git a/testData/src/java25/pkg/TestStringConcatObjectAppendJ25.java b/testData/src/java25/pkg/TestStringConcatObjectAppendJ25.java new file mode 100644 index 0000000000..e523679e3f --- /dev/null +++ b/testData/src/java25/pkg/TestStringConcatObjectAppendJ25.java @@ -0,0 +1,19 @@ +package pkg; + +import java.util.Vector; + +public class TestStringConcatObjectAppendJ25 { + public static void store(Vector values) { + String text = ""; + for (int i = 0; i < values.size(); i++) { + text = text + values.elementAt(i) + ";"; + } + sink(text); + sink(String.valueOf(text)); + } + + + + private static void sink(String value) { + } +} \ No newline at end of file diff --git a/testData/src/java8/pkg/TestArrayArg.java b/testData/src/java8/pkg/TestArrayArg.java index 46f8a4645c..aee3f5110d 100644 --- a/testData/src/java8/pkg/TestArrayArg.java +++ b/testData/src/java8/pkg/TestArrayArg.java @@ -56,6 +56,14 @@ public static void test5_() { overloaded2((Object[]) null); } + public static void test5b(Object[] object) { + overloaded2((Object) object); + } + + public static void test5b_(Object object) { + overloaded2((Object[]) object); + } + public static void test6() { overloaded3(null, 1); } diff --git a/testData/src/java8/pkg/TestDanglingBoxingCall.java b/testData/src/java8/pkg/TestDanglingBoxingCall.java index 3b19817043..41857f2f09 100644 --- a/testData/src/java8/pkg/TestDanglingBoxingCall.java +++ b/testData/src/java8/pkg/TestDanglingBoxingCall.java @@ -10,4 +10,28 @@ public void test(int x) { Float.valueOf(0.9f); } + + public static void consume(Integer value) { + value.intValue(); + } + + public static void consumeWithBox(Object value) { + ((Integer)value).intValue(); + } + + public static void consumeWithMath(Integer value) { + ((Integer)(value + 5)).intValue(); + } + + public static void consumeReverse(Integer value) { + Integer.valueOf(value); + } + + public static void consumeReverseMath(Integer value) { + Integer.valueOf(value + 5); + } + + public static void consumeReverseAndBack(Integer value) { + Integer.valueOf(value).intValue(); + } } diff --git a/testData/src/java8/pkg/TestForEachInSwitch.java b/testData/src/java8/pkg/TestForEachInSwitch.java new file mode 100644 index 0000000000..7da9e37dc4 --- /dev/null +++ b/testData/src/java8/pkg/TestForEachInSwitch.java @@ -0,0 +1,54 @@ +package pkg; + +import java.util.ArrayList; +import java.util.HashSet; + +public class TestForEachInSwitch { + /** + * Reported by nitram84 (issue #543) + */ + private static final int GUEST_CHECKOUT = 1; + private static final int REGISTERED_USER = 2; + private static final int SUBSCRIPTION_RENEWAL = 3; + private static final int EXPRESS_DELIVERY = 4; + private static final int INTERNATIONAL_SHIPPING = 5; + + public void processTransactionDetails(final int status, final ArrayList batch) { + for (final OrderData transaction : batch) { + switch (status) { + case GUEST_CHECKOUT: + case REGISTERED_USER: { + final HashSet items = new HashSet<>(); + for (final ProductItem item : items) { + updateInventoryLog(item); + } + break; + } + case SUBSCRIPTION_RENEWAL: { + for (final ProductItem item : transaction.getPurchasedItems()) { + updateInventoryLog(item); + } + } + case EXPRESS_DELIVERY: + + + case INTERNATIONAL_SHIPPING: { + for (final ProductItem item : transaction.getPurchasedItems()) { + updateInventoryLog(item); + } + } + } + } + } + + private void updateInventoryLog(final ProductItem item) {} + + static class ProductItem { + } + + static class OrderData { + public ProductItem[] getPurchasedItems() { + return null; + } + } +} diff --git a/testData/src/java8/pkg/TestSharedVarIndex.java b/testData/src/java8/pkg/TestSharedVarIndex.java index 9ef46055e8..714c5f899a 100644 --- a/testData/src/java8/pkg/TestSharedVarIndex.java +++ b/testData/src/java8/pkg/TestSharedVarIndex.java @@ -11,6 +11,32 @@ public void StringArrayVsString(){ String b = "lol"; } + public static int ObjectVsInt(Object object, int value) { + { + Object alias = object; + alias.hashCode(); + } + { + int alias = 0; + int result = alias + value; + return result; + } + } + public static void ObjectVsInt2(int value) { + { + Object alias = null; + } + { + int alias = value; + switch (alias) { + case 1: + return; + default: + return; + } + } + } + public void lambda(List l) { { int i = 0; From 4d78a9b9a968a57ae63d1f93edcdb30252f2e37a Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 9 May 2026 18:18:53 +0200 Subject: [PATCH 04/29] Add missing test files --- testData/results/pkg/TestArrayArg.dec | 108 ++++++++++----- .../results/pkg/TestDanglingBoxingCall.dec | 109 +++++++++++++++ testData/results/pkg/TestSharedVarIndex.dec | 130 ++++++++++++++---- 3 files changed, 280 insertions(+), 67 deletions(-) diff --git a/testData/results/pkg/TestArrayArg.dec b/testData/results/pkg/TestArrayArg.dec index 89ce09bd46..f8c6ed4787 100644 --- a/testData/results/pkg/TestArrayArg.dec +++ b/testData/results/pkg/TestArrayArg.dec @@ -56,45 +56,53 @@ public class TestArrayArg { overloaded2((Object[])null);// 56 }// 57 - public static void test6() { - overloaded3(null, 1);// 60 + public static void test5b(Object[] object) { + overloaded2(object);// 60 }// 61 - public static void test6_() { - overloaded3(null, "s");// 64 + public static void test5b_(Object object) { + overloaded2((Object[])object);// 64 }// 65 - private static void overloaded(Object o) { - System.out.println("non-variadic");// 68 + public static void test6() { + overloaded3(null, 1);// 68 }// 69 - private static void overloaded(Object... o) { - System.out.println("variadic");// 72 + public static void test6_() { + overloaded3(null, "s");// 72 }// 73 - private static void overloaded1(String s) { + private static void overloaded(Object o) { System.out.println("non-variadic");// 76 }// 77 - private static void overloaded1(String... s) { + private static void overloaded(Object... o) { System.out.println("variadic");// 80 }// 81 - private static void overloaded2(Object o) { - System.out.println("non-array");// 84 + private static void overloaded1(String s) { + System.out.println("non-variadic");// 84 }// 85 - private static void overloaded2(Object[] o) { - System.out.println("array");// 88 + private static void overloaded1(String... s) { + System.out.println("variadic");// 88 }// 89 - private static void overloaded3(Object o, Number n) { + private static void overloaded2(Object o) { System.out.println("non-array");// 92 }// 93 - private static void overloaded3(String s, String s2) { - System.out.println("non-array");// 96 + private static void overloaded2(Object[] o) { + System.out.println("array");// 96 }// 97 + + private static void overloaded3(Object o, Number n) { + System.out.println("non-array");// 100 + }// 101 + + private static void overloaded3(String s, String s2) { + System.out.println("non-array");// 104 + }// 105 } class 'pkg/TestArrayArg' { @@ -222,29 +230,29 @@ class 'pkg/TestArrayArg' { 7 56 } - method 'test6 ()V' { + method 'test5b ([Ljava/lang/Object;)V' { 0 59 1 59 2 59 3 59 - 4 59 - 5 59 - 6 59 - 7 59 - 8 60 + 4 60 } - method 'test6_ ()V' { + method 'test5b_ (Ljava/lang/Object;)V' { 0 63 1 63 2 63 3 63 4 63 5 63 - 6 64 + 6 63 + 7 63 + 8 63 + 9 63 + a 64 } - method 'overloaded (Ljava/lang/Object;)V' { + method 'test6 ()V' { 0 67 1 67 2 67 @@ -256,19 +264,17 @@ class 'pkg/TestArrayArg' { 8 68 } - method 'overloaded ([Ljava/lang/Object;)V' { + method 'test6_ ()V' { 0 71 1 71 2 71 3 71 4 71 5 71 - 6 71 - 7 71 - 8 72 + 6 72 } - method 'overloaded1 (Ljava/lang/String;)V' { + method 'overloaded (Ljava/lang/Object;)V' { 0 75 1 75 2 75 @@ -280,7 +286,7 @@ class 'pkg/TestArrayArg' { 8 76 } - method 'overloaded1 ([Ljava/lang/String;)V' { + method 'overloaded ([Ljava/lang/Object;)V' { 0 79 1 79 2 79 @@ -292,7 +298,7 @@ class 'pkg/TestArrayArg' { 8 80 } - method 'overloaded2 (Ljava/lang/Object;)V' { + method 'overloaded1 (Ljava/lang/String;)V' { 0 83 1 83 2 83 @@ -304,7 +310,7 @@ class 'pkg/TestArrayArg' { 8 84 } - method 'overloaded2 ([Ljava/lang/Object;)V' { + method 'overloaded1 ([Ljava/lang/String;)V' { 0 87 1 87 2 87 @@ -316,7 +322,7 @@ class 'pkg/TestArrayArg' { 8 88 } - method 'overloaded3 (Ljava/lang/Object;Ljava/lang/Number;)V' { + method 'overloaded2 (Ljava/lang/Object;)V' { 0 91 1 91 2 91 @@ -328,7 +334,7 @@ class 'pkg/TestArrayArg' { 8 92 } - method 'overloaded3 (Ljava/lang/String;Ljava/lang/String;)V' { + method 'overloaded2 ([Ljava/lang/Object;)V' { 0 95 1 95 2 95 @@ -339,6 +345,30 @@ class 'pkg/TestArrayArg' { 7 95 8 96 } + + method 'overloaded3 (Ljava/lang/Object;Ljava/lang/Number;)V' { + 0 99 + 1 99 + 2 99 + 3 99 + 4 99 + 5 99 + 6 99 + 7 99 + 8 100 + } + + method 'overloaded3 (Ljava/lang/String;Ljava/lang/String;)V' { + 0 103 + 1 103 + 2 103 + 3 103 + 4 103 + 5 103 + 6 103 + 7 103 + 8 104 + } } Lines mapping: @@ -388,4 +418,8 @@ Lines mapping: 92 <-> 92 93 <-> 93 96 <-> 96 -97 <-> 97 \ No newline at end of file +97 <-> 97 +100 <-> 100 +101 <-> 101 +104 <-> 104 +105 <-> 105 diff --git a/testData/results/pkg/TestDanglingBoxingCall.dec b/testData/results/pkg/TestDanglingBoxingCall.dec index 4be49c9c9e..96a746feea 100644 --- a/testData/results/pkg/TestDanglingBoxingCall.dec +++ b/testData/results/pkg/TestDanglingBoxingCall.dec @@ -10,6 +10,30 @@ public class TestDanglingBoxingCall { Float.valueOf(0.9F);// 11 }// 12 + + public static void consume(Integer value) { + value;// 15 + }// 16 + + public static void consumeWithBox(Object value) { + (Integer)value;// 19 + }// 20 + + public static void consumeWithMath(Integer value) { + Integer.valueOf(value + 5);// 23 + }// 24 + + public static void consumeReverse(Integer value) { + Integer.valueOf(value);// 27 + }// 28 + + public static void consumeReverseMath(Integer value) { + Integer.valueOf(value + 5);// 31 + }// 32 + + public static void consumeReverseAndBack(Integer value) { + Integer.valueOf(value);// 35 + }// 36 } class 'pkg/TestDanglingBoxingCall' { @@ -39,6 +63,79 @@ class 'pkg/TestDanglingBoxingCall' { 1b 10 1d 11 } + + method 'consume (Ljava/lang/Integer;)V' { + 0 14 + 1 14 + 2 14 + 3 14 + 5 15 + } + + method 'consumeWithBox (Ljava/lang/Object;)V' { + 0 18 + 1 18 + 2 18 + 3 18 + 4 18 + 5 18 + 6 18 + 8 19 + } + + method 'consumeWithMath (Ljava/lang/Integer;)V' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + 7 22 + 8 22 + 9 22 + a 22 + b 22 + d 23 + } + + method 'consumeReverse (Ljava/lang/Integer;)V' { + 0 26 + 1 26 + 2 26 + 3 26 + 4 26 + 5 26 + 6 26 + 8 27 + } + + method 'consumeReverseMath (Ljava/lang/Integer;)V' { + 0 30 + 1 30 + 2 30 + 3 30 + 4 30 + 5 30 + 6 30 + 7 30 + 8 30 + a 31 + } + + method 'consumeReverseAndBack (Ljava/lang/Integer;)V' { + 0 34 + 1 34 + 2 34 + 3 34 + 4 34 + 5 34 + 6 34 + 7 34 + 8 34 + 9 34 + b 35 + } } Lines mapping: @@ -47,3 +144,15 @@ Lines mapping: 8 <-> 8 11 <-> 11 12 <-> 12 +15 <-> 15 +16 <-> 16 +19 <-> 19 +20 <-> 20 +23 <-> 23 +24 <-> 24 +27 <-> 27 +28 <-> 28 +31 <-> 31 +32 <-> 32 +35 <-> 35 +36 <-> 36 diff --git a/testData/results/pkg/TestSharedVarIndex.dec b/testData/results/pkg/TestSharedVarIndex.dec index 6995e1e04c..8cbc0f2a62 100644 --- a/testData/results/pkg/TestSharedVarIndex.dec +++ b/testData/results/pkg/TestSharedVarIndex.dec @@ -8,11 +8,27 @@ public class TestSharedVarIndex { String bx = "lol";// 11 }// 12 + public static int ObjectVsInt(Object object, int value) { + Object alias = object;// 16 + alias.hashCode();// 17 + alias = 0;// 20 + return alias + value;// 21 22 + } + + public static void ObjectVsInt2(int value) { + int alias = null;// 27 + alias = value;// 30 + switch (alias) {// 31 + case 1: + return;// 33 + } + }// 35 + public void lambda(List l) { - int i = 0;// 16 - System.out.println(i);// 17 - l.forEach(ix -> System.out.println(ix + 1));// 19 - }// 20 + int i = 0;// 42 + System.out.println(i);// 43 + l.forEach(ix -> System.out.println(ix + 1));// 45 + }// 46 } class 'pkg/TestSharedVarIndex' { @@ -25,39 +41,83 @@ class 'pkg/TestSharedVarIndex' { 8 8 } - method 'lambda (Ljava/util/List;)V' { + method 'ObjectVsInt (Ljava/lang/Object;I)I' { 0 11 1 11 2 12 3 12 4 12 5 12 - 6 12 - 7 12 - 8 12 - 9 13 - f 13 - 10 13 - 11 13 - 12 13 - 13 13 - 14 14 + 7 13 + 8 13 + 9 14 + a 14 + b 14 + e 14 + } + + method 'ObjectVsInt2 (I)V' { + 0 18 + 1 18 + 2 19 + 3 19 + 4 20 + 5 20 + 6 20 + 7 20 + 8 20 + 9 20 + a 20 + b 20 + c 20 + d 20 + e 20 + f 20 + 10 20 + 11 20 + 12 20 + 13 20 + 14 20 + 15 20 + 16 20 + 17 20 + 18 22 + 19 24 + } + + method 'lambda (Ljava/util/List;)V' { + 0 27 + 1 27 + 2 28 + 3 28 + 4 28 + 5 28 + 6 28 + 7 28 + 8 28 + 9 29 + f 29 + 10 29 + 11 29 + 12 29 + 13 29 + 14 30 } method 'lambda$lambda$0 (Ljava/lang/Integer;)V' { - 0 13 - 1 13 - 2 13 - 3 13 - 4 13 - 5 13 - 6 13 - 7 13 - 8 13 - 9 13 - a 13 - b 13 - c 13 + 0 29 + 1 29 + 2 29 + 3 29 + 4 29 + 5 29 + 6 29 + 7 29 + 8 29 + 9 29 + a 29 + b 29 + c 29 } } @@ -67,5 +127,15 @@ Lines mapping: 12 <-> 9 16 <-> 12 17 <-> 13 -19 <-> 14 -20 <-> 15 +20 <-> 14 +21 <-> 15 +22 <-> 15 +27 <-> 19 +30 <-> 20 +31 <-> 21 +33 <-> 23 +35 <-> 25 +42 <-> 28 +43 <-> 29 +45 <-> 30 +46 <-> 31 From 56cfb3037fe7487df033a2de3b34a75ba111593e Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 9 May 2026 12:24:52 -0400 Subject: [PATCH 05/29] Put concat test in nodebug --- .../java/decompiler/SingleClassesTest.java | 2 +- .../pkg/TestStringConcatObjectAppend.dec | 77 +++++++++---------- .../pkg/TestStringConcatObjectAppend.java | 0 3 files changed, 36 insertions(+), 43 deletions(-) rename testData/src/{java11 => java8nodebug}/pkg/TestStringConcatObjectAppend.java (100%) diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 115f55669f..b55d27e2fa 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -840,7 +840,7 @@ private void registerDefault() { register(JAVA_16, "TestSwitchExpressionIfBlocks"); // TODO: String type info is lost; does not recompile; issue #573 - register(JAVA_11, "TestStringConcatObjectAppend"); + register(JAVA_8_NODEBUG, "TestStringConcatObjectAppend"); register(JAVA_25, "TestStringConcatObjectAppendJ25"); } diff --git a/testData/results/pkg/TestStringConcatObjectAppend.dec b/testData/results/pkg/TestStringConcatObjectAppend.dec index ec680fbae3..2488934b25 100644 --- a/testData/results/pkg/TestStringConcatObjectAppend.dec +++ b/testData/results/pkg/TestStringConcatObjectAppend.dec @@ -3,19 +3,19 @@ package pkg; import java.util.Vector; public class TestStringConcatObjectAppend { - public static void store(Vector values) { - String text = "";// 7 + public static void store(Vector var0) { + Object var1 = ""; - for (int i = 0; i < values.size(); i++) {// 8 - text = text + values.elementAt(i) + ";";// 9 + for (int var2 = 0; var2 < var0.size(); var2++) { + var1 = var1 + var0.elementAt(var2) + ";"; } - sink(text);// 11 - sink(String.valueOf(text));// 12 - }// 13 + sink((String)var1); + sink(String.valueOf(var1)); + } - private static void sink(String value) { - }// 18 + private static void sink(String var0) { + } } class 'pkg/TestStringConcatObjectAppend' { @@ -33,33 +33,33 @@ class 'pkg/TestStringConcatObjectAppend' { a 8 b 8 c 8 - d 9 - e 9 - f 9 - 10 9 - 11 9 - 12 9 - 13 9 14 9 - 15 9 - 16 9 - 17 9 18 9 - 19 8 - 1a 8 - 1b 8 - 1f 12 - 20 12 - 21 12 - 22 12 - 23 13 - 24 13 - 25 13 - 26 13 - 27 13 - 28 13 - 29 13 - 2a 14 + 19 9 + 1a 9 + 1b 9 + 1c 9 + 20 9 + 21 9 + 25 9 + 26 9 + 27 9 + 28 9 + 29 8 + 2a 8 + 2b 8 + 2f 12 + 30 12 + 31 12 + 32 12 + 33 13 + 34 13 + 35 13 + 36 13 + 37 13 + 38 13 + 39 13 + 3a 14 } method 'sink (Ljava/lang/String;)V' { @@ -67,11 +67,4 @@ class 'pkg/TestStringConcatObjectAppend' { } } -Lines mapping: -7 <-> 7 -8 <-> 9 -9 <-> 10 -11 <-> 13 -12 <-> 14 -13 <-> 15 -18 <-> 18 +Lines mapping: \ No newline at end of file diff --git a/testData/src/java11/pkg/TestStringConcatObjectAppend.java b/testData/src/java8nodebug/pkg/TestStringConcatObjectAppend.java similarity index 100% rename from testData/src/java11/pkg/TestStringConcatObjectAppend.java rename to testData/src/java8nodebug/pkg/TestStringConcatObjectAppend.java From 5ba9f739bc5c25a87ae7adeb1487776fd10078e9 Mon Sep 17 00:00:00 2001 From: Kroppeb <7889478+Kroppeb@users.noreply.github.com> Date: Sun, 10 May 2026 16:29:36 +0200 Subject: [PATCH 06/29] Reuse existing logic to fix wrong ppmm inline match (#570) * Reuse existing logic to fix wrong ppmm inline match Fixes #569 * Update dec file * Improve pmm inlining more --- .../vineflower/kotlin/stat/KIfStatement.java | 1 - .../decompiler/main/rels/MethodProcessor.java | 5 - .../modules/decompiler/IfHelper.java | 2 +- .../modules/decompiler/PPandMMHelper.java | 119 ++--- .../decompiler/SimplifyExprentsHelper.java | 35 +- .../decompiler/StackVarsProcessor.java | 2 +- .../modules/decompiler/stats/IfStatement.java | 10 - testData/results/pkg/TestIfLoop.dec | 443 +++++++++--------- testData/results/pkg/TestLoopBreak.dec | 51 +- testData/results/pkg/TestPPMM.dec | 427 ++++++++++++++++- testData/results/pkg/TestWhileTernary9.dec | 229 +++++---- testData/src/java8/pkg/TestPPMM.java | 255 ++++++---- 12 files changed, 985 insertions(+), 594 deletions(-) diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/stat/KIfStatement.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/stat/KIfStatement.java index a0ad29e662..79b5368d19 100644 --- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/stat/KIfStatement.java +++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/stat/KIfStatement.java @@ -35,7 +35,6 @@ public KIfStatement(IfStatement statement) { setElseEdge(statement.getElseEdge()); setNegated(statement.isNegated()); setPatternMatched(statement.isPatternMatched()); - setHasPPMM(statement.hasPPMM()); getHeadexprentList().set(0, statement.getHeadexprent()); } diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java index 4a8f19754e..ccee225600 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java @@ -244,11 +244,6 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe pctx = new PassContext(root, graph, mt, cl, varProc, decompileRecord); - // Inline ppi/mmi that we may have missed - if (PPandMMHelper.inlinePPIandMMIIf(root)) { - decompileRecord.add("InlinePPIandMMI", root); - } - // Process invokedynamic string concat if (cl.getVersion().hasIndyStringConcat()) { ConcatenationHelper.simplifyStringConcat(root); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java index a5ab14deca..7228bc66ac 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java @@ -143,7 +143,7 @@ private static boolean collapseIfIf(IfNode rtnode) { Statement ifinner = ifbranch.innerNode.value; // Don't move $assertionsDisabled into the right hand side of if statements, which could create incorrect code. - if (ifchild.getFirst().getExprents().isEmpty() && !ifchild.hasPPMM() && !hasAssertField(ifchild.getHeadexprent())) { + if (ifchild.getFirst().getExprents().isEmpty() && !hasAssertField(ifchild.getHeadexprent())) { ifparent.getIfEdge().remove(); ifchild.getFirstSuccessor().remove(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java index 432ece1a5e..891609d837 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java @@ -5,6 +5,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent.FunctionType; import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; import org.jetbrains.java.decompiler.modules.decompiler.flow.DirectEdge; import org.jetbrains.java.decompiler.modules.decompiler.flow.DirectEdgeType; @@ -18,12 +19,14 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.Pair; -import java.util.Deque; import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import static org.jetbrains.java.decompiler.modules.decompiler.SimplifyExprentsHelper.findFirstValidUsage; + public class PPandMMHelper { private boolean exprentReplaced; @@ -35,7 +38,6 @@ public PPandMMHelper(VarProcessor varProc) { } public boolean findPPandMM(RootStatement root) { - FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); this.dgraph = flatthelper.buildDirectGraph(root); @@ -121,13 +123,13 @@ private Exprent processExprentRecursive(Exprent exprent) { } } - if (func.getFuncType() == FunctionExprent.FunctionType.ADD || - func.getFuncType() == FunctionExprent.FunctionType.SUB) { + if (func.getFuncType() == FunctionType.ADD || + func.getFuncType() == FunctionType.SUB) { Exprent econd = func.getLstOperands().get(0); Exprent econst = func.getLstOperands().get(1); if (!(econst instanceof ConstExprent) && econd instanceof ConstExprent && - func.getFuncType() == FunctionExprent.FunctionType.ADD) { + func.getFuncType() == FunctionType.ADD) { econd = econst; econst = func.getLstOperands().get(0); } @@ -138,7 +140,7 @@ private Exprent processExprentRecursive(Exprent exprent) { VarType condtype = left.getExprType(); if (exprsEqual(left, econd) && (midlayer == null || midlayer.equals(condtype))) { FunctionExprent ret = new FunctionExprent( - func.getFuncType() == FunctionExprent.FunctionType.ADD ? FunctionExprent.FunctionType.PPI : FunctionExprent.FunctionType.MMI, + func.getFuncType() == FunctionType.ADD ? FunctionType.PPI : FunctionType.MMI, econd, func.bytecode); ret.setImplicitType(condtype); @@ -233,91 +235,26 @@ private static boolean inlinePPIandMMIIfRec(Statement stat) { if (stat.getExprents() != null && !stat.getExprents().isEmpty()) { IfStatement destination = findIfSuccessor(stat); - if (destination != null) { - // Last exprent - Exprent expr = stat.getExprents().get(stat.getExprents().size() - 1); - if (expr instanceof FunctionExprent) { - FunctionExprent func = (FunctionExprent)expr; - - if (func.getFuncType() == FunctionExprent.FunctionType.PPI || func.getFuncType() == FunctionExprent.FunctionType.MMI) { - Exprent inner = func.getLstOperands().get(0); - - if (inner instanceof VarExprent) { - Exprent ifExpr = destination.getHeadexprent().getCondition(); - - if (ifExpr instanceof FunctionExprent) { - FunctionExprent ifFunc = (FunctionExprent)ifExpr; - - while (ifFunc.getFuncType() == FunctionExprent.FunctionType.BOOL_NOT) { - Exprent innerFunc = ifFunc.getLstOperands().get(0); - - if (innerFunc instanceof FunctionExprent) { - ifFunc = (FunctionExprent)innerFunc; - } else { - break; - } - } - - // Search for usages of variable - boolean found = false; - VarExprent old = null; - for (Exprent ex : ifFunc.getAllExprents(true)) { - if (ex instanceof VarExprent) { - VarExprent var = (VarExprent)ex; - if (var.getIndex() == ((VarExprent)inner).getIndex()) { - // Found variable to replace - - // Fail if we've already seen this variable! - if (found) { - return false; - } - - // Store the var we want to replace - old = var; - found = true; - } - } else if (ex instanceof FunctionExprent) { - FunctionExprent funcEx = (FunctionExprent)ex; - - if (funcEx.getFuncType() == FunctionExprent.FunctionType.BOOLEAN_AND || funcEx.getFuncType() == FunctionExprent.FunctionType.BOOLEAN_OR) { - // Cannot yet handle these as we aren't able to decompose a condition into parts that are always run (not short-circuited) and parts that are - // FIXME: handle this case - return false; - } - } - } - - if (found) { - Deque stack = new LinkedList<>(); - stack.push(ifFunc); - - while (!stack.isEmpty()) { - Exprent exprent = stack.pop(); - - for (Exprent ex : exprent.getAllExprents()) { - if (ex == old) { - // Replace variable with ppi/mmi - exprent.replaceExprent(old, expr); - expr.addBytecodeOffsets(old.bytecode); - - // No more itr - stack.clear(); - break; - } - - stack.push(ex); - } - } - - // Remove old expr - stat.getExprents().remove(expr); - res = true; - - destination.setHasPPMM(true); - } - } - } - } + if (destination != null && + // Last exprent is a PPI/MMI on a var + stat.getExprents().get(stat.getExprents().size() - 1) instanceof FunctionExprent func && + (func.getFuncType() == FunctionType.PPI || func.getFuncType() == FunctionType.MMI) && + func.getLstOperands().get(0) instanceof VarExprent inner) { + + + // Search for usages of variable + + // parent, var + Pair usage = findFirstValidUsage(inner, destination.getHeadexprent().getCondition()); + + if (usage != null) { + var parent = usage.a; + var old = usage.b; + // Replace variable with ppi/mmi + parent.replaceExprent(old, func); + func.addBytecodeOffsets(old.bytecode); + stat.getExprents().remove(stat.getExprents().size() - 1); // remove the original + res = true; } } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java index c9dd7f68e4..c414ccbd96 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.modules.decompiler; +import org.jetbrains.annotations.Nullable; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; @@ -632,7 +633,8 @@ private static boolean isIPPorIMM2(Exprent first, Exprent second) { // // array[++i] = 2; // - // While this helps simplify stack vars, it also has can potentially make invalid code! When evaluating ppmm correctness, this is a good place to start. + // While this helps simplify stack vars, it also has can potentially make invalid code! + // When evaluating ppmm correctness, this is a good place to start. // TODO: fernflower preference? private static boolean inlinePPIAndMMI(Exprent expr, Exprent next) { if (expr instanceof FunctionExprent func && @@ -660,7 +662,7 @@ private static boolean inlinePPIAndMMI(Exprent expr, Exprent next) { // Try to find the first valid usage of a variable for PPMM inlining. // Returns Pair{parent exprent, variable exprent to replace} - private static Pair findFirstValidUsage(VarExprent match, Exprent next) { + static @Nullable Pair findFirstValidUsage(VarExprent match, Exprent next) { List stack = new ArrayList<>(); List parent = new ArrayList<>(); stack.add(next); @@ -674,26 +676,31 @@ private static Pair findFirstValidUsage(VarExprent match, E if (parentExpr != null && expr instanceof VarExprent ve && - ve.getIndex() == match.getIndex() && - ve.getVersion() == match.getVersion()) { - return Pair.of(parentExpr, ve); + ve.getIndex() == match.getIndex()) { + if (ve.getVersion() == match.getVersion()) { + return Pair.of(parentExpr, ve); + } else { + // wrong var index, something happened + ValidationHelper.assertTrue(false, "Unexpected var mutation"); + return null; + } } if (expr instanceof FunctionExprent func) { // Don't inline ppmm into more ppmm - if (isPPMM(func)) { - return null; - } - - // Don't consider || or && - if (func.getFuncType() == FunctionType.BOOLEAN_OR || func.getFuncType() == FunctionType.BOOLEAN_AND) { + if (isPPMM(func) && func.getLstOperands().get(0) instanceof VarExprent ve && ve.getIndex() == match.getIndex()) { return null; } - // Don't consider ternaries - if (func.getFuncType() == FunctionType.TERNARY) { - return null; + // Only consider first argument for `||`, `&&` and ternary. + if (func.getFuncType() == FunctionType.BOOLEAN_OR || func.getFuncType() == FunctionType.BOOLEAN_AND || func.getFuncType() == FunctionType.TERNARY) { + // Var might be read in RHS. + stack.clear(); + parent.clear(); + stack.add(func.getLstOperands().get(0)); + parent.add(expr); + continue; } // Subtraction and division make it hard to deduce which variable is used, especially without SSAU, so cancel if we find diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java index 159882deea..89b4d7f977 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java @@ -53,7 +53,7 @@ public static void simplifyStackVars(RootStatement root, StructMethod mt, Struct SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); ssa.splitVariables(root, mt); - while (SimplifyExprentsHelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl, first)) { + while (SimplifyExprentsHelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl, first) || PPandMMHelper.inlinePPIandMMIIf(root)) { ValidationHelper.validateStatement(root); found = true; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java index 54911c9071..0cd6f91bf5 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java @@ -38,8 +38,6 @@ public class IfStatement extends Statement { private boolean negated = false; private boolean patternMatched = false; - private boolean hasPPMM = false; - private final List headexprent = new ArrayList<>(1); // contains IfExprent // ***************************************************************************** @@ -417,14 +415,6 @@ public void setPatternMatched(boolean patternMatched) { this.patternMatched = patternMatched; } - public boolean hasPPMM() { - return hasPPMM; - } - - public void setHasPPMM(boolean hasPPMM) { - this.hasPPMM = hasPPMM; - } - @Override public List getImplicitlyDefinedVars() { List vars = new ArrayList<>(); diff --git a/testData/results/pkg/TestIfLoop.dec b/testData/results/pkg/TestIfLoop.dec index c9cb49096b..eab6b76bad 100644 --- a/testData/results/pkg/TestIfLoop.dec +++ b/testData/results/pkg/TestIfLoop.dec @@ -7,7 +7,8 @@ public class TestIfLoop { public int testCompoundCondition(int i, int j) { while (i > 0 && j < 3) {// 8 if (j < 0) {// 9 - if (i > 3 && --j == -2) {// 10 12 13 + j--;// 10 + if (i > 3 && j == -2) {// 12 13 j = 1;// 14 } } @@ -81,204 +82,204 @@ class 'pkg/TestIfLoop' { d 9 e 9 f 9 - 10 9 - 11 9 - 12 9 - 13 9 - 14 9 - 15 9 - 16 9 - 17 9 - 18 9 - 19 9 - 1a 9 - 1b 10 - 1c 10 - 1d 14 - 1e 14 - 1f 14 - 20 14 - 21 14 - 22 14 - 23 15 - 24 15 - 25 15 - 27 15 - 28 19 - 29 19 + 10 10 + 11 10 + 12 10 + 13 10 + 14 10 + 15 10 + 16 10 + 17 10 + 18 10 + 19 10 + 1a 10 + 1b 11 + 1c 11 + 1d 15 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 15 + 23 16 + 24 16 + 25 16 + 27 16 + 28 20 + 29 20 } method 'testCollection (Ljava/util/List;)Ljava/lang/Object;' { - 0 23 - 1 23 - 2 23 - 3 23 - 4 23 - 5 23 - 6 23 - 7 23 - 8 23 - 9 24 - a 24 - b 24 - c 24 - d 24 - e 24 - f 24 - 10 24 - 11 24 - 12 24 - 13 28 - 14 28 - 15 28 - 16 28 - 17 28 - 18 28 - 19 28 - 1e 25 - 1f 25 - 20 25 - 21 25 - 22 25 - 23 25 - 24 25 - 25 25 - 26 31 - 27 31 + 0 24 + 1 24 + 2 24 + 3 24 + 4 24 + 5 24 + 6 24 + 7 24 + 8 24 + 9 25 + a 25 + b 25 + c 25 + d 25 + e 25 + f 25 + 10 25 + 11 25 + 12 25 + 13 29 + 14 29 + 15 29 + 16 29 + 17 29 + 18 29 + 19 29 + 1e 26 + 1f 26 + 20 26 + 21 26 + 22 26 + 23 26 + 24 26 + 25 26 + 26 32 + 27 32 } method 'testCompound2 (IILjava/util/Random;)V' { - 0 35 - 1 35 - 2 35 - 3 35 - 4 35 - 5 35 - 6 35 - 7 35 - 8 35 - 9 35 - a 35 - b 35 - c 35 - d 35 - e 35 - f 35 - 10 37 - 11 37 - 12 37 - 13 37 - 14 37 - 15 37 - 16 37 - 17 37 - 18 37 - 19 37 - 1a 37 - 1b 37 - 1c 37 - 1d 37 - 1e 37 - 1f 37 - 20 37 - 21 37 - 22 37 - 23 37 - 24 37 - 25 37 - 26 37 - 27 37 - 28 37 - 29 37 - 2a 37 - 2b 37 - 2c 37 - 2d 37 - 2e 37 - 2f 37 - 30 37 - 31 37 - 32 37 - 33 37 - 35 38 - 36 38 - 37 38 - 38 38 - 39 38 - 3a 38 - 3b 38 - 3c 38 - 3d 38 - 3e 38 - 3f 38 - 41 38 - 43 37 - 44 37 - 45 37 - 46 37 - 47 37 - 48 37 - 49 37 - 4a 37 - 4b 37 - 4c 37 - 4d 37 - 4f 37 - 53 40 + 0 36 + 1 36 + 2 36 + 3 36 + 4 36 + 5 36 + 6 36 + 7 36 + 8 36 + 9 36 + a 36 + b 36 + c 36 + d 36 + e 36 + f 36 + 10 38 + 11 38 + 12 38 + 13 38 + 14 38 + 15 38 + 16 38 + 17 38 + 18 38 + 19 38 + 1a 38 + 1b 38 + 1c 38 + 1d 38 + 1e 38 + 1f 38 + 20 38 + 21 38 + 22 38 + 23 38 + 24 38 + 25 38 + 26 38 + 27 38 + 28 38 + 29 38 + 2a 38 + 2b 38 + 2c 38 + 2d 38 + 2e 38 + 2f 38 + 30 38 + 31 38 + 32 38 + 33 38 + 35 39 + 36 39 + 37 39 + 38 39 + 39 39 + 3a 39 + 3b 39 + 3c 39 + 3d 39 + 3e 39 + 3f 39 + 41 39 + 43 38 + 44 38 + 45 38 + 46 38 + 47 38 + 48 38 + 49 38 + 4a 38 + 4b 38 + 4c 38 + 4d 38 + 4f 38 + 53 41 } method 'testElseIf (I)I' { - 0 43 - 1 43 - 2 43 - 3 43 - 4 44 - 5 44 - 6 44 - 7 44 - 8 44 - 9 44 - a 45 - b 45 - c 45 - 10 46 - 11 46 - 12 46 - 13 46 - 14 46 - 15 46 - 16 47 - 17 47 - 18 47 - 1c 48 - 1d 48 - 1e 48 - 1f 48 - 20 48 - 21 48 - 22 49 - 23 49 - 24 49 - 28 50 - 29 50 - 2a 50 - 2b 50 - 2c 50 - 2d 50 - 2f 51 - 31 51 - 35 53 - 36 53 - 37 53 - 38 53 - 39 53 - 3a 53 - 3b 57 - 3c 57 - 3d 57 - 48 54 - 49 61 - 4a 61 + 0 44 + 1 44 + 2 44 + 3 44 + 4 45 + 5 45 + 6 45 + 7 45 + 8 45 + 9 45 + a 46 + b 46 + c 46 + 10 47 + 11 47 + 12 47 + 13 47 + 14 47 + 15 47 + 16 48 + 17 48 + 18 48 + 1c 49 + 1d 49 + 1e 49 + 1f 49 + 20 49 + 21 49 + 22 50 + 23 50 + 24 50 + 28 51 + 29 51 + 2a 51 + 2b 51 + 2c 51 + 2d 51 + 2f 52 + 31 52 + 35 54 + 36 54 + 37 54 + 38 54 + 39 54 + 3a 54 + 3b 58 + 3c 58 + 3d 58 + 48 55 + 49 62 + 4a 62 } } @@ -286,34 +287,34 @@ Lines mapping: 8 <-> 8 9 <-> 9 10 <-> 10 -12 <-> 10 -13 <-> 10 -14 <-> 11 -19 <-> 15 -20 <-> 16 -21 <-> 16 -25 <-> 20 -29 <-> 24 -30 <-> 25 -31 <-> 29 -33 <-> 26 -37 <-> 32 -41 <-> 36 -42 <-> 38 -44 <-> 38 -45 <-> 39 -46 <-> 38 -48 <-> 41 -51 <-> 44 -52 <-> 45 -53 <-> 46 -54 <-> 47 -55 <-> 48 -56 <-> 49 -57 <-> 50 -58 <-> 51 -59 <-> 52 -60 <-> 54 -61 <-> 58 -63 <-> 55 -67 <-> 62 +12 <-> 11 +13 <-> 11 +14 <-> 12 +19 <-> 16 +20 <-> 17 +21 <-> 17 +25 <-> 21 +29 <-> 25 +30 <-> 26 +31 <-> 30 +33 <-> 27 +37 <-> 33 +41 <-> 37 +42 <-> 39 +44 <-> 39 +45 <-> 40 +46 <-> 39 +48 <-> 42 +51 <-> 45 +52 <-> 46 +53 <-> 47 +54 <-> 48 +55 <-> 49 +56 <-> 50 +57 <-> 51 +58 <-> 52 +59 <-> 53 +60 <-> 55 +61 <-> 59 +63 <-> 56 +67 <-> 63 diff --git a/testData/results/pkg/TestLoopBreak.dec b/testData/results/pkg/TestLoopBreak.dec index d820dcfefa..6a1af854fe 100644 --- a/testData/results/pkg/TestLoopBreak.dec +++ b/testData/results/pkg/TestLoopBreak.dec @@ -2,12 +2,8 @@ package pkg; public class TestLoopBreak { public void test(int i) { - while (i > 10) {// 5 - if (++i != 15) {// 6 8 - System.out.println(0);// 12 - continue; - } - break; + while (i > 10 && ++i != 15) {// 5 6 8 + System.out.println(0);// 12 } }// 14 } @@ -20,32 +16,31 @@ class 'pkg/TestLoopBreak' { 3 4 4 4 5 4 - 6 5 - 7 5 - 8 5 - 9 5 - a 5 - b 5 - c 5 - d 5 - e 5 - 12 6 - 13 6 - 14 6 - 15 6 - 16 6 - 17 6 - 18 6 - 19 7 - 1c 11 + 6 4 + 7 4 + 8 4 + 9 4 + a 4 + b 4 + c 4 + d 4 + e 4 + 12 5 + 13 5 + 14 5 + 15 5 + 16 5 + 17 5 + 18 5 + 1c 7 } } Lines mapping: 5 <-> 5 -6 <-> 6 -8 <-> 6 -12 <-> 7 -14 <-> 12 +6 <-> 5 +8 <-> 5 +12 <-> 6 +14 <-> 8 Not mapped: 9 diff --git a/testData/results/pkg/TestPPMM.dec b/testData/results/pkg/TestPPMM.dec index 6523be1f8d..a079185c5f 100644 --- a/testData/results/pkg/TestPPMM.dec +++ b/testData/results/pkg/TestPPMM.dec @@ -115,11 +115,73 @@ public class TestPPMM { t(a);// 133 }// 134 + public void ppiIf(boolean b, int i, int j) { + if (i++ > ++i) {// 137 + System.out.println("i++ > ++i");// 138 + } + + if (b && i++ < 5) {// 140 + System.out.println("b && i++ < 5");// 141 + } + + if (++i < j) {// 143 + System.out.println("++i < j");// 144 + } + + if (--i > ++j) {// 146 147 148 + System.out.println("--i > ++j");// 149 + } + + if (!b || ++i < j) {// 151 + System.out.println("!b || ++i < j");// 152 + } + + j++;// 154 + if (!b && j < i) {// 155 + System.out.println("!b && j < i");// 156 + } + + if ((b ? ++i : ++j) > 0) {// 158 + System.out.println("(b ? ++i : ++j) > 0");// 159 + } + + i++;// 161 + j++;// 162 + if ((b ? i : j) > 0) {// 163 + System.out.println("(b ? i : j) > 0");// 164 + } + + if (++i > j ? b : j > 0) {// 166 + System.out.println("++i > j ? b : j > 0");// 167 + } + + if (++i > j ? b : j > 0) {// 169 170 + System.out.println("++i > j ? b : j > 0");// 171 + } + + if (++i < ++j && (b || i < 5) && ++j > i && b) {// 173 174 + System.out.println("++i < ++j && (b || i < 5) && ++j > i && b");// 175 + } + + i++;// 177 + if ((b && i++ > 0) | i > 0) {// 178 + System.out.println("(b && i++ > 0) | i > 0");// 179 + } + }// 181 + + public void doubleppi2vars() { + int a = 0;// 184 + int b = 0;// 185 + t2(a++, ++b);// 186 + t2(++a, ++b);// 187 188 189 + t2(++a, ++b);// 190 191 192 + }// 193 + private static void t(int x) { - }// 137 + }// 196 private static void t2(int x, int y) { - }// 141 + }// 200 } class 'pkg/TestPPMM' { @@ -510,12 +572,324 @@ class 'pkg/TestPPMM' { 37 115 } + method 'ppiIf (ZII)V' { + 1 118 + 2 118 + 3 118 + 4 118 + 5 118 + 6 118 + 7 118 + 8 118 + 9 118 + a 118 + b 119 + c 119 + d 119 + e 119 + f 119 + 10 119 + 11 119 + 12 119 + 13 122 + 14 122 + 15 122 + 16 122 + 18 122 + 19 122 + 1a 122 + 1b 122 + 1c 122 + 1d 122 + 1e 122 + 1f 123 + 20 123 + 21 123 + 22 123 + 23 123 + 24 123 + 25 123 + 26 123 + 27 126 + 28 126 + 29 126 + 2a 126 + 2b 126 + 2c 126 + 2d 126 + 2e 126 + 2f 127 + 30 127 + 31 127 + 32 127 + 33 127 + 34 127 + 35 127 + 36 127 + 37 130 + 38 130 + 39 130 + 3a 130 + 3b 130 + 3c 130 + 3d 130 + 3e 130 + 3f 130 + 40 130 + 41 130 + 42 131 + 43 131 + 44 131 + 45 131 + 46 131 + 47 131 + 48 131 + 49 131 + 4a 134 + 4b 134 + 4c 134 + 4d 134 + 4e 134 + 4f 134 + 50 134 + 51 134 + 52 134 + 53 134 + 54 134 + 55 134 + 56 135 + 57 135 + 58 135 + 59 135 + 5a 135 + 5b 135 + 5c 135 + 5d 135 + 5e 138 + 5f 138 + 60 138 + 61 139 + 62 139 + 63 139 + 64 139 + 65 139 + 66 139 + 67 139 + 68 139 + 69 139 + 6a 140 + 6b 140 + 6c 140 + 6d 140 + 6e 140 + 6f 140 + 70 140 + 71 140 + 72 143 + 73 143 + 74 143 + 75 143 + 76 143 + 77 143 + 78 143 + 7d 143 + 7e 143 + 7f 143 + 81 143 + 82 143 + 83 143 + 84 144 + 85 144 + 86 144 + 87 144 + 88 144 + 89 144 + 8a 144 + 8b 144 + 8c 147 + 8d 147 + 8e 147 + 8f 148 + 90 148 + 91 148 + 92 149 + 93 149 + 94 149 + 95 149 + 96 149 + 9a 149 + 9b 149 + 9c 149 + 9d 149 + 9e 150 + 9f 150 + a0 150 + a1 150 + a2 150 + a3 150 + a4 150 + a5 150 + a6 153 + a7 153 + a8 153 + a9 153 + aa 153 + ab 153 + ac 153 + ad 153 + ae 153 + af 153 + b0 153 + b1 153 + b5 153 + b6 153 + b7 153 + b8 153 + b9 154 + ba 154 + bb 154 + bc 154 + bd 154 + be 154 + bf 154 + c0 154 + c1 157 + c2 157 + c3 157 + c4 157 + c5 157 + c6 157 + c7 157 + c8 157 + c9 157 + ca 157 + cb 157 + cc 157 + d0 157 + d1 157 + d2 157 + d3 157 + d4 158 + d5 158 + d6 158 + d7 158 + d8 158 + d9 158 + da 158 + db 158 + dc 161 + dd 161 + de 161 + df 161 + e0 161 + e1 161 + e2 161 + e3 161 + e4 161 + e5 161 + e6 161 + e7 161 + e8 161 + e9 161 + ea 161 + eb 161 + ec 161 + ed 161 + ee 161 + ef 161 + f0 161 + f1 161 + f2 161 + f3 161 + f4 161 + f5 161 + f6 161 + f7 161 + f8 161 + f9 161 + fa 161 + fb 161 + fc 162 + fd 162 + fe 162 + ff 162 + 100 162 + 101 162 + 102 162 + 103 162 + 104 165 + 105 165 + 106 165 + 107 166 + 108 166 + 109 166 + 10a 166 + 10c 166 + 10d 166 + 10e 166 + 10f 166 + 110 166 + 111 166 + 117 166 + 118 166 + 119 166 + 11a 166 + 120 166 + 121 166 + 122 166 + 123 166 + 124 167 + 125 167 + 126 167 + 127 167 + 128 167 + 129 167 + 12a 167 + 12b 167 + 12c 169 + } + + method 'doubleppi2vars ()V' { + 0 172 + 1 172 + 2 173 + 3 173 + 5 174 + 6 174 + 7 174 + 8 174 + 9 174 + a 174 + c 174 + d 174 + e 174 + f 175 + 10 175 + 11 175 + 12 175 + 13 175 + 14 175 + 17 175 + 18 175 + 19 175 + 1a 176 + 1b 176 + 1c 176 + 1d 176 + 1e 176 + 1f 176 + 22 176 + 23 176 + 24 176 + 25 177 + } + method 't (I)V' { - 0 118 + 0 180 } method 't2 (II)V' { - 0 121 + 0 183 } } @@ -616,4 +990,47 @@ Lines mapping: 133 <-> 115 134 <-> 116 137 <-> 119 -141 <-> 122 +138 <-> 120 +140 <-> 123 +141 <-> 124 +143 <-> 127 +144 <-> 128 +146 <-> 131 +147 <-> 131 +148 <-> 131 +149 <-> 132 +151 <-> 135 +152 <-> 136 +154 <-> 139 +155 <-> 140 +156 <-> 141 +158 <-> 144 +159 <-> 145 +161 <-> 148 +162 <-> 149 +163 <-> 150 +164 <-> 151 +166 <-> 154 +167 <-> 155 +169 <-> 158 +170 <-> 158 +171 <-> 159 +173 <-> 162 +174 <-> 162 +175 <-> 163 +177 <-> 166 +178 <-> 167 +179 <-> 168 +181 <-> 170 +184 <-> 173 +185 <-> 174 +186 <-> 175 +187 <-> 176 +188 <-> 176 +189 <-> 176 +190 <-> 177 +191 <-> 177 +192 <-> 177 +193 <-> 178 +196 <-> 181 +200 <-> 184 diff --git a/testData/results/pkg/TestWhileTernary9.dec b/testData/results/pkg/TestWhileTernary9.dec index 93b2edebc5..0142d78ee3 100644 --- a/testData/results/pkg/TestWhileTernary9.dec +++ b/testData/results/pkg/TestWhileTernary9.dec @@ -4,10 +4,7 @@ public class TestWhileTernary9 { public void test(boolean condition, boolean a, boolean b) { int i = 0;// 5 - while (condition ? a : b) {// 6 - if (++i == 8) {// 7 9 - break; - } + while ((condition ? a : b) && ++i != 8) {// 6 7 9 } }// 13 @@ -15,10 +12,7 @@ public class TestWhileTernary9 { if (Math.random() > 0.5) {// 16 int i = 0;// 17 - while (condition ? a : b) {// 18 - if (++i == 8) {// 19 21 - break; - } + while ((condition ? a : b) && ++i != 8) {// 18 19 21 } } }// 26 @@ -27,10 +21,7 @@ public class TestWhileTernary9 { if (Math.random() > 0.5) {// 29 int i = 0;// 30 - while (condition ? a : b) {// 31 - if (++i == 8) {// 32 34 - break; - } + while ((condition ? a : b) && ++i != 8) {// 31 32 34 } System.out.println("Successor");// 39 @@ -55,125 +46,125 @@ class 'pkg/TestWhileTernary9' { f 6 10 6 11 6 - 12 7 - 13 7 - 14 7 - 15 7 - 16 7 - 17 7 - 18 7 - 19 7 - 1a 7 - 1b 7 - 1f 11 + 12 6 + 13 6 + 14 6 + 15 6 + 16 6 + 17 6 + 18 6 + 19 6 + 1a 6 + 1b 6 + 1f 8 } method 'test1 (ZZZ)V' { - 0 14 - 1 14 - 2 14 - 3 14 - 4 14 - 5 14 - 6 14 - 7 14 - 8 14 - 9 14 - a 15 - b 15 - c 15 - d 17 - e 17 - f 17 - 10 17 - 11 17 - 12 17 - 13 17 - 14 17 - 18 17 - 19 17 - 1a 17 - 1b 17 - 1c 18 - 1d 18 - 1e 18 - 1f 18 - 20 18 - 21 18 - 22 18 - 23 18 - 24 18 - 25 18 - 29 23 + 0 11 + 1 11 + 2 11 + 3 11 + 4 11 + 5 11 + 6 11 + 7 11 + 8 11 + 9 11 + a 12 + b 12 + c 12 + d 14 + e 14 + f 14 + 10 14 + 11 14 + 12 14 + 13 14 + 14 14 + 18 14 + 19 14 + 1a 14 + 1b 14 + 1c 14 + 1d 14 + 1e 14 + 1f 14 + 20 14 + 21 14 + 22 14 + 23 14 + 24 14 + 25 14 + 29 17 } method 'test2 (ZZZ)V' { - 0 26 - 1 26 - 2 26 - 3 26 - 4 26 - 5 26 - 6 26 - 7 26 - 8 26 - 9 26 - a 27 - b 27 - c 27 - d 29 - e 29 - f 29 - 10 29 - 11 29 - 12 29 - 13 29 - 14 29 - 18 29 - 19 29 - 1a 29 - 1b 29 - 1c 30 - 1d 30 - 1e 30 - 1f 30 - 20 30 - 21 30 - 22 30 - 23 30 - 24 30 - 25 30 - 29 35 - 2a 35 - 2b 35 - 2c 35 - 2d 35 - 2e 35 - 2f 35 - 30 35 - 31 37 + 0 20 + 1 20 + 2 20 + 3 20 + 4 20 + 5 20 + 6 20 + 7 20 + 8 20 + 9 20 + a 21 + b 21 + c 21 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 12 23 + 13 23 + 14 23 + 18 23 + 19 23 + 1a 23 + 1b 23 + 1c 23 + 1d 23 + 1e 23 + 1f 23 + 20 23 + 21 23 + 22 23 + 23 23 + 24 23 + 25 23 + 29 26 + 2a 26 + 2b 26 + 2c 26 + 2d 26 + 2e 26 + 2f 26 + 30 26 + 31 28 } } Lines mapping: 5 <-> 5 6 <-> 7 -7 <-> 8 -9 <-> 8 -13 <-> 12 -16 <-> 15 -17 <-> 16 -18 <-> 18 -19 <-> 19 -21 <-> 19 -26 <-> 24 -29 <-> 27 -30 <-> 28 -31 <-> 30 -32 <-> 31 -34 <-> 31 -39 <-> 36 -41 <-> 38 +7 <-> 7 +9 <-> 7 +13 <-> 9 +16 <-> 12 +17 <-> 13 +18 <-> 15 +19 <-> 15 +21 <-> 15 +26 <-> 18 +29 <-> 21 +30 <-> 22 +31 <-> 24 +32 <-> 24 +34 <-> 24 +39 <-> 27 +41 <-> 29 Not mapped: 10 22 diff --git a/testData/src/java8/pkg/TestPPMM.java b/testData/src/java8/pkg/TestPPMM.java index c545f71b53..0b9e1287e9 100644 --- a/testData/src/java8/pkg/TestPPMM.java +++ b/testData/src/java8/pkg/TestPPMM.java @@ -16,101 +16,101 @@ package pkg; public class TestPPMM { - // Bytecode wise ipp and ppi are identical when not using the intermediate value. - // We keep these seperate tests just to see the bytecode. - public void ipp() { - int a = 0; - a++; - a++; - a++; - a++; - } - public void ppi() { - int a = 0; - ++a; - ++a; - ++a; - ++a; - } - public void imm() { - int a = 0; - a--; - a--; - a--; - a--; - } - public void mmi() { - int a = 0; - --a; - --a; - --a; - --a; - } - - // These versions actually use the intermediate value - public void ippf() { - int a = 0; - t(a++); - t(a++); - t(a++); - t(a++); - } - public void ppif() { - int a = 0; - t(++a); - t(++a); - t(++a); - t(++a); - } - public void immf() { - int a = 0; - t(a--); - t(a--); - t(a--); - t(a--); - } - public void mmif() { - int a = 0; - t(--a); - t(--a); - t(--a); - t(--a); - } - public void doubleppi() { - int a = 0; - ++a; - ++a; - t2(a, a); - ++a; - t2(a++, a); - ++a; - t2(++a, a); - ++a; - t2(a, ++a); - ++a; - t2(a, a++); - ++a; - t2(a, a); - t2(++a, a); - t2(a++, a); - t2(a, ++a); - t2(a, a++); - t2(a, a); - } + // Bytecode wise ipp and ppi are identical when not using the intermediate value. + // We keep these seperate tests just to see the bytecode. + public void ipp() { + int a = 0; + a++; + a++; + a++; + a++; + } + public void ppi() { + int a = 0; + ++a; + ++a; + ++a; + ++a; + } + public void imm() { + int a = 0; + a--; + a--; + a--; + a--; + } + public void mmi() { + int a = 0; + --a; + --a; + --a; + --a; + } - public void ppiAssign() { - int a = 0; - ++a; - a = 5; - System.out.println(); - ++a; - a = a + 5; - System.out.println(); - ++a; - a = 5 * a; - System.out.println(); - t(a); - } + // These versions actually use the intermediate value + public void ippf() { + int a = 0; + t(a++); + t(a++); + t(a++); + t(a++); + } + public void ppif() { + int a = 0; + t(++a); + t(++a); + t(++a); + t(++a); + } + public void immf() { + int a = 0; + t(a--); + t(a--); + t(a--); + t(a--); + } + public void mmif() { + int a = 0; + t(--a); + t(--a); + t(--a); + t(--a); + } + public void doubleppi() { + int a = 0; + ++a; + ++a; + t2(a, a); + ++a; + t2(a++, a); + ++a; + t2(++a, a); + ++a; + t2(a, ++a); + ++a; + t2(a, a++); + ++a; + t2(a, a); + t2(++a, a); + t2(a++, a); + t2(a, ++a); + t2(a, a++); + t2(a, a); + } + + public void ppiAssign() { + int a = 0; + ++a; + a = 5; + System.out.println(); + ++a; + a = a + 5; + System.out.println(); + ++a; + a = 5 * a; + System.out.println(); + t(a); + } public void ppiAssignPhi(boolean b) { @@ -133,10 +133,69 @@ public void ppiAssignPhi(boolean b) { t(a); } - private static void t(int x){ - } + public void ppiIf(boolean b, int i, int j) { + if (i++ > ++i) { + System.out.println("i++ > ++i"); + } + if (b && i++ < 5) { + System.out.println("b && i++ < 5"); + } + if (++i < j) { + System.out.println("++i < j"); + } + j++; + --i; + if (i > j) { + System.out.println("--i > ++j"); + } + if (!b || ++i < j) { + System.out.println("!b || ++i < j"); + } + j++; + if (!b && j < i) { + System.out.println("!b && j < i"); + } + if ((b ? ++i : ++j) > 0) { + System.out.println("(b ? ++i : ++j) > 0"); + } + i++; + j++; + if ((b ? i : j) > 0) { + System.out.println("(b ? i : j) > 0"); + } + if (++i > j ? b : j > 0){ + System.out.println("++i > j ? b : j > 0"); + } + i++; + if (i > j ? b : j > 0){ + System.out.println("++i > j ? b : j > 0"); + } + j++; + if (++i < j && (b || i < 5) && ++j > i && b) { + System.out.println("++i < ++j && (b || i < 5) && ++j > i && b"); + } + i++; + if ((b && i++ > 0) | i > 0){ + System.out.println("(b && i++ > 0) | i > 0"); + } + } + + public void doubleppi2vars() { + int a = 0; + int b = 0; + t2(a++, ++b); + a++; + b++; + t2(a,b); + b++; + a++; + t2(a,b); + } - private static void t2(int x, int y){ + private static void t(int x) { + } + + private static void t2(int x, int y) { - } + } } \ No newline at end of file From a303602c822276e9ce55dfe9f06b04aef545e66b Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sun, 10 May 2026 16:47:21 +0200 Subject: [PATCH 07/29] Add compact source file tests --- .../java/decompiler/SingleClassesTest.java | 5 ++ testData/results/TestCompactSourceFile.dec | 20 ++++++ .../results/TestCompactSourceFileArgs.dec | 49 +++++++++++++ .../TestCompactSourceFileOtherMembers.dec | 70 +++++++++++++++++++ ...estCompactSourceFileOtherMembersStatic.dec | 56 +++++++++++++++ .../src/java25/TestCompactSourceFile.java | 3 + .../src/java25/TestCompactSourceFileArgs.java | 9 +++ .../TestCompactSourceFileOtherMembers.java | 11 +++ ...stCompactSourceFileOtherMembersStatic.java | 10 +++ 9 files changed, 233 insertions(+) create mode 100644 testData/results/TestCompactSourceFile.dec create mode 100644 testData/results/TestCompactSourceFileArgs.dec create mode 100644 testData/results/TestCompactSourceFileOtherMembers.dec create mode 100644 testData/results/TestCompactSourceFileOtherMembersStatic.dec create mode 100644 testData/src/java25/TestCompactSourceFile.java create mode 100644 testData/src/java25/TestCompactSourceFileArgs.java create mode 100644 testData/src/java25/TestCompactSourceFileOtherMembers.java create mode 100644 testData/src/java25/TestCompactSourceFileOtherMembersStatic.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index b55d27e2fa..c0b533fecf 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -842,6 +842,11 @@ private void registerDefault() { // TODO: String type info is lost; does not recompile; issue #573 register(JAVA_8_NODEBUG, "TestStringConcatObjectAppend"); register(JAVA_25, "TestStringConcatObjectAppendJ25"); + + register(JAVA_25, "/TestCompactSourceFile"); + register(JAVA_25, "/TestCompactSourceFileArgs"); + register(JAVA_25, "/TestCompactSourceFileOtherMembers"); + register(JAVA_25, "/TestCompactSourceFileOtherMembersStatic"); } private void registerEntireClassPath() { diff --git a/testData/results/TestCompactSourceFile.dec b/testData/results/TestCompactSourceFile.dec new file mode 100644 index 0000000000..a0c964704b --- /dev/null +++ b/testData/results/TestCompactSourceFile.dec @@ -0,0 +1,20 @@ +final class TestCompactSourceFile { + void main() { + IO.println("Hello world!");// 2 + }// 3 +} + +class 'TestCompactSourceFile' { + method 'main ()V' { + 0 2 + 1 2 + 2 2 + 3 2 + 4 2 + 5 3 + } +} + +Lines mapping: +2 <-> 3 +3 <-> 4 diff --git a/testData/results/TestCompactSourceFileArgs.dec b/testData/results/TestCompactSourceFileArgs.dec new file mode 100644 index 0000000000..bfbb16fb81 --- /dev/null +++ b/testData/results/TestCompactSourceFileArgs.dec @@ -0,0 +1,49 @@ +final class TestCompactSourceFileArgs { + void main(String... args) { + String name; + if (args.length == 0) {// 3 + name = IO.readln("What is your name? ");// 4 + } else { + name = args[0];// 6 + } + + IO.println("Hello " + name + "!");// 8 + }// 9 +} + +class 'TestCompactSourceFileArgs' { + method 'main ([Ljava/lang/String;)V' { + 0 3 + 1 3 + 2 3 + 3 3 + 4 3 + 5 4 + 6 4 + 7 4 + 8 4 + 9 4 + a 4 + e 6 + f 6 + 10 6 + 11 6 + 12 9 + 13 9 + 14 9 + 15 9 + 16 9 + 17 9 + 18 9 + 19 9 + 1a 9 + 1b 10 + } +} + +Lines mapping: +3 <-> 4 +4 <-> 5 +6 <-> 7 +8 <-> 10 +9 <-> 11 diff --git a/testData/results/TestCompactSourceFileOtherMembers.dec b/testData/results/TestCompactSourceFileOtherMembers.dec new file mode 100644 index 0000000000..d897b37880 --- /dev/null +++ b/testData/results/TestCompactSourceFileOtherMembers.dec @@ -0,0 +1,70 @@ +final class TestCompactSourceFileOtherMembers { + String GREETING = "Hello";// 1 + + String createGreeting(String name) { + return this.GREETING + " " + name + "!";// 4 + } + + void main() { + IO.println(this.hashCode());// 8 + String name = IO.readln("Name: ");// 9 + IO.println(this.createGreeting(name));// 10 + }// 11 +} + +class 'TestCompactSourceFileOtherMembers' { + method ' ()V' { + 5 1 + 6 1 + } + + method 'createGreeting (Ljava/lang/String;)Ljava/lang/String;' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 7 4 + 8 4 + 9 4 + a 4 + } + + method 'main ()V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + 8 8 + 9 8 + a 9 + b 9 + c 9 + d 9 + e 9 + f 9 + 10 10 + 11 10 + 12 10 + 13 10 + 14 10 + 15 10 + 16 10 + 17 10 + 18 11 + } +} + +Lines mapping: +1 <-> 2 +4 <-> 5 +8 <-> 9 +9 <-> 10 +10 <-> 11 +11 <-> 12 diff --git a/testData/results/TestCompactSourceFileOtherMembersStatic.dec b/testData/results/TestCompactSourceFileOtherMembersStatic.dec new file mode 100644 index 0000000000..35b1937342 --- /dev/null +++ b/testData/results/TestCompactSourceFileOtherMembersStatic.dec @@ -0,0 +1,56 @@ +final class TestCompactSourceFileOtherMembersStatic { + static String GREETING = "Hello";// 1 + + static String createGreeting(String name) { + return GREETING + " " + name + "!";// 4 + } + + static void main() { + String name = IO.readln("Name: ");// 8 + IO.println(createGreeting(name));// 9 + }// 10 +} + +class 'TestCompactSourceFileOtherMembersStatic' { + method ' ()V' { + 0 1 + 1 1 + } + + method 'createGreeting (Ljava/lang/String;)Ljava/lang/String;' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 7 4 + 8 4 + 9 4 + } + + method 'main ()V' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 9 + 7 9 + 8 9 + 9 9 + a 9 + b 9 + c 9 + d 10 + } +} + +Lines mapping: +1 <-> 2 +4 <-> 5 +8 <-> 9 +9 <-> 10 +10 <-> 11 diff --git a/testData/src/java25/TestCompactSourceFile.java b/testData/src/java25/TestCompactSourceFile.java new file mode 100644 index 0000000000..31c286ed2c --- /dev/null +++ b/testData/src/java25/TestCompactSourceFile.java @@ -0,0 +1,3 @@ +void main() { + IO.println("Hello world!"); +} \ No newline at end of file diff --git a/testData/src/java25/TestCompactSourceFileArgs.java b/testData/src/java25/TestCompactSourceFileArgs.java new file mode 100644 index 0000000000..82062efbc0 --- /dev/null +++ b/testData/src/java25/TestCompactSourceFileArgs.java @@ -0,0 +1,9 @@ +void main(String... args) { + String name; + if (args.length == 0) { + name = IO.readln("What is your name? "); + } else { + name = args[0]; + } + IO.println("Hello " + name + "!"); +} \ No newline at end of file diff --git a/testData/src/java25/TestCompactSourceFileOtherMembers.java b/testData/src/java25/TestCompactSourceFileOtherMembers.java new file mode 100644 index 0000000000..d489a22b4f --- /dev/null +++ b/testData/src/java25/TestCompactSourceFileOtherMembers.java @@ -0,0 +1,11 @@ +String GREETING = "Hello"; + +String createGreeting(String name){ + return GREETING + " " + name + "!"; +} + +void main() { + IO.println(this.hashCode()); + String name = IO.readln("Name: "); + IO.println(createGreeting(name)); +} \ No newline at end of file diff --git a/testData/src/java25/TestCompactSourceFileOtherMembersStatic.java b/testData/src/java25/TestCompactSourceFileOtherMembersStatic.java new file mode 100644 index 0000000000..8d1985495d --- /dev/null +++ b/testData/src/java25/TestCompactSourceFileOtherMembersStatic.java @@ -0,0 +1,10 @@ +static String GREETING = "Hello"; + +static String createGreeting(String name){ + return GREETING + " " + name + "!"; +} + +static void main() { + String name = IO.readln("Name: "); + IO.println(createGreeting(name)); +} \ No newline at end of file From e748887056390c2e1f264f036815c974a3f28aa1 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Mon, 11 May 2026 22:07:27 +0200 Subject: [PATCH 08/29] Add catch and finally tests --- .../java/decompiler/SingleClassesTest.java | 1 + testData/results/pkg/TestTryCatchFinally.dec | 33 ++ .../results/pkg/TestTryCatchThrowable.dec | 315 +++++++++++++ testData/results/pkg/TestTryReturn.dec | 429 +++++++++--------- testData/results/pkg/TestTrySplit.dec | 104 ++++- .../src/java8/pkg/TestTryCatchFinally.java | 9 + .../src/java8/pkg/TestTryCatchThrowable.java | 85 ++++ testData/src/java8/pkg/TestTryReturn.java | 12 + testData/src/java8/pkg/TestTrySplit.java | 27 ++ 9 files changed, 810 insertions(+), 205 deletions(-) create mode 100644 testData/results/pkg/TestTryCatchThrowable.dec create mode 100644 testData/src/java8/pkg/TestTryCatchThrowable.java diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index c0b533fecf..287b6e40de 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -225,6 +225,7 @@ private void registerDefault() { register(JAVA_8, "TestInnerClassConstructor"); register(CUSTOM, "v11/TestInnerClassConstructor"); register(JAVA_8, "TestTryCatchFinally"); + register(JAVA_8, "TestTryCatchThrowable"); register(JAVA_8, "TestTryFinally"); register(JAVA_8, "TestAmbiguousCall"); register(JAVA_8, "TestSynchronizedMapping"); diff --git a/testData/results/pkg/TestTryCatchFinally.dec b/testData/results/pkg/TestTryCatchFinally.dec index fa543ed3ff..dc0b2eacf6 100644 --- a/testData/results/pkg/TestTryCatchFinally.dec +++ b/testData/results/pkg/TestTryCatchFinally.dec @@ -35,6 +35,15 @@ public class TestTryCatchFinally { return -1;// 57 } + + void testEmptyCatch(String msg) { + try { + System.out.println(msg);// 62 + } catch (RuntimeException var6) { + } finally { + System.out.println("Bye");// 65 + } + }// 67 } class 'pkg/TestTryCatchFinally' { @@ -114,6 +123,25 @@ class 'pkg/TestTryCatchFinally' { 3f 35 40 35 } + + method 'testEmptyCatch (Ljava/lang/String;)V' { + 0 40 + 1 40 + 2 40 + 3 40 + 4 40 + 5 40 + 6 40 + 1f 43 + 20 43 + 21 43 + 22 43 + 23 43 + 24 43 + 25 43 + 26 43 + 29 45 + } } Lines mapping: @@ -132,8 +160,13 @@ Lines mapping: 53 <-> 31 55 <-> 33 57 <-> 36 +62 <-> 41 +65 <-> 44 +67 <-> 46 Not mapped: 25 32 35 56 +63 +66 diff --git a/testData/results/pkg/TestTryCatchThrowable.dec b/testData/results/pkg/TestTryCatchThrowable.dec new file mode 100644 index 0000000000..30a66447b8 --- /dev/null +++ b/testData/results/pkg/TestTryCatchThrowable.dec @@ -0,0 +1,315 @@ +package pkg; + +public class TestTryCatchThrowable { + void testEmptyCatch() { + try { + System.out.println("Hi");// 7 + } catch (Throwable var2) {// 8 + } + }// 10 + + void testEmptyCatchWithTail() { + try { + System.out.println("Hi");// 14 + } catch (Throwable var2) {// 15 + } + + System.out.println("tail");// 18 + }// 19 + + String testCatchWithReturn() { + try { + System.out.println("Hi");// 23 + return "5";// 24 + } catch (Throwable ignored) {// 25 + return null;// 26 + } + } + + String testCatchWithReturnAndTail() { + try { + System.out.println("Hi");// 32 + } catch (Throwable ignored) {// 33 + return null;// 34 + } + + System.out.println("Ho");// 36 + return "bye";// 37 + } + + String testCatchNested() { + try { + System.out.println("Hi");// 42 + return "hello";// 43 + } catch (Throwable ignored) { + try { + System.out.println("Hi!");// 46 + return "5";// 47 + } catch (Throwable throwable) {// 48 + return throwable.getMessage();// 49 + } + } + } + + String testCatchWithRethrow() { + try { + System.out.println("Hi");// 56 + return "5";// 57 + } catch (Throwable throwable) {// 58 + System.out.println("Oh no");// 59 + throw throwable;// 60 + } + } + + void testCatchAndOtherEmptyCatch() { + try { + System.out.println("Hi");// 67 + } catch (RuntimeException var2) {// 68 + } catch (Throwable ignored) {// 70 + System.out.println("Oh no");// 71 + } + }// 73 + + void testCatchAndOtherNonEmptyCatch() { + try { + System.out.println("Hi");// 77 + } catch (RuntimeException ignored) {// 78 + System.out.println("Hello");// 79 + } catch (Throwable ignored) {// 80 + System.out.println("Oh no");// 81 + } + }// 83 +} + +class 'pkg/TestTryCatchThrowable' { + method 'testEmptyCatch ()V' { + 0 5 + 1 5 + 2 5 + 3 5 + 4 5 + 5 5 + 6 5 + 7 5 + b 6 + c 8 + } + + method 'testEmptyCatchWithTail ()V' { + 0 12 + 1 12 + 2 12 + 3 12 + 4 12 + 5 12 + 6 12 + 7 12 + b 13 + c 16 + d 16 + e 16 + f 16 + 10 16 + 11 16 + 12 16 + 13 16 + 14 17 + } + + method 'testCatchWithReturn ()Ljava/lang/String;' { + 0 21 + 1 21 + 2 21 + 3 21 + 4 21 + 5 21 + 6 21 + 7 21 + 8 22 + 9 22 + a 22 + b 23 + c 24 + d 24 + } + + method 'testCatchWithReturnAndTail ()Ljava/lang/String;' { + 0 30 + 1 30 + 2 30 + 3 30 + 4 30 + 5 30 + 6 30 + 7 30 + b 31 + c 32 + d 32 + e 35 + f 35 + 10 35 + 11 35 + 12 35 + 13 35 + 14 35 + 15 35 + 16 36 + 17 36 + 18 36 + } + + method 'testCatchNested ()Ljava/lang/String;' { + 0 41 + 1 41 + 2 41 + 3 41 + 4 41 + 5 41 + 6 41 + 7 41 + 8 42 + 9 42 + a 42 + c 45 + d 45 + e 45 + f 45 + 10 45 + 11 45 + 12 45 + 13 45 + 14 46 + 15 46 + 16 46 + 17 47 + 18 48 + 19 48 + 1a 48 + 1b 48 + 1c 48 + } + + method 'testCatchWithRethrow ()Ljava/lang/String;' { + 0 55 + 1 55 + 2 55 + 3 55 + 4 55 + 5 55 + 6 55 + 7 55 + 8 56 + 9 56 + a 56 + b 57 + c 58 + d 58 + e 58 + f 58 + 10 58 + 11 58 + 12 58 + 13 58 + 14 59 + 15 59 + } + + method 'testCatchAndOtherEmptyCatch ()V' { + 0 65 + 1 65 + 2 65 + 3 65 + 4 65 + 5 65 + 6 65 + 7 65 + b 66 + f 67 + 10 68 + 11 68 + 12 68 + 13 68 + 14 68 + 15 68 + 16 68 + 17 68 + 18 70 + } + + method 'testCatchAndOtherNonEmptyCatch ()V' { + 0 74 + 1 74 + 2 74 + 3 74 + 4 74 + 5 74 + 6 74 + 7 74 + b 75 + c 76 + d 76 + e 76 + f 76 + 10 76 + 11 76 + 12 76 + 13 76 + 17 77 + 18 78 + 19 78 + 1a 78 + 1b 78 + 1c 78 + 1d 78 + 1e 78 + 1f 78 + 20 80 + } +} + +Lines mapping: +7 <-> 6 +8 <-> 7 +10 <-> 9 +14 <-> 13 +15 <-> 14 +18 <-> 17 +19 <-> 18 +23 <-> 22 +24 <-> 23 +25 <-> 24 +26 <-> 25 +32 <-> 31 +33 <-> 32 +34 <-> 33 +36 <-> 36 +37 <-> 37 +42 <-> 42 +43 <-> 43 +46 <-> 46 +47 <-> 47 +48 <-> 48 +49 <-> 49 +56 <-> 56 +57 <-> 57 +58 <-> 58 +59 <-> 59 +60 <-> 60 +67 <-> 66 +68 <-> 67 +70 <-> 68 +71 <-> 69 +73 <-> 71 +77 <-> 75 +78 <-> 76 +79 <-> 77 +80 <-> 78 +81 <-> 79 +83 <-> 81 +Not mapped: +9 +16 +35 +44 +72 +82 diff --git a/testData/results/pkg/TestTryReturn.dec b/testData/results/pkg/TestTryReturn.dec index 9d7467801b..76f5c13342 100644 --- a/testData/results/pkg/TestTryReturn.dec +++ b/testData/results/pkg/TestTryReturn.dec @@ -162,79 +162,104 @@ public class TestTryReturn { // try (26 -> 27): 26 null } + public void testParsingFailureSimple() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: getstatic java/lang/System.out Ljava/io/PrintStream; + // 03: ldc "inner" + // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 08: getstatic java/lang/System.out Ljava/io/PrintStream; + // 0b: ldc "fin" + // 0d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 10: return + // 11: astore 1 + // 12: getstatic java/lang/System.out Ljava/io/PrintStream; + // 15: ldc "fin" + // 17: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 1a: return + // 1b: astore 2 + // 1c: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1f: ldc "fin" + // 21: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 24: aload 2 + // 25: athrow + // try (0 -> 3): 7 null + // try (0 -> 3): 12 null + } + public void testPostdomFailure() { - System.out.println(1);// 143 + System.out.println(1);// 155 - while (new Random().nextBoolean()) {// 145 + while (new Random().nextBoolean()) {// 157 try { try { - System.out.println(2);// 148 - } catch (Exception var9) {// 149 - System.out.println(3);// 150 + System.out.println(2);// 160 + } catch (Exception var9) {// 161 + System.out.println(3);// 162 } finally { continue; } } finally { - byte var7 = 28;// 156 + byte var7 = 28;// 168 } } - }// 159 + }// 171 public void testVarWrong() { try { - System.out.println("Hi");// 164 - return;// 175 - } catch (Exception var2) {// 165 - if (var2 == null) {// 166 - System.out.println(var2);// 169 - return;// 170 + System.out.println("Hi");// 176 + return;// 187 + } catch (Exception var2) {// 177 + if (var2 == null) {// 178 + System.out.println(var2);// 181 + return;// 182 } } finally { - float var5 = 9.18F;// 173 + float var5 = 9.18F;// 185 } - }// 167 + }// 179 public void testInvalidUse() { - boolean var1 = false;// 178 - String var3 = "Hi!";// 179 + boolean var1 = false;// 190 + String var3 = "Hi!";// 191 try { Exception var4; try { - System.out.println(var1);// 181 - return;// 182 - } catch (Exception var15) {// 183 + System.out.println(var1);// 193 + return;// 194 + } catch (Exception var15) {// 195 var4 = var15; } try { - System.out.println(var4);// 185 - return;// 196 - } catch (Exception var5) {// 186 + System.out.println(var4);// 197 + return;// 208 + } catch (Exception var5) {// 198 } finally { - System.out.println(var15);// 190 + System.out.println(var15);// 202 } } finally { - System.out.println(var3);// 194 + System.out.println(var3);// 206 } - }// 187 + }// 199 public void returnInCatch() { label27: { try { - System.out.println("Hi!");// 200 + System.out.println("Hi!");// 212 break label27; - } catch (Exception e) {// 201 - System.out.println("hello");// 202 + } catch (Exception e) {// 213 + System.out.println("hello");// 214 } finally { - System.out.println("finally");// 205 + System.out.println("finally");// 217 } - return;// 203 + return;// 215 } - System.out.println("post");// 208 - }// 209 + System.out.println("post");// 220 + }// 221 } class 'pkg/TestTryReturn' { @@ -537,145 +562,145 @@ class 'pkg/TestTryReturn' { } method 'testPostdomFailure ()V' { - 0 165 - 1 165 - 2 165 - 3 165 - 4 165 - 5 165 - 6 165 - e 167 - f 167 - 10 167 - 14 170 - 15 170 - 16 170 - 17 170 - 18 170 - 19 170 - 1a 170 - 21 171 - 22 172 - 23 172 - 24 172 - 25 172 - 26 172 - 27 172 - 28 172 - 3a 177 - 3b 177 - 3c 177 - 3d 177 - 41 180 + 0 190 + 1 190 + 2 190 + 3 190 + 4 190 + 5 190 + 6 190 + e 192 + f 192 + 10 192 + 14 195 + 15 195 + 16 195 + 17 195 + 18 195 + 19 195 + 1a 195 + 21 196 + 22 197 + 23 197 + 24 197 + 25 197 + 26 197 + 27 197 + 28 197 + 3a 202 + 3b 202 + 3c 202 + 3d 202 + 41 205 } method 'testVarWrong ()V' { - 0 184 - 1 184 - 2 184 - 3 184 - 4 184 - 5 184 - 6 184 - 7 184 - e 186 - f 187 - 10 187 - 11 187 - 12 187 - 16 194 - 17 188 - 18 188 - 19 188 - 1a 188 - 1b 188 - 1c 188 - 1d 188 - 21 189 - 24 192 - 25 192 - 26 192 - 27 192 - 2b 185 + 0 209 + 1 209 + 2 209 + 3 209 + 4 209 + 5 209 + 6 209 + 7 209 + e 211 + f 212 + 10 212 + 11 212 + 12 212 + 16 219 + 17 213 + 18 213 + 19 213 + 1a 213 + 1b 213 + 1c 213 + 1d 213 + 21 214 + 24 217 + 25 217 + 26 217 + 27 217 + 2b 210 } method 'testInvalidUse ()V' { - 0 197 - 1 197 - 2 198 - 3 198 - 4 198 - 5 203 - 6 203 - 7 203 - 8 203 - 9 203 - a 203 - b 203 - 13 204 - 14 205 - 15 210 - 16 210 - 17 210 - 18 210 - 19 210 - 1a 210 - 1b 210 - 26 212 - 36 219 - 39 214 - 3a 214 - 3b 214 - 3c 214 - 3d 214 - 3e 214 - 3f 214 - 4f 217 - 50 217 - 51 217 - 52 217 - 53 217 - 54 217 - 55 217 - 59 211 + 0 222 + 1 222 + 2 223 + 3 223 + 4 223 + 5 228 + 6 228 + 7 228 + 8 228 + 9 228 + a 228 + b 228 + 13 229 + 14 230 + 15 235 + 16 235 + 17 235 + 18 235 + 19 235 + 1a 235 + 1b 235 + 26 237 + 36 244 + 39 239 + 3a 239 + 3b 239 + 3c 239 + 3d 239 + 3e 239 + 3f 239 + 4f 242 + 50 242 + 51 242 + 52 242 + 53 242 + 54 242 + 55 242 + 59 236 } method 'returnInCatch ()V' { - 0 224 - 1 224 - 2 224 - 3 224 - 4 224 - 5 224 - 6 224 - 7 224 - 13 226 - 14 227 - 15 227 - 16 227 - 17 227 - 18 227 - 19 227 - 1a 227 - 1b 227 - 24 232 - 26 229 - 27 229 - 28 229 - 29 229 - 2a 229 - 2b 229 - 2c 229 - 2d 229 - 30 235 - 31 235 - 32 235 - 33 235 - 34 235 - 35 235 - 36 235 - 37 235 - 38 236 + 0 249 + 1 249 + 2 249 + 3 249 + 4 249 + 5 249 + 6 249 + 7 249 + 13 251 + 14 252 + 15 252 + 16 252 + 17 252 + 18 252 + 19 252 + 1a 252 + 1b 252 + 24 257 + 26 254 + 27 254 + 28 254 + 29 254 + 2a 254 + 2b 254 + 2c 254 + 2d 254 + 30 260 + 31 260 + 32 260 + 33 260 + 34 260 + 35 260 + 36 260 + 37 260 + 38 261 } } @@ -725,39 +750,39 @@ Lines mapping: 113 <-> 116 114 <-> 117 117 <-> 120 -143 <-> 166 -145 <-> 168 -148 <-> 171 -149 <-> 172 -150 <-> 173 -156 <-> 178 -159 <-> 181 -164 <-> 185 -165 <-> 187 -166 <-> 188 -167 <-> 195 -169 <-> 189 -170 <-> 190 -173 <-> 193 -175 <-> 186 -178 <-> 198 -179 <-> 199 -181 <-> 204 -182 <-> 205 -183 <-> 206 -185 <-> 211 -186 <-> 213 -187 <-> 220 -190 <-> 215 -194 <-> 218 -196 <-> 212 -200 <-> 225 -201 <-> 227 -202 <-> 228 -203 <-> 233 -205 <-> 230 -208 <-> 236 -209 <-> 237 +155 <-> 191 +157 <-> 193 +160 <-> 196 +161 <-> 197 +162 <-> 198 +168 <-> 203 +171 <-> 206 +176 <-> 210 +177 <-> 212 +178 <-> 213 +179 <-> 220 +181 <-> 214 +182 <-> 215 +185 <-> 218 +187 <-> 211 +190 <-> 223 +191 <-> 224 +193 <-> 229 +194 <-> 230 +195 <-> 231 +197 <-> 236 +198 <-> 238 +199 <-> 245 +202 <-> 240 +206 <-> 243 +208 <-> 237 +212 <-> 250 +213 <-> 252 +214 <-> 253 +215 <-> 258 +217 <-> 255 +220 <-> 261 +221 <-> 262 Not mapped: 20 32 @@ -767,9 +792,9 @@ Not mapped: 84 103 118 -153 -157 -174 -191 -195 -206 +165 +169 +186 +203 +207 +218 diff --git a/testData/results/pkg/TestTrySplit.dec b/testData/results/pkg/TestTrySplit.dec index d738cd6cb3..f7a0585413 100644 --- a/testData/results/pkg/TestTrySplit.dec +++ b/testData/results/pkg/TestTrySplit.dec @@ -18,8 +18,35 @@ public class TestTrySplit { } }// 14 + public void testFlat() { + Object obj = null;// 21 + + label25: { + try { + try { + obj = new Object();// 27 + break label25; + } catch (ArithmeticException ex) {// 28 + if (obj != null) {// 29 + System.out.println("a");// 30 + } + } + + throwMyException(ex.getMessage());// 33 + } catch (Throwable t) {// 37 + System.out.println("b");// 38 + throw t;// 39 + } + + System.out.println("b");// 41 + return;// 42 + } + + System.out.println("b");// 44 + }// 45 + public static void throwMyException(String message) { - throw new RuntimeException(message);// 21 + throw new RuntimeException(message);// 48 } } @@ -60,9 +87,64 @@ class 'pkg/TestTrySplit' { 3d 8 } + method 'testFlat ()V' { + 0 21 + 1 21 + 9 26 + d 28 + e 29 + f 29 + 10 29 + 11 29 + 12 30 + 13 30 + 14 30 + 15 30 + 16 30 + 17 30 + 18 30 + 19 30 + 1a 34 + 1b 34 + 1c 34 + 1d 34 + 1e 34 + 1f 34 + 20 34 + 27 35 + 28 36 + 29 36 + 2a 36 + 2b 36 + 2c 36 + 2d 36 + 2e 36 + 2f 36 + 30 37 + 31 37 + 32 40 + 33 40 + 34 40 + 35 40 + 36 40 + 37 40 + 38 40 + 39 40 + 3a 41 + 3b 44 + 3c 44 + 3d 44 + 3e 44 + 3f 44 + 40 44 + 41 44 + 42 44 + 43 45 + } + method 'throwMyException (Ljava/lang/String;)V' { - 4 21 - 8 21 + 4 48 + 8 48 } } @@ -77,5 +159,21 @@ Lines mapping: 16 <-> 17 18 <-> 9 21 <-> 22 +27 <-> 27 +28 <-> 29 +29 <-> 30 +30 <-> 31 +33 <-> 35 +37 <-> 36 +38 <-> 37 +39 <-> 38 +41 <-> 41 +42 <-> 42 +44 <-> 45 +45 <-> 46 +48 <-> 49 Not mapped: 17 +34 +35 +36 diff --git a/testData/src/java8/pkg/TestTryCatchFinally.java b/testData/src/java8/pkg/TestTryCatchFinally.java index 2c49800004..dd97d83e99 100644 --- a/testData/src/java8/pkg/TestTryCatchFinally.java +++ b/testData/src/java8/pkg/TestTryCatchFinally.java @@ -56,4 +56,13 @@ public int test(String a) { } return -1; } + + void testEmptyCatch(String msg) { + try { + System.out.println(msg); + } catch (RuntimeException ignored){ + } finally { + System.out.println("Bye"); + } + } } \ No newline at end of file diff --git a/testData/src/java8/pkg/TestTryCatchThrowable.java b/testData/src/java8/pkg/TestTryCatchThrowable.java new file mode 100644 index 0000000000..d13f867c80 --- /dev/null +++ b/testData/src/java8/pkg/TestTryCatchThrowable.java @@ -0,0 +1,85 @@ +package pkg; + +public class TestTryCatchThrowable { + + void testEmptyCatch(){ + try { + System.out.println("Hi"); + } catch (Throwable ignored){ + } + } + + void testEmptyCatchWithTail(){ + try { + System.out.println("Hi"); + } catch (Throwable ignored){ + } + + System.out.println("tail"); + } + + String testCatchWithReturn(){ + try { + System.out.println("Hi"); + return "5"; + } catch (Throwable ignored){ + return null; + } + } + + String testCatchWithReturnAndTail(){ + try { + System.out.println("Hi"); + } catch (Throwable ignored){ + return null; + } + System.out.println("Ho"); + return "bye"; + } + + String testCatchNested(){ + try { + System.out.println("Hi"); + return "hello"; + } catch (Throwable ignored){ + try { + System.out.println("Hi!"); + return "5"; + } catch (Throwable throwable){ + return throwable.getMessage(); + } + } + } + + String testCatchWithRethrow(){ + try { + System.out.println("Hi"); + return "5"; + } catch (Throwable throwable){ + System.out.println("Oh no"); + throw throwable; + } + } + + + void testCatchAndOtherEmptyCatch(){ + try { + System.out.println("Hi"); + } catch (RuntimeException ignored) { + + } catch (Throwable ignored){ + System.out.println("Oh no"); + } + } + + void testCatchAndOtherNonEmptyCatch(){ + try { + System.out.println("Hi"); + } catch (RuntimeException ignored) { + System.out.println("Hello"); + } catch (Throwable ignored){ + System.out.println("Oh no"); + } + } +} + diff --git a/testData/src/java8/pkg/TestTryReturn.java b/testData/src/java8/pkg/TestTryReturn.java index 9e2b7a5d6e..0d16bf0902 100644 --- a/testData/src/java8/pkg/TestTryReturn.java +++ b/testData/src/java8/pkg/TestTryReturn.java @@ -137,6 +137,18 @@ public void testParsingFailure() { } } + public void testParsingFailureSimple() { + try { + try { + System.out.println("inner"); + } finally { + return; + } + } finally { + System.out.println("fin"); + } + } + public void testPostdomFailure() { // Load bearing useless string- removing this makes vf emit a parsing error??? String var1; diff --git a/testData/src/java8/pkg/TestTrySplit.java b/testData/src/java8/pkg/TestTrySplit.java index 95dba15748..211c229279 100644 --- a/testData/src/java8/pkg/TestTrySplit.java +++ b/testData/src/java8/pkg/TestTrySplit.java @@ -17,6 +17,33 @@ public void test() { } } + public void testFlat() { + Object obj = null; + b1: + { + b2: + try { + try { + obj = new Object(); + } catch (ArithmeticException ex) { + if (obj != null) { + System.out.println("a"); + } + + throwMyException(ex.getMessage()); + break b2; + } + break b1; + } catch (Throwable t) { + System.out.println("b"); + throw t; + } + System.out.println("b"); + return; + } + System.out.println("b"); + } + public static void throwMyException(String message) { throw new RuntimeException(message); } From 7b4f9942289ad3e646afb7406343761a49a44faa Mon Sep 17 00:00:00 2001 From: Kroppeb <7889478+Kroppeb@users.noreply.github.com> Date: Fri, 15 May 2026 02:24:08 +0200 Subject: [PATCH 09/29] Add debug marker exceptions (#585) * Add debug marker exceptions * Add debug marker exceptions * Apply suggestions from code review Co-authored-by: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> * Move marker exceptions into dedicated source set * Update comment --------- Co-authored-by: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> --- build.gradle | 11 + .../main/extern/IFernflowerPreferences.java | 6 + .../java/decompiler/struct/StructMethod.java | 43 ++ .../java/decompiler/SingleClassesTest.java | 6 +- .../vineflower/marker/CatchAllException.java | 7 + .../vineflower/marker/UnCatchException.java | 7 + .../results/pkg/TestTryCatchNoIncrement.dec | 154 ++++++ .../pkg/TestTryFinallyMarkerExceptions.dec | 153 ++++++ .../TestTryFinallyMarkerExceptionsInvalid.dec | 445 ++++++++++++++++++ .../java8/pkg/TestTryCatchNoIncrement.java | 53 +++ .../pkg/TestTryFinallyMarkerExceptions.java | 54 +++ ...TestTryFinallyMarkerExceptionsInvalid.java | 121 +++++ 12 files changed, 1059 insertions(+), 1 deletion(-) create mode 100644 testData/markers/org/vineflower/marker/CatchAllException.java create mode 100644 testData/markers/org/vineflower/marker/UnCatchException.java create mode 100644 testData/results/pkg/TestTryCatchNoIncrement.dec create mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptions.dec create mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec create mode 100644 testData/src/java8/pkg/TestTryCatchNoIncrement.java create mode 100644 testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java create mode 100644 testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java diff --git a/build.gradle b/build.gradle index 3c2cf90be7..b78f88ec85 100644 --- a/build.gradle +++ b/build.gradle @@ -66,6 +66,7 @@ version = version + (ENV.STATUS == "snapshot" ? "-SNAPSHOT" : "") sourceSets { main.java.srcDirs 'src' test.java.srcDirs 'test' + testMarkers.java.srcDirs files("testData/markers") testFixtures.java.srcDirs 'testFixtures' testDataGroovy.groovy.srcDirs files("testData/src/groovy/") testDataKotlin.kotlin.srcDirs files("testData/src/kt/") @@ -115,6 +116,7 @@ testClasses.dependsOn(testDataClasses) void createJavaTestDataSet(int version, String suffix = "", List compilerArgs = []) { sourceSets.create("testDataJava${version}${suffix}") { it.java.srcDirs file("testData/src/java${version}${suffix.toLowerCase()}") + compileClasspath += sourceSets.testMarkers.output } tasks.getByName("compileTestDataJava${version}${suffix}Java") { destinationDirectory = file("testData/classes/java${version}${suffix.toLowerCase()}") @@ -124,6 +126,9 @@ void createJavaTestDataSet(int version, String suffix = "", List compile options.compilerArgs = compilerArgs } + tasks.getByName("testDataJava${version}${suffix}Classes") { + dependsOn testMarkersClasses + } testDataClasses.dependsOn("testDataJava${version}${suffix}Classes") } @@ -138,6 +143,12 @@ def testJavaRuntimes = [:] [16, 17, 21].forEach { version -> createJavaTestDataSet(version, "Preview", ["--enable-preview"]) } [8, 16].forEach { version -> createJavaTestDataSet(version, "NoDebug", ["-g:none"])} +compileTestMarkersJava { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(8) + } +} + task compileTestDataJasm(type: JasmCompile) { source = fileTree("testData/src/jasm/") destinationDirectory = file("testData/classes/jasm/") diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 5353261817..eb59b2502b 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -418,6 +418,11 @@ public interface IFernflowerPreferences { @Type(DecompilerOption.Type.STRING) String METHOD_TO_DECOMPILE = "method-to-decompile"; + @Name("DEBUG: Enable special handling of marker exceptions") + @Description("") + @Type(DecompilerOption.Type.BOOLEAN) + String DEBUG_MARKER_EXCEPTIONS = "debug-marker-exceptions"; + Map DEFAULTS = getDefaults(); static Map getDefaults() { @@ -495,6 +500,7 @@ static Map getDefaults() { defaults.put(VALIDATE_INNER_CLASSES_NAMES, "1"); defaults.put(PRETTIFY_IFS, "1"); defaults.put(METHOD_TO_DECOMPILE, ""); + defaults.put(DEBUG_MARKER_EXCEPTIONS, "0"); return Collections.unmodifiableMap(defaults); } diff --git a/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/src/org/jetbrains/java/decompiler/struct/StructMethod.java index 5e1f857956..98fda95b63 100644 --- a/src/org/jetbrains/java/decompiler/struct/StructMethod.java +++ b/src/org/jetbrains/java/decompiler/struct/StructMethod.java @@ -23,6 +23,7 @@ import java.util.Map; import static org.jetbrains.java.decompiler.code.CodeConstants.*; +import static org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences.DEBUG_MARKER_EXCEPTIONS; /* method_info { @@ -343,11 +344,26 @@ else if (opcode >= opc_invokevirtual && opcode <= opc_invokestatic) { exceptionClass = null; } else { exceptionClass = pool.getPrimitiveConstant(excClass).getString(); + if (DecompilerContext.getOption(DEBUG_MARKER_EXCEPTIONS)) { + if ("org/vineflower/marker/CatchAllException".equals(exceptionClass)){ + exceptionClass = null; + } + } } lstHandlers.add(new ExceptionHandler(from, to, handler, exceptionClass)); } + if (DecompilerContext.getOption(DEBUG_MARKER_EXCEPTIONS)) { + for (int i = 0; i < lstHandlers.size(); i++) { + ExceptionHandler range = lstHandlers.get(i); + + if ("org/vineflower/marker/UnCatchException".equals(range.exceptionClass())) { + lstHandlers = filterOutRange(lstHandlers, i, range.from(), range.to()); + } + } + } + FullInstructionSequence seq = new FullInstructionSequence( instructions, offsetToIndex, @@ -360,6 +376,33 @@ else if (opcode >= opc_invokevirtual && opcode <= opc_invokestatic) { return seq; } + private static List filterOutRange(List lstHandlers, int startIndex, int from, int to) { + // DEBUG ONLY: removes all handlers for a specific range + List newHandlers = new ArrayList<>(); + for (int i = 0; i < lstHandlers.size(); i++) { + ExceptionHandler oldRange = lstHandlers.get(i); + if (i == startIndex) { + // skip marker exception + continue; + } else if (i < startIndex) { + // copy over inner ranges + newHandlers.add(oldRange); + } else if (oldRange.to() > from && to > oldRange.from()) { + // split/filter wrapping ranges + if (oldRange.from() < from) { + newHandlers.add(new ExceptionHandler(oldRange.from(), from, oldRange.handler(), oldRange.exceptionClass())); + } + if (oldRange.to() > to) { + newHandlers.add(new ExceptionHandler(to, oldRange.to(), oldRange.handler(), oldRange.exceptionClass())); + } + } else { + // copy over non overlapping ranges + newHandlers.add(oldRange); + } + } + return newHandlers; + } + public String getName() { return name; } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 287b6e40de..142f503711 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -22,7 +22,8 @@ protected void registerAll() { IFernflowerPreferences.INCLUDE_ENTIRE_CLASSPATH, "0", IFernflowerPreferences.TERNARY_CONDITIONS, "1", IFernflowerPreferences.FORCE_JSR_INLINE, "1", - IFernflowerPreferences.VERIFY_PRE_POST_VARIABLE_MERGES, "1" + IFernflowerPreferences.VERIFY_PRE_POST_VARIABLE_MERGES, "1", + IFernflowerPreferences.DEBUG_MARKER_EXCEPTIONS, "1" ); registerSet("Entire Classpath", this::registerEntireClassPath, IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", @@ -227,6 +228,8 @@ private void registerDefault() { register(JAVA_8, "TestTryCatchFinally"); register(JAVA_8, "TestTryCatchThrowable"); register(JAVA_8, "TestTryFinally"); + register(JAVA_8, "TestTryFinallyMarkerExceptions"); + register(JAVA_8, "TestTryFinallyMarkerExceptionsInvalid"); register(JAVA_8, "TestAmbiguousCall"); register(JAVA_8, "TestSynchronizedMapping"); register(JAVA_8, "TestAbstractMethods"); @@ -678,6 +681,7 @@ private void registerDefault() { register(JAVA_8, "TestForCyclicVarDef"); // TODO: merging of trycatch incorrect register(JAVA_8, "TestTryCatchNested"); + register(JAVA_8, "TestTryCatchNoIncrement"); // Issue #568 register(JAVA_8, "TestSwitchTernary"); register(JAVA_8, "TestBooleanExpressions"); register(JAVA_8, "TestObjectBitwise"); diff --git a/testData/markers/org/vineflower/marker/CatchAllException.java b/testData/markers/org/vineflower/marker/CatchAllException.java new file mode 100644 index 0000000000..8e7789debf --- /dev/null +++ b/testData/markers/org/vineflower/marker/CatchAllException.java @@ -0,0 +1,7 @@ +package org.vineflower.marker; + +public class CatchAllException extends RuntimeException { + public CatchAllException(String message) { + super(message); + } +} diff --git a/testData/markers/org/vineflower/marker/UnCatchException.java b/testData/markers/org/vineflower/marker/UnCatchException.java new file mode 100644 index 0000000000..9aca491c30 --- /dev/null +++ b/testData/markers/org/vineflower/marker/UnCatchException.java @@ -0,0 +1,7 @@ +package org.vineflower.marker; + +public class UnCatchException extends RuntimeException { + public UnCatchException(String message) { + super(message); + } +} diff --git a/testData/results/pkg/TestTryCatchNoIncrement.dec b/testData/results/pkg/TestTryCatchNoIncrement.dec new file mode 100644 index 0000000000..6b41ea8e08 --- /dev/null +++ b/testData/results/pkg/TestTryCatchNoIncrement.dec @@ -0,0 +1,154 @@ +package pkg; + +import java.util.List; + +public class TestTryCatchNoIncrement { + public final void baseline(List items) { + try { + for (int i = 0; i < items.size(); i++) {// 12 + String item = (String)items.get(i);// 13 + System.out.println(i + ": " + item);// 14 + } + } catch (Throwable ex2) {// 17 + ex2.printStackTrace();// 18 + } + }// 20 + + public final void skippedInc(List param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: bipush 0 + // 01: istore 2 + // 02: iload 2 + // 03: aload 1 + // 04: invokeinterface java/util/List.size ()I 1 + // 09: if_icmpge 3f + // 0c: aload 1 + // 0d: iload 2 + // 0e: invokeinterface java/util/List.get (I)Ljava/lang/Object; 2 + // 13: checkcast java/lang/String + // 16: astore 3 + // 17: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1a: new java/lang/StringBuilder + // 1d: dup + // 1e: invokespecial java/lang/StringBuilder. ()V + // 21: iload 2 + // 22: invokevirtual java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; + // 25: ldc ": " + // 27: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; + // 2a: aload 3 + // 2b: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; + // 2e: invokevirtual java/lang/StringBuilder.toString ()Ljava/lang/String; + // 31: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 34: iinc 2 1 + // 37: goto 3c + // 3a: astore 4 + // 3c: goto 02 + // 3f: goto 47 + // 42: astore 2 + // 43: aload 2 + // 44: invokevirtual java/lang/Throwable.printStackTrace ()V + // 47: return + // try (0 -> 23): 28 java/lang/Throwable + // try (24 -> 27): 28 java/lang/Throwable + } + + public final void skipPrinting(List param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: bipush 0 + // 01: istore 2 + // 02: iload 2 + // 03: aload 1 + // 04: invokeinterface java/util/List.size ()I 1 + // 09: if_icmpge 3f + // 0c: aload 1 + // 0d: iload 2 + // 0e: invokeinterface java/util/List.get (I)Ljava/lang/Object; 2 + // 13: checkcast java/lang/String + // 16: astore 3 + // 17: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1a: new java/lang/StringBuilder + // 1d: dup + // 1e: invokespecial java/lang/StringBuilder. ()V + // 21: iload 2 + // 22: invokevirtual java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; + // 25: ldc ": " + // 27: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; + // 2a: aload 3 + // 2b: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; + // 2e: invokevirtual java/lang/StringBuilder.toString ()Ljava/lang/String; + // 31: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 34: goto 39 + // 37: astore 4 + // 39: iinc 2 1 + // 3c: goto 02 + // 3f: goto 47 + // 42: astore 2 + // 43: aload 2 + // 44: invokevirtual java/lang/Throwable.printStackTrace ()V + // 47: return + // try (0 -> 11): 28 java/lang/Throwable + // try (23 -> 27): 28 java/lang/Throwable + } +} + +class 'pkg/TestTryCatchNoIncrement' { + method 'baseline (Ljava/util/List;)V' { + 0 7 + 1 7 + 2 7 + 3 7 + 4 7 + 5 7 + 6 7 + 7 7 + 8 7 + 9 7 + a 7 + b 7 + c 8 + d 8 + e 8 + f 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 8 + 15 8 + 16 8 + 17 9 + 18 9 + 19 9 + 21 9 + 25 9 + 26 9 + 2a 9 + 2e 9 + 2f 9 + 30 9 + 31 9 + 32 9 + 33 9 + 34 7 + 35 7 + 36 7 + 3d 11 + 3e 12 + 3f 12 + 40 12 + 41 12 + 42 14 + } +} + +Lines mapping: +12 <-> 8 +13 <-> 9 +14 <-> 10 +17 <-> 12 +18 <-> 13 +20 <-> 15 +Not mapped: +19 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptions.dec b/testData/results/pkg/TestTryFinallyMarkerExceptions.dec new file mode 100644 index 0000000000..ac34dea490 --- /dev/null +++ b/testData/results/pkg/TestTryFinallyMarkerExceptions.dec @@ -0,0 +1,153 @@ +package pkg; + +public class TestTryFinallyMarkerExceptions { + public void test0() { + try { + System.out.println("Hello");// 8 + } finally { + long l = 5L;// 10 + } + }// 16 + + public void test1() { + try { + System.out.println("Hello");// 20 + } finally { + System.out.println("Finally");// 22 + } + + System.out.println("Bye");// 29 + }// 30 + + public void test2(int i) { + try { + System.out.println("Hello");// 35 + } finally { + System.out.println("Finally");// 37 + if (i > 0) {// 38 + System.out.println(i);// 39 + return;// 40 + } + } + + System.out.println("Bye");// 52 + }// 53 +} + +class 'pkg/TestTryFinallyMarkerExceptions' { + method 'test0 ()V' { + 0 5 + 1 5 + 2 5 + 3 5 + 4 5 + 5 5 + 6 5 + 7 5 + c 7 + d 7 + e 7 + f 7 + 16 9 + } + + method 'test1 ()V' { + 0 13 + 1 13 + 2 13 + 3 13 + 4 13 + 5 13 + 6 13 + 7 13 + c 15 + d 15 + e 15 + f 15 + 10 15 + 11 15 + 12 15 + 13 15 + 1e 18 + 1f 18 + 20 18 + 21 18 + 22 18 + 23 18 + 24 18 + 25 18 + 26 19 + } + + method 'test2 (I)V' { + 0 23 + 1 23 + 2 23 + 3 23 + 4 23 + 5 23 + 6 23 + 7 23 + c 25 + d 25 + e 25 + f 25 + 10 25 + 11 25 + 12 25 + 13 25 + 14 26 + 15 26 + 16 26 + 17 26 + 18 27 + 19 27 + 1a 27 + 1b 27 + 1c 27 + 1d 27 + 1e 27 + 1f 28 + 36 32 + 37 32 + 38 32 + 39 32 + 3a 32 + 3b 32 + 3c 32 + 3d 32 + 3e 33 + } +} + +Lines mapping: +8 <-> 6 +10 <-> 8 +16 <-> 10 +20 <-> 14 +22 <-> 16 +29 <-> 19 +30 <-> 20 +35 <-> 24 +37 <-> 26 +38 <-> 27 +39 <-> 28 +40 <-> 29 +52 <-> 33 +53 <-> 34 +Not mapped: +9 +11 +12 +14 +21 +23 +24 +26 +36 +42 +43 +45 +46 +47 +48 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec new file mode 100644 index 0000000000..15a6c5e0ce --- /dev/null +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec @@ -0,0 +1,445 @@ +package pkg; + +public class TestTryFinallyMarkerExceptionsInvalid { + // $VF: Could not inline inconsistent finally blocks + public Object testReturn() { + try { + System.out.println("Hello");// 8 + } catch (Throwable var3) { + System.out.println("Finally");// 10 + return e;// 11 + } + + System.out.println("Finally");// 14 + System.out.println("Bye");// 17 + return null;// 18 + } + + // $VF: Could not inline inconsistent finally blocks + public void testLogged(int i) { + try { + System.out.println("Hello");// 24 + } catch (Throwable var4) { + System.out.println(e.getMessage());// 27 + System.out.println("Finally");// 29 + throw e;// 30 + } + + System.out.println("Finally");// 33 + System.out.println("Bye");// 36 + }// 37 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testWeirdCatch(int i) { + boolean var5 = false /* VF: Semaphore variable */; + + label26: { + try { + var5 = true; + System.out.println("Hello");// 44 + var5 = false; + break label26; + } catch (NullPointerException npe) { + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 48 + } + } + + System.out.println("NPE");// 46 + } + + System.out.println("Finally");// 52 + System.out.println("Bye");// 55 + }// 56 + + public void testWeirdCatch2(int param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: getstatic java/lang/System.out Ljava/io/PrintStream; + // 03: ldc "Hello" + // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 08: goto 22 + // 0b: astore 2 + // 0c: getstatic java/lang/System.out Ljava/io/PrintStream; + // 0f: ldc "Finally" + // 11: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 14: goto 22 + // 17: astore 2 + // 18: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1b: ldc "Finally" + // 1d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 20: aload 2 + // 21: athrow + // 22: getstatic java/lang/System.out Ljava/io/PrintStream; + // 25: ldc "Finally" + // 27: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 2a: getstatic java/lang/System.out Ljava/io/PrintStream; + // 2d: ldc "Bye" + // 2f: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 32: return + // try (0 -> 3): 4 java/lang/NullPointerException + // try (0 -> 3): 9 null + } + + public void testWeirdCatch3(int i) { + label26: { + NullPointerException npe; + try { + System.out.println("Hello");// 81 + break label26; + } catch (NullPointerException var5) { + npe = var5;// 82 + } finally { + System.out.println("Finally");// 86 + } + + System.out.println("NPE: " + npe.getMessage());// 84 + } + + System.out.println("Bye");// 93 + }// 94 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testBlockReuse(int i) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 101 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally");// 103 + if (i > 0) {// 104 + System.out.println("Cool 1");// 105 + } else { + System.out.println("Cool 2");// 107 + } + + if (i < 0) {// 109 + } + } + } + + System.out.println("Finally");// 113 + if (i > 0) {// 114 + } + + System.out.println("Cool 1");// 115 + if (i < 0) {// 116 + } + + System.out.println("Bye");// 119 + }// 120 +} + +class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { + method 'testReturn ()Ljava/lang/Object;' { + 0 6 + 1 6 + 2 6 + 3 6 + 4 6 + 5 6 + 6 6 + 7 6 + c 8 + d 8 + e 8 + f 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 9 + 15 9 + 16 12 + 17 12 + 18 12 + 19 12 + 1a 12 + 1b 12 + 1c 12 + 1d 12 + 1e 13 + 1f 13 + 20 13 + 21 13 + 22 13 + 23 13 + 24 13 + 25 13 + 26 14 + 27 14 + } + + method 'testLogged (I)V' { + 0 20 + 1 20 + 2 20 + 3 20 + 4 20 + 5 20 + 6 20 + 7 20 + c 22 + d 22 + e 22 + f 22 + 10 22 + 11 22 + 12 22 + 13 22 + 14 22 + 15 22 + 16 23 + 17 23 + 18 23 + 19 23 + 1a 23 + 1b 23 + 1c 23 + 1d 23 + 1e 24 + 1f 24 + 20 27 + 21 27 + 22 27 + 23 27 + 24 27 + 25 27 + 26 27 + 27 27 + 28 28 + 29 28 + 2a 28 + 2b 28 + 2c 28 + 2d 28 + 2e 28 + 2f 28 + 30 29 + } + + method 'testWeirdCatch (I)V' { + 0 38 + 1 38 + 2 38 + 3 38 + 4 38 + 5 38 + 6 38 + 7 38 + c 49 + d 49 + e 49 + f 49 + 10 49 + 11 49 + 12 49 + 13 49 + 18 45 + 19 45 + 1a 45 + 1b 45 + 1c 45 + 1d 45 + 1e 45 + 1f 45 + 22 52 + 23 52 + 24 52 + 25 52 + 26 52 + 27 52 + 28 52 + 29 52 + 2a 53 + 2b 53 + 2c 53 + 2d 53 + 2e 53 + 2f 53 + 30 53 + 31 53 + 32 54 + } + + method 'testWeirdCatch3 (I)V' { + 0 89 + 1 89 + 2 89 + 3 89 + 4 89 + 5 89 + 6 89 + 7 89 + b 92 + 14 97 + 15 97 + 16 97 + 1e 97 + 1f 97 + 23 97 + 24 97 + 25 97 + 26 97 + 2a 97 + 2b 97 + 2c 97 + 2d 97 + 2e 97 + 2f 97 + 34 94 + 35 94 + 36 94 + 37 94 + 38 94 + 39 94 + 3a 94 + 3b 94 + 46 100 + 47 100 + 48 100 + 49 100 + 4a 100 + 4b 100 + 4c 100 + 4d 100 + 4e 101 + } + + method 'testBlockReuse (I)V' { + 0 109 + 1 109 + 2 109 + 3 109 + 4 109 + 5 109 + 6 109 + 7 109 + c 113 + d 113 + e 113 + f 113 + 10 113 + 11 113 + 12 113 + 13 113 + 14 114 + 15 114 + 16 114 + 17 114 + 18 115 + 19 115 + 1a 115 + 1b 115 + 1c 115 + 1d 115 + 1e 115 + 1f 115 + 23 117 + 24 117 + 25 117 + 26 117 + 27 117 + 28 117 + 29 117 + 2a 117 + 2b 120 + 2c 120 + 2d 120 + 2e 120 + 31 125 + 32 125 + 33 125 + 34 125 + 35 125 + 36 125 + 37 125 + 38 125 + 39 126 + 3a 126 + 3b 126 + 3c 126 + 3d 129 + 3e 129 + 3f 129 + 40 129 + 41 129 + 42 129 + 43 129 + 44 129 + 45 130 + 46 130 + 47 130 + 48 130 + 49 133 + 4a 133 + 4b 133 + 4c 133 + 4d 133 + 4e 133 + 4f 133 + 50 133 + 51 134 + } +} + +Lines mapping: +8 <-> 7 +10 <-> 9 +11 <-> 10 +14 <-> 13 +17 <-> 14 +18 <-> 15 +24 <-> 21 +27 <-> 23 +29 <-> 24 +30 <-> 25 +33 <-> 28 +36 <-> 29 +37 <-> 30 +44 <-> 39 +46 <-> 50 +48 <-> 46 +52 <-> 53 +55 <-> 54 +56 <-> 55 +81 <-> 90 +82 <-> 93 +84 <-> 98 +86 <-> 95 +93 <-> 101 +94 <-> 102 +101 <-> 110 +103 <-> 114 +104 <-> 115 +105 <-> 116 +107 <-> 118 +109 <-> 121 +113 <-> 126 +114 <-> 127 +115 <-> 130 +116 <-> 131 +119 <-> 134 +120 <-> 135 +Not mapped: +9 +12 +25 +31 +45 +47 +49 +50 +83 +85 +87 +88 +90 +102 +110 +111 diff --git a/testData/src/java8/pkg/TestTryCatchNoIncrement.java b/testData/src/java8/pkg/TestTryCatchNoIncrement.java new file mode 100644 index 0000000000..1ea3363464 --- /dev/null +++ b/testData/src/java8/pkg/TestTryCatchNoIncrement.java @@ -0,0 +1,53 @@ +package pkg; + +import org.vineflower.marker.UnCatchException; + +import java.io.File; +import java.net.URL; +import java.util.List; + +public class TestTryCatchNoIncrement { + public final void baseline(List items) { + try { + for (int i = 0; i < items.size(); i++) { + String item = items.get(i); + System.out.println(i + ": " + item); + } + } + catch (Throwable ex2) { + ex2.printStackTrace(); + } + } + + public final void skippedInc(List items) { + try { + int i = 0; + while (i < items.size()) { + String item = items.get(i); + System.out.println(i + ": " + item); + try { + i++; + } catch (UnCatchException ex) { + } + } + } + catch (Throwable ex2) { + ex2.printStackTrace(); + } + + } + public final void skipPrinting(List items) { + try { + for (int i = 0; i < items.size(); i++) { + String item = items.get(i); + try { + System.out.println(i + ": " + item); + } catch (UnCatchException ex) { + } + } + } + catch (Throwable ex2) { + ex2.printStackTrace(); + } + } +} diff --git a/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java b/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java new file mode 100644 index 0000000000..4eaf2e80cf --- /dev/null +++ b/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java @@ -0,0 +1,54 @@ +package pkg; + +import org.vineflower.marker.CatchAllException; + +public class TestTryFinallyMarkerExceptions { + public void test0() { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + long l = 5; + throw e; + } + { + long l = 5; + } + } + + public void test1() { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + throw e; + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + + public void test2(int i) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if(i > 0) { + System.out.println(i); + return; + } + throw e; + } + { + System.out.println("Finally"); + if(i > 0) { + System.out.println(i); + return; + } + } + + System.out.println("Bye"); + } +} diff --git a/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java new file mode 100644 index 0000000000..152d43b47c --- /dev/null +++ b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java @@ -0,0 +1,121 @@ +package pkg; + +import org.vineflower.marker.CatchAllException; + +public class TestTryFinallyMarkerExceptionsInvalid { + public Object testReturn() { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + return e; // return instead of throw + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + return null; + } + + + public void testLogged(int i) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + // eg logger injection + System.out.println(e.getMessage()); + + System.out.println("Finally"); + throw e; + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + + public void testWeirdCatch(int i) { + // In a try catch finally, the catch is actually inside the try block of the finally + // here we don't. Such cases have been seen in non java code. + try { + System.out.println("Hello"); + } catch (NullPointerException npe) { + System.out.println("NPE"); + } catch (CatchAllException e) { + System.out.println("Finally"); + throw e; + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + public void testWeirdCatch2(int i) { + // In a try catch finally, the catch is actually inside the try block of the finally + // here we don't. Such cases have been seen in non java code. + try { + System.out.println("Hello"); + } catch (NullPointerException npe) { + System.out.println("Finally"); + } catch (CatchAllException e) { + System.out.println("Finally"); + throw e; + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + + public void testWeirdCatch3(int i) { + // In a try catch finally, the catch is actually inside the try block of the finally + // here we don't. Such cases have been seen in non java code. + try { + System.out.println("Hello"); + } catch (NullPointerException npe) { + System.out.println("Finally"); + System.out.println("NPE: " + npe.getMessage()); + } catch (CatchAllException e) { + System.out.println("Finally"); + throw e; + } + { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + + public void testBlockReuse(int i) { + // while matching basic blocks, just because a "sample" block has been seen before + // does not guarantee it matches with the block we are inspecting. + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if(i > 0){ + System.out.println("Cool 1"); + } else { + System.out.println("Cool 2"); + } + if(i < 0); // break up basic block + throw e; + } + { + System.out.println("Finally"); + if(i > 0); + System.out.println("Cool 1"); + if(i < 0); // break up basic block + } + + System.out.println("Bye"); + } +} From 5d72fa45b7febc4686f71313713e593833b24d49 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Fri, 15 May 2026 10:05:58 +0200 Subject: [PATCH 10/29] Make "debug marker exceptions" unit test only --- .../decompiler/main/extern/IFernflowerPreferences.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index eb59b2502b..ac33113896 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -324,6 +324,7 @@ public interface IFernflowerPreferences { String DUMP_ORIGINAL_LINES = "__dump_original_lines__"; String UNIT_TEST_MODE = "__unit_test_mode__"; + String DEBUG_MARKER_EXCEPTIONS = "__debug_marker_exceptions__"; String LINE_SEPARATOR_WIN = "\r\n"; String LINE_SEPARATOR_UNX = "\n"; @@ -418,11 +419,6 @@ public interface IFernflowerPreferences { @Type(DecompilerOption.Type.STRING) String METHOD_TO_DECOMPILE = "method-to-decompile"; - @Name("DEBUG: Enable special handling of marker exceptions") - @Description("") - @Type(DecompilerOption.Type.BOOLEAN) - String DEBUG_MARKER_EXCEPTIONS = "debug-marker-exceptions"; - Map DEFAULTS = getDefaults(); static Map getDefaults() { @@ -483,6 +479,7 @@ static Map getDefaults() { defaults.put(ERROR_MESSAGE, "Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)"); defaults.put(UNIT_TEST_MODE, "0"); defaults.put(DUMP_ORIGINAL_LINES, "0"); + defaults.put(DEBUG_MARKER_EXCEPTIONS, "0"); defaults.put(THREADS, String.valueOf(Runtime.getRuntime().availableProcessors())); defaults.put(SKIP_EXTRA_FILES, "0"); defaults.put(WARN_INCONSISTENT_INNER_CLASSES, "1"); @@ -500,7 +497,6 @@ static Map getDefaults() { defaults.put(VALIDATE_INNER_CLASSES_NAMES, "1"); defaults.put(PRETTIFY_IFS, "1"); defaults.put(METHOD_TO_DECOMPILE, ""); - defaults.put(DEBUG_MARKER_EXCEPTIONS, "0"); return Collections.unmodifiableMap(defaults); } From 931262167195d74c6c7e0f6d8bb5d5edc428035b Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Wed, 20 May 2026 04:07:30 +0200 Subject: [PATCH 11/29] Add more fake finally tests --- .../pkg/TestTryFinallyMarkerExceptions.dec | 33 + .../TestTryFinallyMarkerExceptionsInvalid.dec | 1863 ++++++++++++++--- ...estTryFinallyMarkerExceptionsInvalid_1.dec | 1762 ++++++++++++++++ ...estTryFinallyMarkerExceptionsInvalid_2.dec | 1762 ++++++++++++++++ .../pkg/TestTryFinallyMarkerExceptions.java | 16 +- ...TestTryFinallyMarkerExceptionsInvalid.java | 341 ++- .../decompiler/SingleClassesTestBase.java | 23 +- 7 files changed, 5513 insertions(+), 287 deletions(-) create mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec create mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptions.dec b/testData/results/pkg/TestTryFinallyMarkerExceptions.dec index ac34dea490..44c888e463 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptions.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptions.dec @@ -32,6 +32,16 @@ public class TestTryFinallyMarkerExceptions { System.out.println("Bye");// 52 }// 53 + + public void testNoTryExit(boolean b) { + try { + while (true) { + System.out.println("Hello");// 59 + } + } finally { + System.out.println("Finally");// 62 + } + } } class 'pkg/TestTryFinallyMarkerExceptions' { @@ -118,6 +128,25 @@ class 'pkg/TestTryFinallyMarkerExceptions' { 3d 32 3e 33 } + + method 'testNoTryExit (Z)V' { + 0 38 + 1 38 + 2 38 + 3 38 + 4 38 + 5 38 + 6 38 + 7 38 + c 41 + d 41 + e 41 + f 41 + 10 41 + 11 41 + 12 41 + 13 41 + } } Lines mapping: @@ -135,6 +164,8 @@ Lines mapping: 40 <-> 29 52 <-> 33 53 <-> 34 +59 <-> 39 +62 <-> 42 Not mapped: 9 11 @@ -151,3 +182,5 @@ Not mapped: 46 47 48 +61 +63 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec index 15a6c5e0ce..a85d8a65e3 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec @@ -1,5 +1,7 @@ package pkg; +import org.vineflower.marker.CatchAllException; + public class TestTryFinallyMarkerExceptionsInvalid { // $VF: Could not inline inconsistent finally blocks public Object testReturn() { @@ -133,299 +135,1531 @@ public class TestTryFinallyMarkerExceptionsInvalid { System.out.println("Bye");// 119 }// 120 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testInjectWrongException(boolean b) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 124 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally start");// 126 + CatchAllException e; + if (b) {// 127 + e = new CatchAllException("yo");// 128 + } + + System.out.println("Finally end");// 130 + throw e;// 131 + } + } + + System.out.println("Finally start");// 134 + if (b) {// 135 + new CatchAllException("yo");// 136 + } + + System.out.println("Finally end");// 138 + System.out.println("Bye");// 141 + }// 142 + + public void testMultiImplicitExits(int i) { + try { + System.out.println("Hello");// 146 + } finally { + System.out.println("Finally");// 148 + if (i > 0) {// 149 + System.out.println("Positive!");// 150 + } else if (i == 0) {// 152 + System.out.println("ZERO");// 153 + } else { + System.out.println("Negative!");// 156 + } + } + + System.out.println("Bye 2");// 167 + }// 173 + + public void testConfusion1(String a, String b) { + try { + System.out.println("Hello");// 177 + } finally { + System.out.println("Finally");// 179 + System.out.println(a);// 180 + } + + System.out.println("Bye");// 187 + }// 188 + + public void testConfusion2() { + try { + System.out.println("Hello");// 193 + } finally { + System.out.println("Finally");// 195 + String x = "X";// 196 + String y = "Y";// 197 + String z = "Z";// 198 + x = x + z;// 199 + y = y + x;// 200 + z = z + y;// 201 + System.out.println(z);// 202 + } + + System.out.println("Bye");// 215 + }// 216 + + public void testMismatchedSwitch(int i) { + try { + System.out.println("Hello");// 221 + } finally { + System.out.println("Finally");// 223 + switch (i) {// 224 + case 10: + System.out.println("10");// 226 + case 9: + System.out.println("9");// 228 + case 8: + System.out.println("8");// 230 + case 7: + System.out.println("7");// 232 + case 6: + System.out.println("6");// 234 + case 5: + System.out.println("5");// 236 + case 4: + System.out.println("4");// 238 + case 3: + System.out.println("3");// 240 + case 2: + System.out.println("2");// 242 + case 1: + System.out.println("1");// 244 + case 0: + System.out.println("Lift off!");// 246 + } + } + + System.out.println("Bye");// 277 + }// 278 + + public void testMismatchedOutputExit(int a, int b) { + label53: + while (a > 0) {// 282 + System.out.println("A: " + a);// 283 + a--;// 284 + + for (; b > 0; System.out.println("Beep")) {// 286 310 + a++;// 287 + System.out.println("B: " + b);// 288 + + try { + b--;// 291 + System.out.println("Hello");// 292 + } finally { + System.out.println("Finally");// 294 + if (a > b) {// 295 + a--;// 296 + continue label53;// 297 + } + + System.out.println("Boop");// 299 + } + } + + System.out.println("BLORB");// 312 + } + + System.out.println("Bye");// 314 + }// 315 + + public void testMismatchedOutputExit3(int a, int b, int c) { + label84: + while (a > 0) {// 320 + System.out.println("A: " + a);// 321 + a--;// 322 + + label82: + while (b > 0) {// 324 + a++;// 325 + System.out.println("B: " + b);// 326 + + for (; c > 0; System.out.println("Lost")) {// 329 371 + c -= b;// 330 + + try { + b--;// 337 + System.out.println("Hello");// 338 + if (c < a) {// 339 + continue label82; + } + } finally { + System.out.println("Finally");// 343 + if (a > b) {// 344 + a--;// 345 + continue label84;// 346 + } + + System.out.println("Boop");// 348 + } + } + + System.out.println("Beep");// 373 + } + + System.out.println("BLORB");// 375 + } + + System.out.println("Bye");// 377 + }// 378 + + public void testMismatchedOutputExitReturn(int a, int b) { + label54: + while (a > 0) {// 383 + System.out.println("A: " + a);// 384 + a--;// 385 + + for (; b > 0; System.out.println("Beep")) {// 387 411 + a++;// 388 + System.out.println("B: " + b);// 389 + + try { + b--;// 392 + System.out.println("Hello");// 393 + } finally { + System.out.println("Finally");// 395 + if (a > b) {// 396 + a--;// 397 + continue label54;// 398 + } + + System.out.println("Boop");// 400 + } + } + + System.out.println("BLORB");// 413 + } + + System.out.println("Bye");// 415 + }// 416 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testMismatchedOutputExitReturnInner(int a, int b) { + while (a > 0) {// 420 + System.out.println("A: " + a);// 421 + a--;// 422 + + while (b > 0) {// 424 + a++;// 425 + System.out.println("B: " + b);// 426 + boolean var5 = false /* VF: Semaphore variable */; + + try { + var5 = true; + b--;// 429 + System.out.println("Hello");// 430 + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 432 + if (a > b) {// 433 + a--;// 434 + return;// 435 + } + + System.out.println("Boop");// 437 + } + } + + System.out.println("Finally");// 441 + if (a > b) {// 442 + a--;// 443 + } else { + System.out.println("Boop");// 446 + System.out.println("Beep");// 448 + } + } + + System.out.println("BLORB");// 450 + } + + System.out.println("Bye");// 452 + }// 453 } class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { method 'testReturn ()Ljava/lang/Object;' { - 0 6 - 1 6 - 2 6 - 3 6 - 4 6 - 5 6 - 6 6 - 7 6 - c 8 - d 8 - e 8 - f 8 - 10 8 - 11 8 - 12 8 - 13 8 - 14 9 - 15 9 - 16 12 - 17 12 - 18 12 - 19 12 - 1a 12 - 1b 12 - 1c 12 - 1d 12 - 1e 13 - 1f 13 - 20 13 - 21 13 - 22 13 - 23 13 - 24 13 - 25 13 - 26 14 - 27 14 + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + c 10 + d 10 + e 10 + f 10 + 10 10 + 11 10 + 12 10 + 13 10 + 14 11 + 15 11 + 16 14 + 17 14 + 18 14 + 19 14 + 1a 14 + 1b 14 + 1c 14 + 1d 14 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 15 + 23 15 + 24 15 + 25 15 + 26 16 + 27 16 } method 'testLogged (I)V' { - 0 20 - 1 20 - 2 20 - 3 20 - 4 20 - 5 20 - 6 20 - 7 20 - c 22 - d 22 - e 22 - f 22 - 10 22 - 11 22 - 12 22 - 13 22 - 14 22 - 15 22 - 16 23 - 17 23 - 18 23 - 19 23 - 1a 23 - 1b 23 - 1c 23 - 1d 23 - 1e 24 - 1f 24 - 20 27 - 21 27 - 22 27 - 23 27 - 24 27 - 25 27 - 26 27 - 27 27 - 28 28 - 29 28 - 2a 28 - 2b 28 - 2c 28 - 2d 28 - 2e 28 - 2f 28 - 30 29 + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + 7 22 + c 24 + d 24 + e 24 + f 24 + 10 24 + 11 24 + 12 24 + 13 24 + 14 24 + 15 24 + 16 25 + 17 25 + 18 25 + 19 25 + 1a 25 + 1b 25 + 1c 25 + 1d 25 + 1e 26 + 1f 26 + 20 29 + 21 29 + 22 29 + 23 29 + 24 29 + 25 29 + 26 29 + 27 29 + 28 30 + 29 30 + 2a 30 + 2b 30 + 2c 30 + 2d 30 + 2e 30 + 2f 30 + 30 31 } method 'testWeirdCatch (I)V' { - 0 38 - 1 38 - 2 38 - 3 38 - 4 38 - 5 38 - 6 38 - 7 38 - c 49 - d 49 - e 49 - f 49 - 10 49 - 11 49 - 12 49 - 13 49 - 18 45 - 19 45 - 1a 45 - 1b 45 - 1c 45 - 1d 45 - 1e 45 - 1f 45 - 22 52 - 23 52 - 24 52 - 25 52 - 26 52 - 27 52 - 28 52 - 29 52 - 2a 53 - 2b 53 - 2c 53 - 2d 53 - 2e 53 - 2f 53 - 30 53 - 31 53 - 32 54 + 0 40 + 1 40 + 2 40 + 3 40 + 4 40 + 5 40 + 6 40 + 7 40 + c 51 + d 51 + e 51 + f 51 + 10 51 + 11 51 + 12 51 + 13 51 + 18 47 + 19 47 + 1a 47 + 1b 47 + 1c 47 + 1d 47 + 1e 47 + 1f 47 + 22 54 + 23 54 + 24 54 + 25 54 + 26 54 + 27 54 + 28 54 + 29 54 + 2a 55 + 2b 55 + 2c 55 + 2d 55 + 2e 55 + 2f 55 + 30 55 + 31 55 + 32 56 } method 'testWeirdCatch3 (I)V' { - 0 89 - 1 89 - 2 89 - 3 89 - 4 89 - 5 89 - 6 89 - 7 89 - b 92 - 14 97 - 15 97 - 16 97 - 1e 97 - 1f 97 - 23 97 - 24 97 - 25 97 - 26 97 - 2a 97 - 2b 97 - 2c 97 - 2d 97 - 2e 97 - 2f 97 - 34 94 - 35 94 - 36 94 - 37 94 - 38 94 - 39 94 - 3a 94 - 3b 94 - 46 100 - 47 100 - 48 100 - 49 100 - 4a 100 - 4b 100 - 4c 100 - 4d 100 - 4e 101 + 0 91 + 1 91 + 2 91 + 3 91 + 4 91 + 5 91 + 6 91 + 7 91 + b 94 + 14 99 + 15 99 + 16 99 + 1e 99 + 1f 99 + 23 99 + 24 99 + 25 99 + 26 99 + 2a 99 + 2b 99 + 2c 99 + 2d 99 + 2e 99 + 2f 99 + 34 96 + 35 96 + 36 96 + 37 96 + 38 96 + 39 96 + 3a 96 + 3b 96 + 46 102 + 47 102 + 48 102 + 49 102 + 4a 102 + 4b 102 + 4c 102 + 4d 102 + 4e 103 } method 'testBlockReuse (I)V' { - 0 109 - 1 109 - 2 109 - 3 109 - 4 109 - 5 109 - 6 109 - 7 109 - c 113 - d 113 - e 113 - f 113 - 10 113 - 11 113 - 12 113 - 13 113 - 14 114 - 15 114 - 16 114 - 17 114 - 18 115 - 19 115 - 1a 115 - 1b 115 - 1c 115 - 1d 115 - 1e 115 - 1f 115 - 23 117 - 24 117 - 25 117 - 26 117 - 27 117 - 28 117 - 29 117 - 2a 117 - 2b 120 - 2c 120 - 2d 120 - 2e 120 - 31 125 - 32 125 - 33 125 - 34 125 - 35 125 - 36 125 - 37 125 - 38 125 - 39 126 - 3a 126 - 3b 126 - 3c 126 - 3d 129 - 3e 129 - 3f 129 - 40 129 - 41 129 - 42 129 - 43 129 - 44 129 - 45 130 - 46 130 - 47 130 - 48 130 - 49 133 - 4a 133 - 4b 133 - 4c 133 - 4d 133 - 4e 133 - 4f 133 - 50 133 - 51 134 + 0 111 + 1 111 + 2 111 + 3 111 + 4 111 + 5 111 + 6 111 + 7 111 + c 115 + d 115 + e 115 + f 115 + 10 115 + 11 115 + 12 115 + 13 115 + 14 116 + 15 116 + 16 116 + 17 116 + 18 117 + 19 117 + 1a 117 + 1b 117 + 1c 117 + 1d 117 + 1e 117 + 1f 117 + 23 119 + 24 119 + 25 119 + 26 119 + 27 119 + 28 119 + 29 119 + 2a 119 + 2b 122 + 2c 122 + 2d 122 + 2e 122 + 31 127 + 32 127 + 33 127 + 34 127 + 35 127 + 36 127 + 37 127 + 38 127 + 39 128 + 3a 128 + 3b 128 + 3c 128 + 3d 131 + 3e 131 + 3f 131 + 40 131 + 41 131 + 42 131 + 43 131 + 44 131 + 45 132 + 46 132 + 47 132 + 48 132 + 49 135 + 4a 135 + 4b 135 + 4c 135 + 4d 135 + 4e 135 + 4f 135 + 50 135 + 51 136 + } + + method 'testInjectWrongException (Z)V' { + 0 144 + 1 144 + 2 144 + 3 144 + 4 144 + 5 144 + 6 144 + 7 144 + c 148 + d 148 + e 148 + f 148 + 10 148 + 11 148 + 12 148 + 13 148 + 14 150 + 15 150 + 16 150 + 17 150 + 1c 151 + 1d 151 + 21 151 + 22 154 + 23 154 + 24 154 + 25 154 + 26 154 + 27 154 + 28 154 + 29 154 + 2a 155 + 2b 155 + 2c 159 + 2d 159 + 2e 159 + 2f 159 + 30 159 + 31 159 + 32 159 + 33 159 + 34 160 + 35 160 + 36 160 + 37 160 + 3c 161 + 3d 161 + 42 164 + 43 164 + 44 164 + 45 164 + 46 164 + 47 164 + 48 164 + 49 164 + 4a 165 + 4b 165 + 4c 165 + 4d 165 + 4e 165 + 4f 165 + 50 165 + 51 165 + 52 166 + } + + method 'testMultiImplicitExits (I)V' { + 0 170 + 1 170 + 2 170 + 3 170 + 4 170 + 5 170 + 6 170 + 7 170 + c 172 + d 172 + e 172 + f 172 + 10 172 + 11 172 + 12 172 + 13 172 + 14 173 + 15 173 + 16 173 + 17 173 + 18 174 + 19 174 + 1a 174 + 1b 174 + 1c 174 + 1d 174 + 1e 174 + 1f 174 + 22 175 + 23 175 + 24 175 + 25 175 + 26 176 + 27 176 + 28 176 + 29 176 + 2a 176 + 2b 176 + 2c 176 + 2d 176 + 30 178 + 31 178 + 32 178 + 33 178 + 34 178 + 35 178 + 36 178 + 37 178 + 65 182 + 66 182 + 67 182 + 68 182 + 69 182 + 6a 182 + 6b 182 + 6c 182 + 80 183 + } + + method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { + 0 187 + 1 187 + 2 187 + 3 187 + 4 187 + 5 187 + 6 187 + 7 187 + c 189 + d 189 + e 189 + f 189 + 10 189 + 11 189 + 12 189 + 13 189 + 14 190 + 15 190 + 16 190 + 17 190 + 18 190 + 19 190 + 1a 190 + 2c 193 + 2d 193 + 2e 193 + 2f 193 + 30 193 + 31 193 + 32 193 + 33 193 + 34 194 + } + + method 'testConfusion2 ()V' { + 0 198 + 1 198 + 2 198 + 3 198 + 4 198 + 5 198 + 6 198 + 7 198 + d 200 + e 200 + f 200 + 10 200 + 11 200 + 12 200 + 13 200 + 14 200 + 15 201 + 16 201 + 17 201 + 18 202 + 19 202 + 1a 202 + 1b 203 + 1c 203 + 1d 203 + 25 204 + 29 204 + 2d 204 + 2e 204 + 2f 204 + 30 204 + 38 205 + 3c 205 + 40 205 + 41 205 + 42 205 + 43 205 + 4b 206 + 4f 206 + 53 206 + 54 206 + 55 206 + 56 206 + 57 207 + 58 207 + 59 207 + 5a 207 + 5b 207 + 5c 207 + 5d 207 + b2 210 + b3 210 + b4 210 + b5 210 + b6 210 + b7 210 + b8 210 + b9 210 + ba 211 + } + + method 'testMismatchedSwitch (I)V' { + 0 215 + 1 215 + 2 215 + 3 215 + 4 215 + 5 215 + 6 215 + 7 215 + c 217 + d 217 + e 217 + f 217 + 10 217 + 11 217 + 12 217 + 13 217 + 14 218 + 15 218 + 16 218 + 17 218 + 18 218 + 19 218 + 1a 218 + 1b 218 + 1c 218 + 1d 218 + 1e 218 + 1f 218 + 20 218 + 21 218 + 22 218 + 23 218 + 24 218 + 25 218 + 26 218 + 27 218 + 28 218 + 29 218 + 2a 218 + 2b 218 + 2c 218 + 2d 218 + 2e 218 + 2f 218 + 30 218 + 31 218 + 32 218 + 33 218 + 34 218 + 35 218 + 36 218 + 37 218 + 38 218 + 39 218 + 3a 218 + 3b 218 + 3c 218 + 3d 218 + 3e 218 + 3f 218 + 40 218 + 41 218 + 42 218 + 43 218 + 44 218 + 45 218 + 46 218 + 47 218 + 48 218 + 49 218 + 4a 218 + 4b 218 + 4c 218 + 4d 218 + 4e 218 + 4f 218 + 50 220 + 51 220 + 52 220 + 53 220 + 54 220 + 55 220 + 56 220 + 57 220 + 58 222 + 59 222 + 5a 222 + 5b 222 + 5c 222 + 5d 222 + 5e 222 + 5f 222 + 60 224 + 61 224 + 62 224 + 63 224 + 64 224 + 65 224 + 66 224 + 67 224 + 68 226 + 69 226 + 6a 226 + 6b 226 + 6c 226 + 6d 226 + 6e 226 + 6f 226 + 70 228 + 71 228 + 72 228 + 73 228 + 74 228 + 75 228 + 76 228 + 77 228 + 78 230 + 79 230 + 7a 230 + 7b 230 + 7c 230 + 7d 230 + 7e 230 + 7f 230 + 80 232 + 81 232 + 82 232 + 83 232 + 84 232 + 85 232 + 86 232 + 87 232 + 88 234 + 89 234 + 8a 234 + 8b 234 + 8c 234 + 8d 234 + 8e 234 + 8f 234 + 90 236 + 91 236 + 92 236 + 93 236 + 94 236 + 95 236 + 96 236 + 97 236 + 98 238 + 99 238 + 9a 238 + 9b 238 + 9c 238 + 9d 238 + 9e 238 + 9f 238 + a0 240 + a1 240 + a2 240 + a3 240 + a4 240 + a5 240 + a6 240 + a7 240 + 144 244 + 145 244 + 146 244 + 147 244 + 148 244 + 149 244 + 14a 244 + 14b 244 + 14c 245 + } + + method 'testMismatchedOutputExit (II)V' { + 0 249 + 1 249 + 2 249 + 3 249 + 4 250 + 5 250 + 6 250 + e 250 + f 250 + 13 250 + 17 250 + 18 250 + 19 250 + 1a 250 + 1b 250 + 1c 250 + 1d 251 + 1e 251 + 1f 251 + 20 253 + 21 253 + 22 253 + 23 253 + 24 254 + 25 254 + 26 254 + 27 255 + 28 255 + 29 255 + 31 255 + 32 255 + 36 255 + 3a 255 + 3b 255 + 3c 255 + 3d 255 + 3e 255 + 3f 255 + 40 258 + 41 258 + 42 258 + 43 259 + 44 259 + 45 259 + 46 259 + 47 259 + 48 259 + 49 259 + 4a 259 + 4f 261 + 50 261 + 51 261 + 52 261 + 53 261 + 54 261 + 55 261 + 56 261 + 57 262 + 58 262 + 59 262 + 5a 262 + 5b 262 + 5c 263 + 5d 263 + 5e 263 + 5f 264 + 62 267 + 63 267 + 64 267 + 65 267 + 66 267 + 67 267 + 68 267 + 69 267 + 87 253 + 88 253 + 89 253 + 8a 253 + 8b 253 + 8c 253 + 8d 253 + 8e 253 + 92 271 + 93 271 + 94 271 + 95 271 + 96 271 + 97 271 + 98 271 + 99 271 + 9d 274 + 9e 274 + 9f 274 + a0 274 + a1 274 + a2 274 + a3 274 + a4 274 + a5 275 + } + + method 'testMismatchedOutputExit3 (III)V' { + 0 279 + 1 279 + 2 279 + 3 279 + 4 280 + 5 280 + 6 280 + e 280 + f 280 + 13 280 + 17 280 + 18 280 + 19 280 + 1a 280 + 1b 280 + 1c 280 + 1d 281 + 1e 281 + 1f 281 + 20 284 + 21 284 + 22 284 + 23 284 + 24 285 + 25 285 + 26 285 + 27 286 + 28 286 + 29 286 + 31 286 + 32 286 + 36 286 + 3a 286 + 3b 286 + 3c 286 + 3d 286 + 3e 286 + 3f 286 + 40 288 + 41 288 + 42 288 + 43 288 + 45 289 + 47 289 + 48 292 + 49 292 + 4a 292 + 4b 293 + 4c 293 + 4d 293 + 4e 293 + 4f 293 + 50 293 + 51 293 + 52 293 + 53 294 + 54 294 + 55 294 + 56 294 + 57 294 + 60 298 + 61 298 + 62 298 + 63 298 + 64 298 + 65 298 + 66 298 + 67 298 + 68 299 + 69 299 + 6a 299 + 6b 299 + 6c 299 + 6d 300 + 6e 300 + 6f 300 + 70 301 + 73 304 + 74 304 + 75 304 + 76 304 + 77 304 + 78 304 + 79 304 + 7a 304 + ba 288 + bb 288 + bc 288 + bd 288 + be 288 + bf 288 + c0 288 + c1 288 + c5 308 + c6 308 + c7 308 + c8 308 + c9 308 + ca 308 + cb 308 + cc 308 + d0 311 + d1 311 + d2 311 + d3 311 + d4 311 + d5 311 + d6 311 + d7 311 + db 314 + dc 314 + dd 314 + de 314 + df 314 + e0 314 + e1 314 + e2 314 + e3 315 + } + + method 'testMismatchedOutputExitReturn (II)V' { + 0 319 + 1 319 + 2 319 + 3 319 + 4 320 + 5 320 + 6 320 + e 320 + f 320 + 13 320 + 17 320 + 18 320 + 19 320 + 1a 320 + 1b 320 + 1c 320 + 1d 321 + 1e 321 + 1f 321 + 20 323 + 21 323 + 22 323 + 23 323 + 24 324 + 25 324 + 26 324 + 27 325 + 28 325 + 29 325 + 31 325 + 32 325 + 36 325 + 3a 325 + 3b 325 + 3c 325 + 3d 325 + 3e 325 + 3f 325 + 40 328 + 41 328 + 42 328 + 43 329 + 44 329 + 45 329 + 46 329 + 47 329 + 48 329 + 49 329 + 4a 329 + 4f 331 + 50 331 + 51 331 + 52 331 + 53 331 + 54 331 + 55 331 + 56 331 + 57 332 + 58 332 + 59 332 + 5a 332 + 5b 332 + 5c 333 + 5d 333 + 5e 333 + 5f 334 + 62 337 + 63 337 + 64 337 + 65 337 + 66 337 + 67 337 + 68 337 + 69 337 + 85 323 + 86 323 + 87 323 + 88 323 + 89 323 + 8a 323 + 8b 323 + 8c 323 + 90 341 + 91 341 + 92 341 + 93 341 + 94 341 + 95 341 + 96 341 + 97 341 + 9b 344 + 9c 344 + 9d 344 + 9e 344 + 9f 344 + a0 344 + a1 344 + a2 344 + a3 345 + } + + method 'testMismatchedOutputExitReturnInner (II)V' { + 0 349 + 1 349 + 2 349 + 3 349 + 4 350 + 5 350 + 6 350 + e 350 + f 350 + 13 350 + 17 350 + 18 350 + 19 350 + 1a 350 + 1b 350 + 1c 350 + 1d 351 + 1e 351 + 1f 351 + 20 353 + 21 353 + 22 353 + 23 353 + 24 354 + 25 354 + 26 354 + 27 355 + 28 355 + 29 355 + 31 355 + 32 355 + 36 355 + 3a 355 + 3b 355 + 3c 355 + 3d 355 + 3e 355 + 3f 355 + 40 360 + 41 360 + 42 360 + 43 361 + 44 361 + 45 361 + 46 361 + 47 361 + 48 361 + 49 361 + 4a 361 + 4f 365 + 50 365 + 51 365 + 52 365 + 53 365 + 54 365 + 55 365 + 56 365 + 57 366 + 58 366 + 59 366 + 5a 366 + 5b 366 + 5c 367 + 5d 367 + 5e 367 + 5f 368 + 60 371 + 61 371 + 62 371 + 63 371 + 64 371 + 65 371 + 66 371 + 67 371 + 6a 375 + 6b 375 + 6c 375 + 6d 375 + 6e 375 + 6f 375 + 70 375 + 71 375 + 72 376 + 73 376 + 74 376 + 75 376 + 76 376 + 77 377 + 78 377 + 79 377 + 7d 379 + 7e 379 + 7f 379 + 80 379 + 81 379 + 82 379 + 83 379 + 84 379 + 85 380 + 86 380 + 87 380 + 88 380 + 89 380 + 8a 380 + 8b 380 + 8c 380 + 90 384 + 91 384 + 92 384 + 93 384 + 94 384 + 95 384 + 96 384 + 97 384 + 9b 387 + 9c 387 + 9d 387 + 9e 387 + 9f 387 + a0 387 + a1 387 + a2 387 + a3 388 } } Lines mapping: -8 <-> 7 -10 <-> 9 -11 <-> 10 -14 <-> 13 -17 <-> 14 -18 <-> 15 -24 <-> 21 -27 <-> 23 -29 <-> 24 -30 <-> 25 -33 <-> 28 -36 <-> 29 -37 <-> 30 -44 <-> 39 -46 <-> 50 -48 <-> 46 -52 <-> 53 -55 <-> 54 -56 <-> 55 -81 <-> 90 -82 <-> 93 -84 <-> 98 -86 <-> 95 -93 <-> 101 -94 <-> 102 -101 <-> 110 -103 <-> 114 -104 <-> 115 -105 <-> 116 -107 <-> 118 -109 <-> 121 -113 <-> 126 -114 <-> 127 -115 <-> 130 -116 <-> 131 -119 <-> 134 -120 <-> 135 +8 <-> 9 +10 <-> 11 +11 <-> 12 +14 <-> 15 +17 <-> 16 +18 <-> 17 +24 <-> 23 +27 <-> 25 +29 <-> 26 +30 <-> 27 +33 <-> 30 +36 <-> 31 +37 <-> 32 +44 <-> 41 +46 <-> 52 +48 <-> 48 +52 <-> 55 +55 <-> 56 +56 <-> 57 +81 <-> 92 +82 <-> 95 +84 <-> 100 +86 <-> 97 +93 <-> 103 +94 <-> 104 +101 <-> 112 +103 <-> 116 +104 <-> 117 +105 <-> 118 +107 <-> 120 +109 <-> 123 +113 <-> 128 +114 <-> 129 +115 <-> 132 +116 <-> 133 +119 <-> 136 +120 <-> 137 +124 <-> 145 +126 <-> 149 +127 <-> 151 +128 <-> 152 +130 <-> 155 +131 <-> 156 +134 <-> 160 +135 <-> 161 +136 <-> 162 +138 <-> 165 +141 <-> 166 +142 <-> 167 +146 <-> 171 +148 <-> 173 +149 <-> 174 +150 <-> 175 +152 <-> 176 +153 <-> 177 +156 <-> 179 +167 <-> 183 +173 <-> 184 +177 <-> 188 +179 <-> 190 +180 <-> 191 +187 <-> 194 +188 <-> 195 +193 <-> 199 +195 <-> 201 +196 <-> 202 +197 <-> 203 +198 <-> 204 +199 <-> 205 +200 <-> 206 +201 <-> 207 +202 <-> 208 +215 <-> 211 +216 <-> 212 +221 <-> 216 +223 <-> 218 +224 <-> 219 +226 <-> 221 +228 <-> 223 +230 <-> 225 +232 <-> 227 +234 <-> 229 +236 <-> 231 +238 <-> 233 +240 <-> 235 +242 <-> 237 +244 <-> 239 +246 <-> 241 +277 <-> 245 +278 <-> 246 +282 <-> 250 +283 <-> 251 +284 <-> 252 +286 <-> 254 +287 <-> 255 +288 <-> 256 +291 <-> 259 +292 <-> 260 +294 <-> 262 +295 <-> 263 +296 <-> 264 +297 <-> 265 +299 <-> 268 +310 <-> 254 +312 <-> 272 +314 <-> 275 +315 <-> 276 +320 <-> 280 +321 <-> 281 +322 <-> 282 +324 <-> 285 +325 <-> 286 +326 <-> 287 +329 <-> 289 +330 <-> 290 +337 <-> 293 +338 <-> 294 +339 <-> 295 +343 <-> 299 +344 <-> 300 +345 <-> 301 +346 <-> 302 +348 <-> 305 +371 <-> 289 +373 <-> 309 +375 <-> 312 +377 <-> 315 +378 <-> 316 +383 <-> 320 +384 <-> 321 +385 <-> 322 +387 <-> 324 +388 <-> 325 +389 <-> 326 +392 <-> 329 +393 <-> 330 +395 <-> 332 +396 <-> 333 +397 <-> 334 +398 <-> 335 +400 <-> 338 +411 <-> 324 +413 <-> 342 +415 <-> 345 +416 <-> 346 +420 <-> 350 +421 <-> 351 +422 <-> 352 +424 <-> 354 +425 <-> 355 +426 <-> 356 +429 <-> 361 +430 <-> 362 +432 <-> 366 +433 <-> 367 +434 <-> 368 +435 <-> 369 +437 <-> 372 +441 <-> 376 +442 <-> 377 +443 <-> 378 +446 <-> 380 +448 <-> 381 +450 <-> 385 +452 <-> 388 +453 <-> 389 Not mapped: 9 12 @@ -443,3 +1677,86 @@ Not mapped: 102 110 111 +125 +132 +147 +151 +154 +157 +159 +161 +162 +163 +164 +165 +166 +169 +170 +178 +181 +182 +184 +185 +194 +203 +204 +206 +207 +208 +209 +210 +211 +212 +213 +222 +248 +249 +251 +252 +254 +256 +258 +260 +262 +264 +266 +268 +270 +272 +274 +293 +300 +301 +303 +304 +305 +306 +308 +340 +342 +349 +350 +352 +353 +354 +355 +357 +359 +362 +363 +364 +365 +367 +368 +394 +401 +402 +404 +405 +406 +407 +409 +431 +438 +439 +444 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec new file mode 100644 index 0000000000..6e39fa1f5e --- /dev/null +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec @@ -0,0 +1,1762 @@ +package pkg; + +import org.vineflower.marker.CatchAllException; + +public class TestTryFinallyMarkerExceptionsInvalid { + // $VF: Could not inline inconsistent finally blocks + public Object testReturn() { + try { + System.out.println("Hello");// 8 + } catch (Throwable var3) { + System.out.println("Finally");// 10 + return e;// 11 + } + + System.out.println("Finally");// 14 + System.out.println("Bye");// 17 + return null;// 18 + } + + // $VF: Could not inline inconsistent finally blocks + public void testLogged(int i) { + try { + System.out.println("Hello");// 24 + } catch (Throwable var4) { + System.out.println(e.getMessage());// 27 + System.out.println("Finally");// 29 + throw e;// 30 + } + + System.out.println("Finally");// 33 + System.out.println("Bye");// 36 + }// 37 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testWeirdCatch(int i) { + boolean var5 = false /* VF: Semaphore variable */; + + label26: { + try { + var5 = true; + System.out.println("Hello");// 44 + var5 = false; + break label26; + } catch (NullPointerException npe) { + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 48 + } + } + + System.out.println("NPE");// 46 + } + + System.out.println("Finally");// 52 + System.out.println("Bye");// 55 + }// 56 + + public void testWeirdCatch2(int param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: getstatic java/lang/System.out Ljava/io/PrintStream; + // 03: ldc "Hello" + // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 08: goto 22 + // 0b: astore 2 + // 0c: getstatic java/lang/System.out Ljava/io/PrintStream; + // 0f: ldc "Finally" + // 11: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 14: goto 22 + // 17: astore 2 + // 18: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1b: ldc "Finally" + // 1d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 20: aload 2 + // 21: athrow + // 22: getstatic java/lang/System.out Ljava/io/PrintStream; + // 25: ldc "Finally" + // 27: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 2a: getstatic java/lang/System.out Ljava/io/PrintStream; + // 2d: ldc "Bye" + // 2f: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 32: return + // try (0 -> 3): 4 java/lang/NullPointerException + // try (0 -> 3): 9 null + } + + public void testWeirdCatch3(int i) { + label26: { + NullPointerException npe; + try { + System.out.println("Hello");// 81 + break label26; + } catch (NullPointerException var5) { + npe = var5;// 82 + } finally { + System.out.println("Finally");// 86 + } + + System.out.println("NPE: " + npe.getMessage());// 84 + } + + System.out.println("Bye");// 93 + }// 94 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testBlockReuse(int i) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 101 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally");// 103 + if (i > 0) {// 104 + System.out.println("Cool 1");// 105 + } else { + System.out.println("Cool 2");// 107 + } + + if (i < 0) {// 109 + } + } + } + + System.out.println("Finally");// 113 + if (i > 0) {// 114 + } + + System.out.println("Cool 1");// 115 + if (i < 0) {// 116 + } + + System.out.println("Bye");// 119 + }// 120 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testInjectWrongException(boolean b) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 124 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally start");// 126 + CatchAllException e; + if (b) {// 127 + e = new CatchAllException("yo");// 128 + } + + System.out.println("Finally end");// 130 + throw e;// 131 + } + } + + System.out.println("Finally start");// 134 + if (b) {// 135 + new CatchAllException("yo");// 136 + } + + System.out.println("Finally end");// 138 + System.out.println("Bye");// 141 + }// 142 + + public void testMultiImplicitExits(int i) { + try { + System.out.println("Hello");// 146 + } finally { + System.out.println("Finally");// 148 + if (i > 0) {// 149 + System.out.println("Positive!");// 150 + } else if (i == 0) {// 152 + System.out.println("ZERO");// 153 + } else { + System.out.println("Negative!");// 156 + } + } + + System.out.println("Bye 1");// 164 + }// 173 + + public void testConfusion1(String a, String b) { + try { + System.out.println("Hello");// 177 + } finally { + System.out.println("Finally");// 179 + System.out.println(a);// 180 + } + + System.out.println("Bye");// 187 + }// 188 + + public void testConfusion2() { + try { + System.out.println("Hello");// 193 + } finally { + System.out.println("Finally");// 195 + String x = "X";// 196 + String y = "Y";// 197 + String z = "Z";// 198 + x = x + z;// 199 + y = y + x;// 200 + z = z + y;// 201 + System.out.println(z);// 202 + } + + System.out.println("Bye");// 215 + }// 216 + + public void testMismatchedSwitch(int i) { + try { + System.out.println("Hello");// 221 + } finally { + System.out.println("Finally");// 223 + switch (i) {// 224 + case 10: + System.out.println("10");// 226 + case 9: + System.out.println("9");// 228 + case 8: + System.out.println("8");// 230 + case 7: + System.out.println("7");// 232 + case 6: + System.out.println("6");// 234 + case 5: + System.out.println("5");// 236 + case 4: + System.out.println("4");// 238 + case 3: + System.out.println("3");// 240 + case 2: + System.out.println("2");// 242 + case 1: + System.out.println("1");// 244 + case 0: + System.out.println("Lift off!");// 246 + } + } + + System.out.println("Bye");// 277 + }// 278 + + public void testMismatchedOutputExit(int a, int b) { + label53: + while (a > 0) {// 282 + System.out.println("A: " + a);// 283 + a--;// 284 + + for (; b > 0; System.out.println("Beep")) {// 286 310 + a++;// 287 + System.out.println("B: " + b);// 288 + + try { + b--;// 291 + System.out.println("Hello");// 292 + } finally { + System.out.println("Finally");// 294 + if (a > b) {// 295 + a--;// 296 + continue label53;// 297 + } + + System.out.println("Boop");// 299 + } + } + + System.out.println("BLORB");// 312 + } + + System.out.println("Bye");// 314 + }// 315 + + public void testMismatchedOutputExit3(int a, int b, int c) { + label84: + while (a > 0) {// 320 + System.out.println("A: " + a);// 321 + a--;// 322 + + label82: + while (b > 0) {// 324 + a++;// 325 + System.out.println("B: " + b);// 326 + + for (; c > 0; System.out.println("Lost")) {// 329 371 + c -= b;// 330 + + try { + b--;// 337 + System.out.println("Hello");// 338 + if (c < a) {// 339 + continue label82; + } + } finally { + System.out.println("Finally");// 343 + if (a > b) {// 344 + a--;// 345 + continue label84;// 346 + } + + System.out.println("Boop");// 348 + } + } + + System.out.println("Beep");// 373 + } + + System.out.println("BLORB");// 375 + } + + System.out.println("Bye");// 377 + }// 378 + + public void testMismatchedOutputExitReturn(int a, int b) { + label54: + while (a > 0) {// 383 + System.out.println("A: " + a);// 384 + a--;// 385 + + for (; b > 0; System.out.println("Beep")) {// 387 411 + a++;// 388 + System.out.println("B: " + b);// 389 + + try { + b--;// 392 + System.out.println("Hello");// 393 + } finally { + System.out.println("Finally");// 395 + if (a > b) {// 396 + a--;// 397 + continue label54;// 398 + } + + System.out.println("Boop");// 400 + } + } + + System.out.println("BLORB");// 413 + } + + System.out.println("Bye");// 415 + }// 416 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testMismatchedOutputExitReturnInner(int a, int b) { + while (a > 0) {// 420 + System.out.println("A: " + a);// 421 + a--;// 422 + + while (b > 0) {// 424 + a++;// 425 + System.out.println("B: " + b);// 426 + boolean var5 = false /* VF: Semaphore variable */; + + try { + var5 = true; + b--;// 429 + System.out.println("Hello");// 430 + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 432 + if (a > b) {// 433 + a--;// 434 + return;// 435 + } + + System.out.println("Boop");// 437 + } + } + + System.out.println("Finally");// 441 + if (a > b) {// 442 + a--;// 443 + } else { + System.out.println("Boop");// 446 + System.out.println("Beep");// 448 + } + } + + System.out.println("BLORB");// 450 + } + + System.out.println("Bye");// 452 + }// 453 +} + +class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { + method 'testReturn ()Ljava/lang/Object;' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + c 10 + d 10 + e 10 + f 10 + 10 10 + 11 10 + 12 10 + 13 10 + 14 11 + 15 11 + 16 14 + 17 14 + 18 14 + 19 14 + 1a 14 + 1b 14 + 1c 14 + 1d 14 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 15 + 23 15 + 24 15 + 25 15 + 26 16 + 27 16 + } + + method 'testLogged (I)V' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + 7 22 + c 24 + d 24 + e 24 + f 24 + 10 24 + 11 24 + 12 24 + 13 24 + 14 24 + 15 24 + 16 25 + 17 25 + 18 25 + 19 25 + 1a 25 + 1b 25 + 1c 25 + 1d 25 + 1e 26 + 1f 26 + 20 29 + 21 29 + 22 29 + 23 29 + 24 29 + 25 29 + 26 29 + 27 29 + 28 30 + 29 30 + 2a 30 + 2b 30 + 2c 30 + 2d 30 + 2e 30 + 2f 30 + 30 31 + } + + method 'testWeirdCatch (I)V' { + 0 40 + 1 40 + 2 40 + 3 40 + 4 40 + 5 40 + 6 40 + 7 40 + c 51 + d 51 + e 51 + f 51 + 10 51 + 11 51 + 12 51 + 13 51 + 18 47 + 19 47 + 1a 47 + 1b 47 + 1c 47 + 1d 47 + 1e 47 + 1f 47 + 22 54 + 23 54 + 24 54 + 25 54 + 26 54 + 27 54 + 28 54 + 29 54 + 2a 55 + 2b 55 + 2c 55 + 2d 55 + 2e 55 + 2f 55 + 30 55 + 31 55 + 32 56 + } + + method 'testWeirdCatch3 (I)V' { + 0 91 + 1 91 + 2 91 + 3 91 + 4 91 + 5 91 + 6 91 + 7 91 + b 94 + 14 99 + 15 99 + 16 99 + 1e 99 + 1f 99 + 23 99 + 24 99 + 25 99 + 26 99 + 2a 99 + 2b 99 + 2c 99 + 2d 99 + 2e 99 + 2f 99 + 34 96 + 35 96 + 36 96 + 37 96 + 38 96 + 39 96 + 3a 96 + 3b 96 + 46 102 + 47 102 + 48 102 + 49 102 + 4a 102 + 4b 102 + 4c 102 + 4d 102 + 4e 103 + } + + method 'testBlockReuse (I)V' { + 0 111 + 1 111 + 2 111 + 3 111 + 4 111 + 5 111 + 6 111 + 7 111 + c 115 + d 115 + e 115 + f 115 + 10 115 + 11 115 + 12 115 + 13 115 + 14 116 + 15 116 + 16 116 + 17 116 + 18 117 + 19 117 + 1a 117 + 1b 117 + 1c 117 + 1d 117 + 1e 117 + 1f 117 + 23 119 + 24 119 + 25 119 + 26 119 + 27 119 + 28 119 + 29 119 + 2a 119 + 2b 122 + 2c 122 + 2d 122 + 2e 122 + 31 127 + 32 127 + 33 127 + 34 127 + 35 127 + 36 127 + 37 127 + 38 127 + 39 128 + 3a 128 + 3b 128 + 3c 128 + 3d 131 + 3e 131 + 3f 131 + 40 131 + 41 131 + 42 131 + 43 131 + 44 131 + 45 132 + 46 132 + 47 132 + 48 132 + 49 135 + 4a 135 + 4b 135 + 4c 135 + 4d 135 + 4e 135 + 4f 135 + 50 135 + 51 136 + } + + method 'testInjectWrongException (Z)V' { + 0 144 + 1 144 + 2 144 + 3 144 + 4 144 + 5 144 + 6 144 + 7 144 + c 148 + d 148 + e 148 + f 148 + 10 148 + 11 148 + 12 148 + 13 148 + 14 150 + 15 150 + 16 150 + 17 150 + 1c 151 + 1d 151 + 21 151 + 22 154 + 23 154 + 24 154 + 25 154 + 26 154 + 27 154 + 28 154 + 29 154 + 2a 155 + 2b 155 + 2c 159 + 2d 159 + 2e 159 + 2f 159 + 30 159 + 31 159 + 32 159 + 33 159 + 34 160 + 35 160 + 36 160 + 37 160 + 3c 161 + 3d 161 + 42 164 + 43 164 + 44 164 + 45 164 + 46 164 + 47 164 + 48 164 + 49 164 + 4a 165 + 4b 165 + 4c 165 + 4d 165 + 4e 165 + 4f 165 + 50 165 + 51 165 + 52 166 + } + + method 'testMultiImplicitExits (I)V' { + 0 170 + 1 170 + 2 170 + 3 170 + 4 170 + 5 170 + 6 170 + 7 170 + c 172 + d 172 + e 172 + f 172 + 10 172 + 11 172 + 12 172 + 13 172 + 14 173 + 15 173 + 16 173 + 17 173 + 18 174 + 19 174 + 1a 174 + 1b 174 + 1c 174 + 1d 174 + 1e 174 + 1f 174 + 22 175 + 23 175 + 24 175 + 25 175 + 26 176 + 27 176 + 28 176 + 29 176 + 2a 176 + 2b 176 + 2c 176 + 2d 176 + 30 178 + 31 178 + 32 178 + 33 178 + 34 178 + 35 178 + 36 178 + 37 178 + 4e 182 + 4f 182 + 50 182 + 51 182 + 52 182 + 53 182 + 54 182 + 55 182 + 80 183 + } + + method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { + 0 187 + 1 187 + 2 187 + 3 187 + 4 187 + 5 187 + 6 187 + 7 187 + c 189 + d 189 + e 189 + f 189 + 10 189 + 11 189 + 12 189 + 13 189 + 14 190 + 15 190 + 16 190 + 17 190 + 18 190 + 19 190 + 1a 190 + 2c 193 + 2d 193 + 2e 193 + 2f 193 + 30 193 + 31 193 + 32 193 + 33 193 + 34 194 + } + + method 'testConfusion2 ()V' { + 0 198 + 1 198 + 2 198 + 3 198 + 4 198 + 5 198 + 6 198 + 7 198 + d 200 + e 200 + f 200 + 10 200 + 11 200 + 12 200 + 13 200 + 14 200 + 15 201 + 16 201 + 17 201 + 18 202 + 19 202 + 1a 202 + 1b 203 + 1c 203 + 1d 203 + 25 204 + 29 204 + 2d 204 + 2e 204 + 2f 204 + 30 204 + 38 205 + 3c 205 + 40 205 + 41 205 + 42 205 + 43 205 + 4b 206 + 4f 206 + 53 206 + 54 206 + 55 206 + 56 206 + 57 207 + 58 207 + 59 207 + 5a 207 + 5b 207 + 5c 207 + 5d 207 + b2 210 + b3 210 + b4 210 + b5 210 + b6 210 + b7 210 + b8 210 + b9 210 + ba 211 + } + + method 'testMismatchedSwitch (I)V' { + 0 215 + 1 215 + 2 215 + 3 215 + 4 215 + 5 215 + 6 215 + 7 215 + c 217 + d 217 + e 217 + f 217 + 10 217 + 11 217 + 12 217 + 13 217 + 14 218 + 15 218 + 16 218 + 17 218 + 18 218 + 19 218 + 1a 218 + 1b 218 + 1c 218 + 1d 218 + 1e 218 + 1f 218 + 20 218 + 21 218 + 22 218 + 23 218 + 24 218 + 25 218 + 26 218 + 27 218 + 28 218 + 29 218 + 2a 218 + 2b 218 + 2c 218 + 2d 218 + 2e 218 + 2f 218 + 30 218 + 31 218 + 32 218 + 33 218 + 34 218 + 35 218 + 36 218 + 37 218 + 38 218 + 39 218 + 3a 218 + 3b 218 + 3c 218 + 3d 218 + 3e 218 + 3f 218 + 40 218 + 41 218 + 42 218 + 43 218 + 44 218 + 45 218 + 46 218 + 47 218 + 48 218 + 49 218 + 4a 218 + 4b 218 + 4c 218 + 4d 218 + 4e 218 + 4f 218 + 50 220 + 51 220 + 52 220 + 53 220 + 54 220 + 55 220 + 56 220 + 57 220 + 58 222 + 59 222 + 5a 222 + 5b 222 + 5c 222 + 5d 222 + 5e 222 + 5f 222 + 60 224 + 61 224 + 62 224 + 63 224 + 64 224 + 65 224 + 66 224 + 67 224 + 68 226 + 69 226 + 6a 226 + 6b 226 + 6c 226 + 6d 226 + 6e 226 + 6f 226 + 70 228 + 71 228 + 72 228 + 73 228 + 74 228 + 75 228 + 76 228 + 77 228 + 78 230 + 79 230 + 7a 230 + 7b 230 + 7c 230 + 7d 230 + 7e 230 + 7f 230 + 80 232 + 81 232 + 82 232 + 83 232 + 84 232 + 85 232 + 86 232 + 87 232 + 88 234 + 89 234 + 8a 234 + 8b 234 + 8c 234 + 8d 234 + 8e 234 + 8f 234 + 90 236 + 91 236 + 92 236 + 93 236 + 94 236 + 95 236 + 96 236 + 97 236 + 98 238 + 99 238 + 9a 238 + 9b 238 + 9c 238 + 9d 238 + 9e 238 + 9f 238 + a0 240 + a1 240 + a2 240 + a3 240 + a4 240 + a5 240 + a6 240 + a7 240 + 144 244 + 145 244 + 146 244 + 147 244 + 148 244 + 149 244 + 14a 244 + 14b 244 + 14c 245 + } + + method 'testMismatchedOutputExit (II)V' { + 0 249 + 1 249 + 2 249 + 3 249 + 4 250 + 5 250 + 6 250 + e 250 + f 250 + 13 250 + 17 250 + 18 250 + 19 250 + 1a 250 + 1b 250 + 1c 250 + 1d 251 + 1e 251 + 1f 251 + 20 253 + 21 253 + 22 253 + 23 253 + 24 254 + 25 254 + 26 254 + 27 255 + 28 255 + 29 255 + 31 255 + 32 255 + 36 255 + 3a 255 + 3b 255 + 3c 255 + 3d 255 + 3e 255 + 3f 255 + 40 258 + 41 258 + 42 258 + 43 259 + 44 259 + 45 259 + 46 259 + 47 259 + 48 259 + 49 259 + 4a 259 + 4f 261 + 50 261 + 51 261 + 52 261 + 53 261 + 54 261 + 55 261 + 56 261 + 57 262 + 58 262 + 59 262 + 5a 262 + 5b 262 + 5c 263 + 5d 263 + 5e 263 + 5f 264 + 62 267 + 63 267 + 64 267 + 65 267 + 66 267 + 67 267 + 68 267 + 69 267 + 87 253 + 88 253 + 89 253 + 8a 253 + 8b 253 + 8c 253 + 8d 253 + 8e 253 + 92 271 + 93 271 + 94 271 + 95 271 + 96 271 + 97 271 + 98 271 + 99 271 + 9d 274 + 9e 274 + 9f 274 + a0 274 + a1 274 + a2 274 + a3 274 + a4 274 + a5 275 + } + + method 'testMismatchedOutputExit3 (III)V' { + 0 279 + 1 279 + 2 279 + 3 279 + 4 280 + 5 280 + 6 280 + e 280 + f 280 + 13 280 + 17 280 + 18 280 + 19 280 + 1a 280 + 1b 280 + 1c 280 + 1d 281 + 1e 281 + 1f 281 + 20 284 + 21 284 + 22 284 + 23 284 + 24 285 + 25 285 + 26 285 + 27 286 + 28 286 + 29 286 + 31 286 + 32 286 + 36 286 + 3a 286 + 3b 286 + 3c 286 + 3d 286 + 3e 286 + 3f 286 + 40 288 + 41 288 + 42 288 + 43 288 + 45 289 + 47 289 + 48 292 + 49 292 + 4a 292 + 4b 293 + 4c 293 + 4d 293 + 4e 293 + 4f 293 + 50 293 + 51 293 + 52 293 + 53 294 + 54 294 + 55 294 + 56 294 + 57 294 + 60 298 + 61 298 + 62 298 + 63 298 + 64 298 + 65 298 + 66 298 + 67 298 + 68 299 + 69 299 + 6a 299 + 6b 299 + 6c 299 + 6d 300 + 6e 300 + 6f 300 + 70 301 + 73 304 + 74 304 + 75 304 + 76 304 + 77 304 + 78 304 + 79 304 + 7a 304 + ba 288 + bb 288 + bc 288 + bd 288 + be 288 + bf 288 + c0 288 + c1 288 + c5 308 + c6 308 + c7 308 + c8 308 + c9 308 + ca 308 + cb 308 + cc 308 + d0 311 + d1 311 + d2 311 + d3 311 + d4 311 + d5 311 + d6 311 + d7 311 + db 314 + dc 314 + dd 314 + de 314 + df 314 + e0 314 + e1 314 + e2 314 + e3 315 + } + + method 'testMismatchedOutputExitReturn (II)V' { + 0 319 + 1 319 + 2 319 + 3 319 + 4 320 + 5 320 + 6 320 + e 320 + f 320 + 13 320 + 17 320 + 18 320 + 19 320 + 1a 320 + 1b 320 + 1c 320 + 1d 321 + 1e 321 + 1f 321 + 20 323 + 21 323 + 22 323 + 23 323 + 24 324 + 25 324 + 26 324 + 27 325 + 28 325 + 29 325 + 31 325 + 32 325 + 36 325 + 3a 325 + 3b 325 + 3c 325 + 3d 325 + 3e 325 + 3f 325 + 40 328 + 41 328 + 42 328 + 43 329 + 44 329 + 45 329 + 46 329 + 47 329 + 48 329 + 49 329 + 4a 329 + 4f 331 + 50 331 + 51 331 + 52 331 + 53 331 + 54 331 + 55 331 + 56 331 + 57 332 + 58 332 + 59 332 + 5a 332 + 5b 332 + 5c 333 + 5d 333 + 5e 333 + 5f 334 + 62 337 + 63 337 + 64 337 + 65 337 + 66 337 + 67 337 + 68 337 + 69 337 + 85 323 + 86 323 + 87 323 + 88 323 + 89 323 + 8a 323 + 8b 323 + 8c 323 + 90 341 + 91 341 + 92 341 + 93 341 + 94 341 + 95 341 + 96 341 + 97 341 + 9b 344 + 9c 344 + 9d 344 + 9e 344 + 9f 344 + a0 344 + a1 344 + a2 344 + a3 345 + } + + method 'testMismatchedOutputExitReturnInner (II)V' { + 0 349 + 1 349 + 2 349 + 3 349 + 4 350 + 5 350 + 6 350 + e 350 + f 350 + 13 350 + 17 350 + 18 350 + 19 350 + 1a 350 + 1b 350 + 1c 350 + 1d 351 + 1e 351 + 1f 351 + 20 353 + 21 353 + 22 353 + 23 353 + 24 354 + 25 354 + 26 354 + 27 355 + 28 355 + 29 355 + 31 355 + 32 355 + 36 355 + 3a 355 + 3b 355 + 3c 355 + 3d 355 + 3e 355 + 3f 355 + 40 360 + 41 360 + 42 360 + 43 361 + 44 361 + 45 361 + 46 361 + 47 361 + 48 361 + 49 361 + 4a 361 + 4f 365 + 50 365 + 51 365 + 52 365 + 53 365 + 54 365 + 55 365 + 56 365 + 57 366 + 58 366 + 59 366 + 5a 366 + 5b 366 + 5c 367 + 5d 367 + 5e 367 + 5f 368 + 60 371 + 61 371 + 62 371 + 63 371 + 64 371 + 65 371 + 66 371 + 67 371 + 6a 375 + 6b 375 + 6c 375 + 6d 375 + 6e 375 + 6f 375 + 70 375 + 71 375 + 72 376 + 73 376 + 74 376 + 75 376 + 76 376 + 77 377 + 78 377 + 79 377 + 7d 379 + 7e 379 + 7f 379 + 80 379 + 81 379 + 82 379 + 83 379 + 84 379 + 85 380 + 86 380 + 87 380 + 88 380 + 89 380 + 8a 380 + 8b 380 + 8c 380 + 90 384 + 91 384 + 92 384 + 93 384 + 94 384 + 95 384 + 96 384 + 97 384 + 9b 387 + 9c 387 + 9d 387 + 9e 387 + 9f 387 + a0 387 + a1 387 + a2 387 + a3 388 + } +} + +Lines mapping: +8 <-> 9 +10 <-> 11 +11 <-> 12 +14 <-> 15 +17 <-> 16 +18 <-> 17 +24 <-> 23 +27 <-> 25 +29 <-> 26 +30 <-> 27 +33 <-> 30 +36 <-> 31 +37 <-> 32 +44 <-> 41 +46 <-> 52 +48 <-> 48 +52 <-> 55 +55 <-> 56 +56 <-> 57 +81 <-> 92 +82 <-> 95 +84 <-> 100 +86 <-> 97 +93 <-> 103 +94 <-> 104 +101 <-> 112 +103 <-> 116 +104 <-> 117 +105 <-> 118 +107 <-> 120 +109 <-> 123 +113 <-> 128 +114 <-> 129 +115 <-> 132 +116 <-> 133 +119 <-> 136 +120 <-> 137 +124 <-> 145 +126 <-> 149 +127 <-> 151 +128 <-> 152 +130 <-> 155 +131 <-> 156 +134 <-> 160 +135 <-> 161 +136 <-> 162 +138 <-> 165 +141 <-> 166 +142 <-> 167 +146 <-> 171 +148 <-> 173 +149 <-> 174 +150 <-> 175 +152 <-> 176 +153 <-> 177 +156 <-> 179 +164 <-> 183 +173 <-> 184 +177 <-> 188 +179 <-> 190 +180 <-> 191 +187 <-> 194 +188 <-> 195 +193 <-> 199 +195 <-> 201 +196 <-> 202 +197 <-> 203 +198 <-> 204 +199 <-> 205 +200 <-> 206 +201 <-> 207 +202 <-> 208 +215 <-> 211 +216 <-> 212 +221 <-> 216 +223 <-> 218 +224 <-> 219 +226 <-> 221 +228 <-> 223 +230 <-> 225 +232 <-> 227 +234 <-> 229 +236 <-> 231 +238 <-> 233 +240 <-> 235 +242 <-> 237 +244 <-> 239 +246 <-> 241 +277 <-> 245 +278 <-> 246 +282 <-> 250 +283 <-> 251 +284 <-> 252 +286 <-> 254 +287 <-> 255 +288 <-> 256 +291 <-> 259 +292 <-> 260 +294 <-> 262 +295 <-> 263 +296 <-> 264 +297 <-> 265 +299 <-> 268 +310 <-> 254 +312 <-> 272 +314 <-> 275 +315 <-> 276 +320 <-> 280 +321 <-> 281 +322 <-> 282 +324 <-> 285 +325 <-> 286 +326 <-> 287 +329 <-> 289 +330 <-> 290 +337 <-> 293 +338 <-> 294 +339 <-> 295 +343 <-> 299 +344 <-> 300 +345 <-> 301 +346 <-> 302 +348 <-> 305 +371 <-> 289 +373 <-> 309 +375 <-> 312 +377 <-> 315 +378 <-> 316 +383 <-> 320 +384 <-> 321 +385 <-> 322 +387 <-> 324 +388 <-> 325 +389 <-> 326 +392 <-> 329 +393 <-> 330 +395 <-> 332 +396 <-> 333 +397 <-> 334 +398 <-> 335 +400 <-> 338 +411 <-> 324 +413 <-> 342 +415 <-> 345 +416 <-> 346 +420 <-> 350 +421 <-> 351 +422 <-> 352 +424 <-> 354 +425 <-> 355 +426 <-> 356 +429 <-> 361 +430 <-> 362 +432 <-> 366 +433 <-> 367 +434 <-> 368 +435 <-> 369 +437 <-> 372 +441 <-> 376 +442 <-> 377 +443 <-> 378 +446 <-> 380 +448 <-> 381 +450 <-> 385 +452 <-> 388 +453 <-> 389 +Not mapped: +9 +12 +25 +31 +45 +47 +49 +50 +83 +85 +87 +88 +90 +102 +110 +111 +125 +132 +147 +151 +154 +157 +159 +161 +162 +163 +165 +166 +167 +169 +170 +178 +181 +182 +184 +185 +194 +203 +204 +206 +207 +208 +209 +210 +211 +212 +213 +222 +248 +249 +251 +252 +254 +256 +258 +260 +262 +264 +266 +268 +270 +272 +274 +293 +300 +301 +303 +304 +305 +306 +308 +340 +342 +349 +350 +352 +353 +354 +355 +357 +359 +362 +363 +364 +365 +367 +368 +394 +401 +402 +404 +405 +406 +407 +409 +431 +438 +439 +444 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec new file mode 100644 index 0000000000..79c9104aca --- /dev/null +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec @@ -0,0 +1,1762 @@ +package pkg; + +import org.vineflower.marker.CatchAllException; + +public class TestTryFinallyMarkerExceptionsInvalid { + // $VF: Could not inline inconsistent finally blocks + public Object testReturn() { + try { + System.out.println("Hello");// 8 + } catch (Throwable var3) { + System.out.println("Finally");// 10 + return e;// 11 + } + + System.out.println("Finally");// 14 + System.out.println("Bye");// 17 + return null;// 18 + } + + // $VF: Could not inline inconsistent finally blocks + public void testLogged(int i) { + try { + System.out.println("Hello");// 24 + } catch (Throwable var4) { + System.out.println(e.getMessage());// 27 + System.out.println("Finally");// 29 + throw e;// 30 + } + + System.out.println("Finally");// 33 + System.out.println("Bye");// 36 + }// 37 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testWeirdCatch(int i) { + boolean var5 = false /* VF: Semaphore variable */; + + label26: { + try { + var5 = true; + System.out.println("Hello");// 44 + var5 = false; + break label26; + } catch (NullPointerException npe) { + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 48 + } + } + + System.out.println("NPE");// 46 + } + + System.out.println("Finally");// 52 + System.out.println("Bye");// 55 + }// 56 + + public void testWeirdCatch2(int param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: getstatic java/lang/System.out Ljava/io/PrintStream; + // 03: ldc "Hello" + // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 08: goto 22 + // 0b: astore 2 + // 0c: getstatic java/lang/System.out Ljava/io/PrintStream; + // 0f: ldc "Finally" + // 11: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 14: goto 22 + // 17: astore 2 + // 18: getstatic java/lang/System.out Ljava/io/PrintStream; + // 1b: ldc "Finally" + // 1d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 20: aload 2 + // 21: athrow + // 22: getstatic java/lang/System.out Ljava/io/PrintStream; + // 25: ldc "Finally" + // 27: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 2a: getstatic java/lang/System.out Ljava/io/PrintStream; + // 2d: ldc "Bye" + // 2f: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V + // 32: return + // try (0 -> 3): 4 java/lang/NullPointerException + // try (0 -> 3): 9 null + } + + public void testWeirdCatch3(int i) { + label26: { + NullPointerException npe; + try { + System.out.println("Hello");// 81 + break label26; + } catch (NullPointerException var5) { + npe = var5;// 82 + } finally { + System.out.println("Finally");// 86 + } + + System.out.println("NPE: " + npe.getMessage());// 84 + } + + System.out.println("Bye");// 93 + }// 94 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testBlockReuse(int i) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 101 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally");// 103 + if (i > 0) {// 104 + System.out.println("Cool 1");// 105 + } else { + System.out.println("Cool 2");// 107 + } + + if (i < 0) {// 109 + } + } + } + + System.out.println("Finally");// 113 + if (i > 0) {// 114 + } + + System.out.println("Cool 1");// 115 + if (i < 0) {// 116 + } + + System.out.println("Bye");// 119 + }// 120 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testInjectWrongException(boolean b) { + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + System.out.println("Hello");// 124 + var4 = false; + } finally { + if (var4) { + System.out.println("Finally start");// 126 + CatchAllException e; + if (b) {// 127 + e = new CatchAllException("yo");// 128 + } + + System.out.println("Finally end");// 130 + throw e;// 131 + } + } + + System.out.println("Finally start");// 134 + if (b) {// 135 + new CatchAllException("yo");// 136 + } + + System.out.println("Finally end");// 138 + System.out.println("Bye");// 141 + }// 142 + + public void testMultiImplicitExits(int i) { + try { + System.out.println("Hello");// 146 + } finally { + System.out.println("Finally");// 148 + if (i > 0) {// 149 + System.out.println("Positive!");// 150 + } else if (i == 0) {// 152 + System.out.println("ZERO");// 153 + } else { + System.out.println("Negative!");// 156 + } + } + + System.out.println("Bye 3");// 170 + }// 173 + + public void testConfusion1(String a, String b) { + try { + System.out.println("Hello");// 177 + } finally { + System.out.println("Finally");// 179 + System.out.println(a);// 180 + } + + System.out.println("Bye");// 187 + }// 188 + + public void testConfusion2() { + try { + System.out.println("Hello");// 193 + } finally { + System.out.println("Finally");// 195 + String x = "X";// 196 + String y = "Y";// 197 + String z = "Z";// 198 + x = x + z;// 199 + y = y + x;// 200 + z = z + y;// 201 + System.out.println(z);// 202 + } + + System.out.println("Bye");// 215 + }// 216 + + public void testMismatchedSwitch(int i) { + try { + System.out.println("Hello");// 221 + } finally { + System.out.println("Finally");// 223 + switch (i) {// 224 + case 10: + System.out.println("10");// 226 + case 9: + System.out.println("9");// 228 + case 8: + System.out.println("8");// 230 + case 7: + System.out.println("7");// 232 + case 6: + System.out.println("6");// 234 + case 5: + System.out.println("5");// 236 + case 4: + System.out.println("4");// 238 + case 3: + System.out.println("3");// 240 + case 2: + System.out.println("2");// 242 + case 1: + System.out.println("1");// 244 + case 0: + System.out.println("Lift off!");// 246 + } + } + + System.out.println("Bye");// 277 + }// 278 + + public void testMismatchedOutputExit(int a, int b) { + label53: + while (a > 0) {// 282 + System.out.println("A: " + a);// 283 + a--;// 284 + + for (; b > 0; System.out.println("Beep")) {// 286 310 + a++;// 287 + System.out.println("B: " + b);// 288 + + try { + b--;// 291 + System.out.println("Hello");// 292 + } finally { + System.out.println("Finally");// 294 + if (a > b) {// 295 + a--;// 296 + continue label53;// 297 + } + + System.out.println("Boop");// 299 + } + } + + System.out.println("BLORB");// 312 + } + + System.out.println("Bye");// 314 + }// 315 + + public void testMismatchedOutputExit3(int a, int b, int c) { + label84: + while (a > 0) {// 320 + System.out.println("A: " + a);// 321 + a--;// 322 + + label82: + while (b > 0) {// 324 + a++;// 325 + System.out.println("B: " + b);// 326 + + for (; c > 0; System.out.println("Lost")) {// 329 371 + c -= b;// 330 + + try { + b--;// 337 + System.out.println("Hello");// 338 + if (c < a) {// 339 + continue label82; + } + } finally { + System.out.println("Finally");// 343 + if (a > b) {// 344 + a--;// 345 + continue label84;// 346 + } + + System.out.println("Boop");// 348 + } + } + + System.out.println("Beep");// 373 + } + + System.out.println("BLORB");// 375 + } + + System.out.println("Bye");// 377 + }// 378 + + public void testMismatchedOutputExitReturn(int a, int b) { + label54: + while (a > 0) {// 383 + System.out.println("A: " + a);// 384 + a--;// 385 + + for (; b > 0; System.out.println("Beep")) {// 387 411 + a++;// 388 + System.out.println("B: " + b);// 389 + + try { + b--;// 392 + System.out.println("Hello");// 393 + } finally { + System.out.println("Finally");// 395 + if (a > b) {// 396 + a--;// 397 + continue label54;// 398 + } + + System.out.println("Boop");// 400 + } + } + + System.out.println("BLORB");// 413 + } + + System.out.println("Bye");// 415 + }// 416 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testMismatchedOutputExitReturnInner(int a, int b) { + while (a > 0) {// 420 + System.out.println("A: " + a);// 421 + a--;// 422 + + while (b > 0) {// 424 + a++;// 425 + System.out.println("B: " + b);// 426 + boolean var5 = false /* VF: Semaphore variable */; + + try { + var5 = true; + b--;// 429 + System.out.println("Hello");// 430 + var5 = false; + } finally { + if (var5) { + System.out.println("Finally");// 432 + if (a > b) {// 433 + a--;// 434 + return;// 435 + } + + System.out.println("Boop");// 437 + } + } + + System.out.println("Finally");// 441 + if (a > b) {// 442 + a--;// 443 + } else { + System.out.println("Boop");// 446 + System.out.println("Beep");// 448 + } + } + + System.out.println("BLORB");// 450 + } + + System.out.println("Bye");// 452 + }// 453 +} + +class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { + method 'testReturn ()Ljava/lang/Object;' { + 0 8 + 1 8 + 2 8 + 3 8 + 4 8 + 5 8 + 6 8 + 7 8 + c 10 + d 10 + e 10 + f 10 + 10 10 + 11 10 + 12 10 + 13 10 + 14 11 + 15 11 + 16 14 + 17 14 + 18 14 + 19 14 + 1a 14 + 1b 14 + 1c 14 + 1d 14 + 1e 15 + 1f 15 + 20 15 + 21 15 + 22 15 + 23 15 + 24 15 + 25 15 + 26 16 + 27 16 + } + + method 'testLogged (I)V' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + 7 22 + c 24 + d 24 + e 24 + f 24 + 10 24 + 11 24 + 12 24 + 13 24 + 14 24 + 15 24 + 16 25 + 17 25 + 18 25 + 19 25 + 1a 25 + 1b 25 + 1c 25 + 1d 25 + 1e 26 + 1f 26 + 20 29 + 21 29 + 22 29 + 23 29 + 24 29 + 25 29 + 26 29 + 27 29 + 28 30 + 29 30 + 2a 30 + 2b 30 + 2c 30 + 2d 30 + 2e 30 + 2f 30 + 30 31 + } + + method 'testWeirdCatch (I)V' { + 0 40 + 1 40 + 2 40 + 3 40 + 4 40 + 5 40 + 6 40 + 7 40 + c 51 + d 51 + e 51 + f 51 + 10 51 + 11 51 + 12 51 + 13 51 + 18 47 + 19 47 + 1a 47 + 1b 47 + 1c 47 + 1d 47 + 1e 47 + 1f 47 + 22 54 + 23 54 + 24 54 + 25 54 + 26 54 + 27 54 + 28 54 + 29 54 + 2a 55 + 2b 55 + 2c 55 + 2d 55 + 2e 55 + 2f 55 + 30 55 + 31 55 + 32 56 + } + + method 'testWeirdCatch3 (I)V' { + 0 91 + 1 91 + 2 91 + 3 91 + 4 91 + 5 91 + 6 91 + 7 91 + b 94 + 14 99 + 15 99 + 16 99 + 1e 99 + 1f 99 + 23 99 + 24 99 + 25 99 + 26 99 + 2a 99 + 2b 99 + 2c 99 + 2d 99 + 2e 99 + 2f 99 + 34 96 + 35 96 + 36 96 + 37 96 + 38 96 + 39 96 + 3a 96 + 3b 96 + 46 102 + 47 102 + 48 102 + 49 102 + 4a 102 + 4b 102 + 4c 102 + 4d 102 + 4e 103 + } + + method 'testBlockReuse (I)V' { + 0 111 + 1 111 + 2 111 + 3 111 + 4 111 + 5 111 + 6 111 + 7 111 + c 115 + d 115 + e 115 + f 115 + 10 115 + 11 115 + 12 115 + 13 115 + 14 116 + 15 116 + 16 116 + 17 116 + 18 117 + 19 117 + 1a 117 + 1b 117 + 1c 117 + 1d 117 + 1e 117 + 1f 117 + 23 119 + 24 119 + 25 119 + 26 119 + 27 119 + 28 119 + 29 119 + 2a 119 + 2b 122 + 2c 122 + 2d 122 + 2e 122 + 31 127 + 32 127 + 33 127 + 34 127 + 35 127 + 36 127 + 37 127 + 38 127 + 39 128 + 3a 128 + 3b 128 + 3c 128 + 3d 131 + 3e 131 + 3f 131 + 40 131 + 41 131 + 42 131 + 43 131 + 44 131 + 45 132 + 46 132 + 47 132 + 48 132 + 49 135 + 4a 135 + 4b 135 + 4c 135 + 4d 135 + 4e 135 + 4f 135 + 50 135 + 51 136 + } + + method 'testInjectWrongException (Z)V' { + 0 144 + 1 144 + 2 144 + 3 144 + 4 144 + 5 144 + 6 144 + 7 144 + c 148 + d 148 + e 148 + f 148 + 10 148 + 11 148 + 12 148 + 13 148 + 14 150 + 15 150 + 16 150 + 17 150 + 1c 151 + 1d 151 + 21 151 + 22 154 + 23 154 + 24 154 + 25 154 + 26 154 + 27 154 + 28 154 + 29 154 + 2a 155 + 2b 155 + 2c 159 + 2d 159 + 2e 159 + 2f 159 + 30 159 + 31 159 + 32 159 + 33 159 + 34 160 + 35 160 + 36 160 + 37 160 + 3c 161 + 3d 161 + 42 164 + 43 164 + 44 164 + 45 164 + 46 164 + 47 164 + 48 164 + 49 164 + 4a 165 + 4b 165 + 4c 165 + 4d 165 + 4e 165 + 4f 165 + 50 165 + 51 165 + 52 166 + } + + method 'testMultiImplicitExits (I)V' { + 0 170 + 1 170 + 2 170 + 3 170 + 4 170 + 5 170 + 6 170 + 7 170 + c 172 + d 172 + e 172 + f 172 + 10 172 + 11 172 + 12 172 + 13 172 + 14 173 + 15 173 + 16 173 + 17 173 + 18 174 + 19 174 + 1a 174 + 1b 174 + 1c 174 + 1d 174 + 1e 174 + 1f 174 + 22 175 + 23 175 + 24 175 + 25 175 + 26 176 + 27 176 + 28 176 + 29 176 + 2a 176 + 2b 176 + 2c 176 + 2d 176 + 30 178 + 31 178 + 32 178 + 33 178 + 34 178 + 35 178 + 36 178 + 37 178 + 78 182 + 79 182 + 7a 182 + 7b 182 + 7c 182 + 7d 182 + 7e 182 + 7f 182 + 80 183 + } + + method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { + 0 187 + 1 187 + 2 187 + 3 187 + 4 187 + 5 187 + 6 187 + 7 187 + c 189 + d 189 + e 189 + f 189 + 10 189 + 11 189 + 12 189 + 13 189 + 14 190 + 15 190 + 16 190 + 17 190 + 18 190 + 19 190 + 1a 190 + 2c 193 + 2d 193 + 2e 193 + 2f 193 + 30 193 + 31 193 + 32 193 + 33 193 + 34 194 + } + + method 'testConfusion2 ()V' { + 0 198 + 1 198 + 2 198 + 3 198 + 4 198 + 5 198 + 6 198 + 7 198 + d 200 + e 200 + f 200 + 10 200 + 11 200 + 12 200 + 13 200 + 14 200 + 15 201 + 16 201 + 17 201 + 18 202 + 19 202 + 1a 202 + 1b 203 + 1c 203 + 1d 203 + 25 204 + 29 204 + 2d 204 + 2e 204 + 2f 204 + 30 204 + 38 205 + 3c 205 + 40 205 + 41 205 + 42 205 + 43 205 + 4b 206 + 4f 206 + 53 206 + 54 206 + 55 206 + 56 206 + 57 207 + 58 207 + 59 207 + 5a 207 + 5b 207 + 5c 207 + 5d 207 + b2 210 + b3 210 + b4 210 + b5 210 + b6 210 + b7 210 + b8 210 + b9 210 + ba 211 + } + + method 'testMismatchedSwitch (I)V' { + 0 215 + 1 215 + 2 215 + 3 215 + 4 215 + 5 215 + 6 215 + 7 215 + c 217 + d 217 + e 217 + f 217 + 10 217 + 11 217 + 12 217 + 13 217 + 14 218 + 15 218 + 16 218 + 17 218 + 18 218 + 19 218 + 1a 218 + 1b 218 + 1c 218 + 1d 218 + 1e 218 + 1f 218 + 20 218 + 21 218 + 22 218 + 23 218 + 24 218 + 25 218 + 26 218 + 27 218 + 28 218 + 29 218 + 2a 218 + 2b 218 + 2c 218 + 2d 218 + 2e 218 + 2f 218 + 30 218 + 31 218 + 32 218 + 33 218 + 34 218 + 35 218 + 36 218 + 37 218 + 38 218 + 39 218 + 3a 218 + 3b 218 + 3c 218 + 3d 218 + 3e 218 + 3f 218 + 40 218 + 41 218 + 42 218 + 43 218 + 44 218 + 45 218 + 46 218 + 47 218 + 48 218 + 49 218 + 4a 218 + 4b 218 + 4c 218 + 4d 218 + 4e 218 + 4f 218 + 50 220 + 51 220 + 52 220 + 53 220 + 54 220 + 55 220 + 56 220 + 57 220 + 58 222 + 59 222 + 5a 222 + 5b 222 + 5c 222 + 5d 222 + 5e 222 + 5f 222 + 60 224 + 61 224 + 62 224 + 63 224 + 64 224 + 65 224 + 66 224 + 67 224 + 68 226 + 69 226 + 6a 226 + 6b 226 + 6c 226 + 6d 226 + 6e 226 + 6f 226 + 70 228 + 71 228 + 72 228 + 73 228 + 74 228 + 75 228 + 76 228 + 77 228 + 78 230 + 79 230 + 7a 230 + 7b 230 + 7c 230 + 7d 230 + 7e 230 + 7f 230 + 80 232 + 81 232 + 82 232 + 83 232 + 84 232 + 85 232 + 86 232 + 87 232 + 88 234 + 89 234 + 8a 234 + 8b 234 + 8c 234 + 8d 234 + 8e 234 + 8f 234 + 90 236 + 91 236 + 92 236 + 93 236 + 94 236 + 95 236 + 96 236 + 97 236 + 98 238 + 99 238 + 9a 238 + 9b 238 + 9c 238 + 9d 238 + 9e 238 + 9f 238 + a0 240 + a1 240 + a2 240 + a3 240 + a4 240 + a5 240 + a6 240 + a7 240 + 144 244 + 145 244 + 146 244 + 147 244 + 148 244 + 149 244 + 14a 244 + 14b 244 + 14c 245 + } + + method 'testMismatchedOutputExit (II)V' { + 0 249 + 1 249 + 2 249 + 3 249 + 4 250 + 5 250 + 6 250 + e 250 + f 250 + 13 250 + 17 250 + 18 250 + 19 250 + 1a 250 + 1b 250 + 1c 250 + 1d 251 + 1e 251 + 1f 251 + 20 253 + 21 253 + 22 253 + 23 253 + 24 254 + 25 254 + 26 254 + 27 255 + 28 255 + 29 255 + 31 255 + 32 255 + 36 255 + 3a 255 + 3b 255 + 3c 255 + 3d 255 + 3e 255 + 3f 255 + 40 258 + 41 258 + 42 258 + 43 259 + 44 259 + 45 259 + 46 259 + 47 259 + 48 259 + 49 259 + 4a 259 + 4f 261 + 50 261 + 51 261 + 52 261 + 53 261 + 54 261 + 55 261 + 56 261 + 57 262 + 58 262 + 59 262 + 5a 262 + 5b 262 + 5c 263 + 5d 263 + 5e 263 + 5f 264 + 62 267 + 63 267 + 64 267 + 65 267 + 66 267 + 67 267 + 68 267 + 69 267 + 87 253 + 88 253 + 89 253 + 8a 253 + 8b 253 + 8c 253 + 8d 253 + 8e 253 + 92 271 + 93 271 + 94 271 + 95 271 + 96 271 + 97 271 + 98 271 + 99 271 + 9d 274 + 9e 274 + 9f 274 + a0 274 + a1 274 + a2 274 + a3 274 + a4 274 + a5 275 + } + + method 'testMismatchedOutputExit3 (III)V' { + 0 279 + 1 279 + 2 279 + 3 279 + 4 280 + 5 280 + 6 280 + e 280 + f 280 + 13 280 + 17 280 + 18 280 + 19 280 + 1a 280 + 1b 280 + 1c 280 + 1d 281 + 1e 281 + 1f 281 + 20 284 + 21 284 + 22 284 + 23 284 + 24 285 + 25 285 + 26 285 + 27 286 + 28 286 + 29 286 + 31 286 + 32 286 + 36 286 + 3a 286 + 3b 286 + 3c 286 + 3d 286 + 3e 286 + 3f 286 + 40 288 + 41 288 + 42 288 + 43 288 + 45 289 + 47 289 + 48 292 + 49 292 + 4a 292 + 4b 293 + 4c 293 + 4d 293 + 4e 293 + 4f 293 + 50 293 + 51 293 + 52 293 + 53 294 + 54 294 + 55 294 + 56 294 + 57 294 + 60 298 + 61 298 + 62 298 + 63 298 + 64 298 + 65 298 + 66 298 + 67 298 + 68 299 + 69 299 + 6a 299 + 6b 299 + 6c 299 + 6d 300 + 6e 300 + 6f 300 + 70 301 + 73 304 + 74 304 + 75 304 + 76 304 + 77 304 + 78 304 + 79 304 + 7a 304 + ba 288 + bb 288 + bc 288 + bd 288 + be 288 + bf 288 + c0 288 + c1 288 + c5 308 + c6 308 + c7 308 + c8 308 + c9 308 + ca 308 + cb 308 + cc 308 + d0 311 + d1 311 + d2 311 + d3 311 + d4 311 + d5 311 + d6 311 + d7 311 + db 314 + dc 314 + dd 314 + de 314 + df 314 + e0 314 + e1 314 + e2 314 + e3 315 + } + + method 'testMismatchedOutputExitReturn (II)V' { + 0 319 + 1 319 + 2 319 + 3 319 + 4 320 + 5 320 + 6 320 + e 320 + f 320 + 13 320 + 17 320 + 18 320 + 19 320 + 1a 320 + 1b 320 + 1c 320 + 1d 321 + 1e 321 + 1f 321 + 20 323 + 21 323 + 22 323 + 23 323 + 24 324 + 25 324 + 26 324 + 27 325 + 28 325 + 29 325 + 31 325 + 32 325 + 36 325 + 3a 325 + 3b 325 + 3c 325 + 3d 325 + 3e 325 + 3f 325 + 40 328 + 41 328 + 42 328 + 43 329 + 44 329 + 45 329 + 46 329 + 47 329 + 48 329 + 49 329 + 4a 329 + 4f 331 + 50 331 + 51 331 + 52 331 + 53 331 + 54 331 + 55 331 + 56 331 + 57 332 + 58 332 + 59 332 + 5a 332 + 5b 332 + 5c 333 + 5d 333 + 5e 333 + 5f 334 + 62 337 + 63 337 + 64 337 + 65 337 + 66 337 + 67 337 + 68 337 + 69 337 + 85 323 + 86 323 + 87 323 + 88 323 + 89 323 + 8a 323 + 8b 323 + 8c 323 + 90 341 + 91 341 + 92 341 + 93 341 + 94 341 + 95 341 + 96 341 + 97 341 + 9b 344 + 9c 344 + 9d 344 + 9e 344 + 9f 344 + a0 344 + a1 344 + a2 344 + a3 345 + } + + method 'testMismatchedOutputExitReturnInner (II)V' { + 0 349 + 1 349 + 2 349 + 3 349 + 4 350 + 5 350 + 6 350 + e 350 + f 350 + 13 350 + 17 350 + 18 350 + 19 350 + 1a 350 + 1b 350 + 1c 350 + 1d 351 + 1e 351 + 1f 351 + 20 353 + 21 353 + 22 353 + 23 353 + 24 354 + 25 354 + 26 354 + 27 355 + 28 355 + 29 355 + 31 355 + 32 355 + 36 355 + 3a 355 + 3b 355 + 3c 355 + 3d 355 + 3e 355 + 3f 355 + 40 360 + 41 360 + 42 360 + 43 361 + 44 361 + 45 361 + 46 361 + 47 361 + 48 361 + 49 361 + 4a 361 + 4f 365 + 50 365 + 51 365 + 52 365 + 53 365 + 54 365 + 55 365 + 56 365 + 57 366 + 58 366 + 59 366 + 5a 366 + 5b 366 + 5c 367 + 5d 367 + 5e 367 + 5f 368 + 60 371 + 61 371 + 62 371 + 63 371 + 64 371 + 65 371 + 66 371 + 67 371 + 6a 375 + 6b 375 + 6c 375 + 6d 375 + 6e 375 + 6f 375 + 70 375 + 71 375 + 72 376 + 73 376 + 74 376 + 75 376 + 76 376 + 77 377 + 78 377 + 79 377 + 7d 379 + 7e 379 + 7f 379 + 80 379 + 81 379 + 82 379 + 83 379 + 84 379 + 85 380 + 86 380 + 87 380 + 88 380 + 89 380 + 8a 380 + 8b 380 + 8c 380 + 90 384 + 91 384 + 92 384 + 93 384 + 94 384 + 95 384 + 96 384 + 97 384 + 9b 387 + 9c 387 + 9d 387 + 9e 387 + 9f 387 + a0 387 + a1 387 + a2 387 + a3 388 + } +} + +Lines mapping: +8 <-> 9 +10 <-> 11 +11 <-> 12 +14 <-> 15 +17 <-> 16 +18 <-> 17 +24 <-> 23 +27 <-> 25 +29 <-> 26 +30 <-> 27 +33 <-> 30 +36 <-> 31 +37 <-> 32 +44 <-> 41 +46 <-> 52 +48 <-> 48 +52 <-> 55 +55 <-> 56 +56 <-> 57 +81 <-> 92 +82 <-> 95 +84 <-> 100 +86 <-> 97 +93 <-> 103 +94 <-> 104 +101 <-> 112 +103 <-> 116 +104 <-> 117 +105 <-> 118 +107 <-> 120 +109 <-> 123 +113 <-> 128 +114 <-> 129 +115 <-> 132 +116 <-> 133 +119 <-> 136 +120 <-> 137 +124 <-> 145 +126 <-> 149 +127 <-> 151 +128 <-> 152 +130 <-> 155 +131 <-> 156 +134 <-> 160 +135 <-> 161 +136 <-> 162 +138 <-> 165 +141 <-> 166 +142 <-> 167 +146 <-> 171 +148 <-> 173 +149 <-> 174 +150 <-> 175 +152 <-> 176 +153 <-> 177 +156 <-> 179 +170 <-> 183 +173 <-> 184 +177 <-> 188 +179 <-> 190 +180 <-> 191 +187 <-> 194 +188 <-> 195 +193 <-> 199 +195 <-> 201 +196 <-> 202 +197 <-> 203 +198 <-> 204 +199 <-> 205 +200 <-> 206 +201 <-> 207 +202 <-> 208 +215 <-> 211 +216 <-> 212 +221 <-> 216 +223 <-> 218 +224 <-> 219 +226 <-> 221 +228 <-> 223 +230 <-> 225 +232 <-> 227 +234 <-> 229 +236 <-> 231 +238 <-> 233 +240 <-> 235 +242 <-> 237 +244 <-> 239 +246 <-> 241 +277 <-> 245 +278 <-> 246 +282 <-> 250 +283 <-> 251 +284 <-> 252 +286 <-> 254 +287 <-> 255 +288 <-> 256 +291 <-> 259 +292 <-> 260 +294 <-> 262 +295 <-> 263 +296 <-> 264 +297 <-> 265 +299 <-> 268 +310 <-> 254 +312 <-> 272 +314 <-> 275 +315 <-> 276 +320 <-> 280 +321 <-> 281 +322 <-> 282 +324 <-> 285 +325 <-> 286 +326 <-> 287 +329 <-> 289 +330 <-> 290 +337 <-> 293 +338 <-> 294 +339 <-> 295 +343 <-> 299 +344 <-> 300 +345 <-> 301 +346 <-> 302 +348 <-> 305 +371 <-> 289 +373 <-> 309 +375 <-> 312 +377 <-> 315 +378 <-> 316 +383 <-> 320 +384 <-> 321 +385 <-> 322 +387 <-> 324 +388 <-> 325 +389 <-> 326 +392 <-> 329 +393 <-> 330 +395 <-> 332 +396 <-> 333 +397 <-> 334 +398 <-> 335 +400 <-> 338 +411 <-> 324 +413 <-> 342 +415 <-> 345 +416 <-> 346 +420 <-> 350 +421 <-> 351 +422 <-> 352 +424 <-> 354 +425 <-> 355 +426 <-> 356 +429 <-> 361 +430 <-> 362 +432 <-> 366 +433 <-> 367 +434 <-> 368 +435 <-> 369 +437 <-> 372 +441 <-> 376 +442 <-> 377 +443 <-> 378 +446 <-> 380 +448 <-> 381 +450 <-> 385 +452 <-> 388 +453 <-> 389 +Not mapped: +9 +12 +25 +31 +45 +47 +49 +50 +83 +85 +87 +88 +90 +102 +110 +111 +125 +132 +147 +151 +154 +157 +159 +161 +162 +163 +164 +165 +166 +167 +169 +178 +181 +182 +184 +185 +194 +203 +204 +206 +207 +208 +209 +210 +211 +212 +213 +222 +248 +249 +251 +252 +254 +256 +258 +260 +262 +264 +266 +268 +270 +272 +274 +293 +300 +301 +303 +304 +305 +306 +308 +340 +342 +349 +350 +352 +353 +354 +355 +357 +359 +362 +363 +364 +365 +367 +368 +394 +401 +402 +404 +405 +406 +407 +409 +431 +438 +439 +444 diff --git a/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java b/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java index 4eaf2e80cf..53998bb5ab 100644 --- a/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java +++ b/testData/src/java8/pkg/TestTryFinallyMarkerExceptions.java @@ -35,7 +35,7 @@ public void test2(int i) { System.out.println("Hello"); } catch (CatchAllException e) { System.out.println("Finally"); - if(i > 0) { + if (i > 0) { System.out.println(i); return; } @@ -43,7 +43,7 @@ public void test2(int i) { } { System.out.println("Finally"); - if(i > 0) { + if (i > 0) { System.out.println(i); return; } @@ -51,4 +51,16 @@ public void test2(int i) { System.out.println("Bye"); } + + + public void testNoTryExit(boolean b) { + try { + while (true) { + System.out.println("Hello"); + } + } catch (CatchAllException e) { + System.out.println("Finally"); + throw e; + } + } } diff --git a/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java index 152d43b47c..04bbe8408d 100644 --- a/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java +++ b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java @@ -101,21 +101,354 @@ public void testBlockReuse(int i) { System.out.println("Hello"); } catch (CatchAllException e) { System.out.println("Finally"); - if(i > 0){ + if (i > 0) { System.out.println("Cool 1"); } else { System.out.println("Cool 2"); } - if(i < 0); // break up basic block + if (i < 0) ; // break up basic block throw e; } { System.out.println("Finally"); - if(i > 0); + if (i > 0) ; System.out.println("Cool 1"); - if(i < 0); // break up basic block + if (i < 0) ; // break up basic block } System.out.println("Bye"); } + + public void testInjectWrongException(boolean b) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally start"); + if (b) { + e = new CatchAllException("yo"); + } + System.out.println("Finally end"); + throw e; + } + { + System.out.println("Finally start"); + if (b) { + CatchAllException e = new CatchAllException("yo"); + } + System.out.println("Finally end"); + } + + System.out.println("Bye"); + } + + public void testMultiImplicitExits(int i) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if (i > 0) { + System.out.println("Positive!"); + throw e; + } else if (i == 0) { + System.out.println("ZERO"); + throw e; + } else { + System.out.println("Negative!"); + throw e; + } + } + { + System.out.println("Finally"); + if (i > 0) { + System.out.println("Positive!"); + System.out.println("Bye 1"); + } else if (i == 0) { + System.out.println("ZERO"); + System.out.println("Bye 2"); + } else { + System.out.println("Negative!"); + System.out.println("Bye 3"); + } + } + } + + public void testConfusion1(String a, String b) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + System.out.println(a); + throw e; + } + { + System.out.println("Finally"); + System.out.println(b); + } + System.out.println("Bye"); + } + + public void testConfusion2() { + String x, y, z; + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + x = "X"; + y = "Y"; + z = "Z"; + x += z; + y += x; + z += y; + System.out.println(z); // "ZYXZ" + throw e; + } + { + System.out.println("Finally"); + y = "X"; // x -> y + z = "Y"; // y -> z + x = "Z"; // z -> x + z = y + z; // x -> z + x = z + x; // y -> x + y = x + y; // z -> y + System.out.println(y); // "XYZX" + } + System.out.println("Bye"); + } + + + public void testMismatchedSwitch(int i) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + switch (i) { + case 10: + System.out.println("10"); + case 9: + System.out.println("9"); + case 8: + System.out.println("8"); + case 7: + System.out.println("7"); + case 6: + System.out.println("6"); + case 5: + System.out.println("5"); + case 4: + System.out.println("4"); + case 3: + System.out.println("3"); + case 2: + System.out.println("2"); + case 1: + System.out.println("1"); + case 0: + System.out.println("Lift off!"); + } + throw e; + } + { + System.out.println("Finally"); + switch (i) { + case 1337_10: + System.out.println("10"); + case 1337_09: + System.out.println("9"); + case 1337_08: + System.out.println("8"); + case 1337_07: + System.out.println("7"); + case 1337_06: + System.out.println("6"); + case 1337_05: + System.out.println("5"); + case 1337_04: + System.out.println("4"); + case 1337_03: + System.out.println("3"); + case 1337_02: + System.out.println("2"); + case 1337_01: + System.out.println("1"); + case 1337_00: + System.out.println("Lift off!"); + } + } + System.out.println("Bye"); + } + + public void testMismatchedOutputExit(int a, int b) { + A: + while (a > 0) { + System.out.println("A: " + a); + a--; + B: + while (b > 0) { + a++; + System.out.println("B: " + b); + + try { + b--; + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if (a > b) { + a--; + continue A; + } + System.out.println("Boop"); + throw e; + } + { + System.out.println("Finally"); + if (a > b) { + a--; + continue B; + } + System.out.println("Boop"); + } + System.out.println("Beep"); + } + System.out.println("BLORB"); + } + System.out.println("Bye"); + } + + + public void testMismatchedOutputExit3(int a, int b, int c) { + A: + while (a > 0) { + System.out.println("A: " + a); + a--; + B: + while (b > 0) { + a++; + System.out.println("B: " + b); + + C: + while (c > 0) { + c -= b; + + C_post_finally: + { + C_finally: + { + try { + b--; + System.out.println("Hello"); + if (c < a) { + break C_finally; + } + } catch (CatchAllException e) { + System.out.println("Finally"); + if (a > b) { + a--; + continue A; + } + System.out.println("Boop"); + throw e; + } + { + System.out.println("Finally"); + if (a > b) { + a--; + continue B; + } + System.out.println("Boop"); + } + break C_post_finally; + } + { + System.out.println("Finally"); + if (a > b) { + a--; + continue C; + } + System.out.println("Boop"); + continue B; + } + } + System.out.println("Lost"); + } + System.out.println("Beep"); + } + System.out.println("BLORB"); + } + System.out.println("Bye"); + } + + + public void testMismatchedOutputExitReturn(int a, int b) { + A: + while (a > 0) { + System.out.println("A: " + a); + a--; + B: + while (b > 0) { + a++; + System.out.println("B: " + b); + + try { + b--; + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if (a > b) { + a--; + continue A; + } + System.out.println("Boop"); + throw e; + } + { + System.out.println("Finally"); + if (a > b) { + a--; + return; + } + System.out.println("Boop"); + } + System.out.println("Beep"); + } + System.out.println("BLORB"); + } + System.out.println("Bye"); + } + + public void testMismatchedOutputExitReturnInner(int a, int b) { + A: + while (a > 0) { + System.out.println("A: " + a); + a--; + B: + while (b > 0) { + a++; + System.out.println("B: " + b); + + try { + b--; + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if (a > b) { + a--; + return; + } + System.out.println("Boop"); + throw e; + } + { + System.out.println("Finally"); + if (a > b) { + a--; + continue B; + } + System.out.println("Boop"); + } + System.out.println("Beep"); + } + System.out.println("BLORB"); + } + System.out.println("Bye"); + } } diff --git a/testFixtures/org/jetbrains/java/decompiler/SingleClassesTestBase.java b/testFixtures/org/jetbrains/java/decompiler/SingleClassesTestBase.java index f3fdf0c0ef..e69797df24 100644 --- a/testFixtures/org/jetbrains/java/decompiler/SingleClassesTestBase.java +++ b/testFixtures/org/jetbrains/java/decompiler/SingleClassesTestBase.java @@ -278,14 +278,21 @@ public void run(Object[] options, SingleClassesTestBase base) throws IOException } else { // This is terrible! We shouldn't need this! The reason this exists is because Github Actions likes to create // different code in impossible to debug ways, so we just allowlist two different versions of the decompiled code. - Path tryNext = referenceFile.resolveSibling(referenceFile.getFileName().toString() - .replace(".dec", "_1.dec")); - - if (Files.exists(tryNext)) { - assertTrue(Files.isRegularFile(tryNext)); - assertEquals(getContent(tryNext), decompiledContent); - } else { - throw e; + + for (int i = 1; ; i++) { + Path tryNext = referenceFile.resolveSibling(referenceFile.getFileName().toString() + .replace(".dec", "_" + i + ".dec")); + + if (!Files.exists(tryNext)) { + throw e; + } else { + try { + assertTrue(Files.isRegularFile(tryNext)); + assertEquals(getContent(tryNext), decompiledContent); + break; + } catch (AssertionFailedError ignored) { + } + } } } } From f4fb4202e1a832d73a2095b2ee8bc65387157b5e Mon Sep 17 00:00:00 2001 From: Kroppeb <7889478+Kroppeb@users.noreply.github.com> Date: Tue, 2 Jun 2026 05:18:32 +0200 Subject: [PATCH 12/29] Fix: Multi entry exception deobf (#571) * Fix 2 bugs in multi entry exception ranges * Update dec file * Feature/better multi entry exception deobf (#586) * Improve output for some obfuscated exceptions * Update dec file * A tad more docs * Update src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java Co-authored-by: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> * Reword comment * update dec file --------- Co-authored-by: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> --------- Co-authored-by: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> --- .../java/decompiler/code/Instruction.java | 16 +- .../java/decompiler/code/cfg/BasicBlock.java | 2 +- .../decompiler/code/cfg/ControlFlowGraph.java | 19 +- .../modules/code/ExceptionDeobfuscator.java | 102 +++++++- .../results/pkg/TestTryCatchNoIncrement.dec | 235 ++++++++++++------ 5 files changed, 280 insertions(+), 94 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/code/Instruction.java b/src/org/jetbrains/java/decompiler/code/Instruction.java index 5b265898b4..bd6e390432 100644 --- a/src/org/jetbrains/java/decompiler/code/Instruction.java +++ b/src/org/jetbrains/java/decompiler/code/Instruction.java @@ -2,7 +2,6 @@ package org.jetbrains.java.decompiler.code; import org.jetbrains.java.decompiler.util.TextUtil; -import static org.jetbrains.java.decompiler.code.CodeConstants.*; public class Instruction implements CodeConstants { public static Instruction create( @@ -80,6 +79,21 @@ public boolean canFallThrough() { opcode != opc_jsr && opcode != opc_tableswitch && opcode != opc_lookupswitch; } + public boolean canNotThrow() { + // Ignoring VirtualMachineErrors, including link errors + return opcode <= opc_sipush || + (opc_iload <= opcode && opcode <= opc_aload_3) || + (opc_istore <= opcode && opcode <= opc_astore_3) || + (opc_pop <= opcode && opcode <= opc_dmul) || + (opcode == opc_fdiv) || + (opcode == opc_ddiv) || + (opcode == opc_frem) || + (opcode == opc_drem) || + (opc_ineg <= opcode && opcode <= opc_lookupswitch) || + (opcode == opc_wide) || + (opc_ifnull <= opcode && opcode <= opc_jsr_w); + } + @Override public String toString() { StringBuilder res = new StringBuilder(); diff --git a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java index e3f390336c..65be298241 100644 --- a/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java +++ b/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java @@ -174,7 +174,7 @@ public int getId() { } @Override - public Collection getPredecessors() { + public Collection getPredecessors() { List lst = new ArrayList<>(preds); lst.addAll(predExceptions); return lst; diff --git a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java index 7b8510fad6..5d0cde87f7 100644 --- a/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java +++ b/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java @@ -153,19 +153,28 @@ public void removeBlock(BasicBlock block) { } public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) { - - //List ranges = new ArrayList(); - for (int i = exceptions.size() - 1; i >= 0; i--) { ExceptionRangeCFG range = exceptions.get(i); if (range.getHandler() == handler && range.getProtectedRange().contains(block)) { return range; - //ranges.add(range); } } return null; - //return ranges.isEmpty() ? null : ranges; + } + + public List getAllExceptionRanges(BasicBlock handler, BasicBlock block) { + + List ranges = new ArrayList<>(); + + for (int i = exceptions.size() - 1; i >= 0; i--) { + ExceptionRangeCFG range = exceptions.get(i); + if (range.getHandler() == handler && range.getProtectedRange().contains(block)) { + ranges.add(range); + } + } + + return ranges; } // public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) { diff --git a/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java b/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java index 5ce80b3ba8..a3c245da77 100644 --- a/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java +++ b/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java @@ -1,6 +1,7 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.modules.code; +import org.jetbrains.annotations.Nullable; import org.jetbrains.java.decompiler.code.*; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph; @@ -8,6 +9,7 @@ import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.jetbrains.java.decompiler.modules.decompiler.ValidationHelper; import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine; import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph; import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode; @@ -263,7 +265,9 @@ private static List getReachableBlocksRestricted(BasicBlock start, E while (!stack.isEmpty()) { BasicBlock block = stack.removeFirst(); - setVisited.add(block); + if(!setVisited.add(block)) { + continue; + } if (range.getProtectedRange().contains(block) && engine.isDominator(block, start)) { lstRes.add(block); @@ -271,11 +275,7 @@ private static List getReachableBlocksRestricted(BasicBlock start, E List lstSuccs = new ArrayList<>(block.getSuccs()); lstSuccs.addAll(block.getSuccExceptions()); - for (BasicBlock succ : lstSuccs) { - if (!setVisited.contains(succ)) { - stack.add(succ); - } - } + stack.addAll(lstSuccs); } } @@ -336,12 +336,17 @@ public Set getRoots() { boolean splitted = false; for (ExceptionRangeCFG range : graph.getExceptions()) { - Set setEntries = getRangeEntries(range); + // map of entry points to entry sources (null indicating method start) + LinkedHashMap> setEntries = getRangeEntries(range, graph.getFirst()); if (setEntries.size() > 1) { // multiple-entry protected range found = true; - if (splitExceptionRange(range, setEntries, graph, engine)) { + if (growExceptionRange(range, setEntries)) { + splitted = true; + graph.addComment("$VF: Handled exception range with multiple entry points by expanding it"); + break; + } else if (splitExceptionRange(range, setEntries.keySet(), graph, engine)) { splitted = true; graph.addComment("$VF: Handled exception range with multiple entry points by splitting it"); break; @@ -357,22 +362,95 @@ public Set getRoots() { return !found; } - private static Set getRangeEntries(ExceptionRangeCFG range) { - Set setEntries = new HashSet<>(); + private static LinkedHashMap> getRangeEntries(ExceptionRangeCFG range, BasicBlock first) { + LinkedHashMap> setEntries = new LinkedHashMap<>(); Set setRange = new HashSet<>(range.getProtectedRange()); for (BasicBlock block : range.getProtectedRange()) { - Set setPreds = new HashSet<>(block.getPreds()); + List<@Nullable BasicBlock> setPreds = new ArrayList<>(block.getPreds()); setPreds.removeAll(setRange); + if (block == first){ + setPreds.add(null); + } if (!setPreds.isEmpty()) { - setEntries.add(block); + setEntries.put(block, setPreds); } } return setEntries; } + private static boolean growExceptionRange( + ExceptionRangeCFG range, + LinkedHashMap> setEntries + ) { + // Try to inline basic blocks that can't throw, but are only reachable from within this handler + // and have successors in this handler + // Each try handler must have at least one entry point that can't be removed + @Nullable BasicBlock missed = null; + + for(var entry : setEntries.entrySet()) { + BasicBlock destination = entry.getKey(); + if (!validateExceptionGrow(range, entry.getValue())){ + if (missed == null) { + missed = destination; + continue; + } + return false; // At least 2 entry points exist that can't be fixed + } + } + + ValidationHelper.notNull(missed); + + // Cleanup is possible. Add blocks to exception range. + Set handled = new HashSet<>(); + for(var entry : setEntries.entrySet()) { + if (missed == entry.getKey()) { + continue; + } + for (BasicBlock block : entry.getValue()) { + ValidationHelper.notNull(block); + if (!handled.add(block)) { // prevent handling twice + continue; + } + block.addSuccessorException(range.getHandler()); + range.getProtectedRange().add(block); + } + } + return true; + } + + private static boolean validateExceptionGrow( + ExceptionRangeCFG range, + List<@Nullable BasicBlock> blocks + ){ + Set protectedRange = new HashSet<>(range.getProtectedRange()); + for (BasicBlock block : blocks) { + // can't optimize away method entry + if (block == null) { + return false; + } + + if(!protectedRange.containsAll(block.getPredecessors())) { + // limit to inlining single blocks, not sequences of blocks + return false; + } + + for (Instruction inst:block.getSeq()){ + if (!inst.canNotThrow()) { + // We don't want to catch extra exceptions + // many instructions can only throw a very small number of exceptions + // so we could actually filter more lenient based on the caught exception types + return false; + } + } + } + return true; + } + + + private static boolean splitExceptionRange(ExceptionRangeCFG range, Set setEntries, ControlFlowGraph graph, diff --git a/testData/results/pkg/TestTryCatchNoIncrement.dec b/testData/results/pkg/TestTryCatchNoIncrement.dec index 6b41ea8e08..1ff3dacdd9 100644 --- a/testData/results/pkg/TestTryCatchNoIncrement.dec +++ b/testData/results/pkg/TestTryCatchNoIncrement.dec @@ -14,82 +14,51 @@ public class TestTryCatchNoIncrement { } }// 20 - public final void skippedInc(List param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: bipush 0 - // 01: istore 2 - // 02: iload 2 - // 03: aload 1 - // 04: invokeinterface java/util/List.size ()I 1 - // 09: if_icmpge 3f - // 0c: aload 1 - // 0d: iload 2 - // 0e: invokeinterface java/util/List.get (I)Ljava/lang/Object; 2 - // 13: checkcast java/lang/String - // 16: astore 3 - // 17: getstatic java/lang/System.out Ljava/io/PrintStream; - // 1a: new java/lang/StringBuilder - // 1d: dup - // 1e: invokespecial java/lang/StringBuilder. ()V - // 21: iload 2 - // 22: invokevirtual java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; - // 25: ldc ": " - // 27: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; - // 2a: aload 3 - // 2b: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; - // 2e: invokevirtual java/lang/StringBuilder.toString ()Ljava/lang/String; - // 31: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 34: iinc 2 1 - // 37: goto 3c - // 3a: astore 4 - // 3c: goto 02 - // 3f: goto 47 - // 42: astore 2 - // 43: aload 2 - // 44: invokevirtual java/lang/Throwable.printStackTrace ()V - // 47: return - // try (0 -> 23): 28 java/lang/Throwable - // try (24 -> 27): 28 java/lang/Throwable - } + // $VF: Handled exception range with multiple entry points by expanding it + public final void skippedInc(List items) { + try { + for (int i = 0; i < items.size(); i++) {// 24 25 29 + String item = (String)items.get(i);// 26 + System.out.println(i + ": " + item);// 27 + } + } catch (Throwable ex2) {// 34 + ex2.printStackTrace();// 35 + } + }// 38 - public final void skipPrinting(List param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: bipush 0 - // 01: istore 2 - // 02: iload 2 - // 03: aload 1 - // 04: invokeinterface java/util/List.size ()I 1 - // 09: if_icmpge 3f - // 0c: aload 1 - // 0d: iload 2 - // 0e: invokeinterface java/util/List.get (I)Ljava/lang/Object; 2 - // 13: checkcast java/lang/String - // 16: astore 3 - // 17: getstatic java/lang/System.out Ljava/io/PrintStream; - // 1a: new java/lang/StringBuilder - // 1d: dup - // 1e: invokespecial java/lang/StringBuilder. ()V - // 21: iload 2 - // 22: invokevirtual java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; - // 25: ldc ": " - // 27: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; - // 2a: aload 3 - // 2b: invokevirtual java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; - // 2e: invokevirtual java/lang/StringBuilder.toString ()Ljava/lang/String; - // 31: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 34: goto 39 - // 37: astore 4 - // 39: iinc 2 1 - // 3c: goto 02 - // 3f: goto 47 - // 42: astore 2 - // 43: aload 2 - // 44: invokevirtual java/lang/Throwable.printStackTrace ()V - // 47: return - // try (0 -> 11): 28 java/lang/Throwable - // try (23 -> 27): 28 java/lang/Throwable + // $VF: Handled exception range with multiple entry points by splitting it + // $VF: Duplicated exception handlers to handle obfuscated exceptions + public final void skipPrinting(List items) { + int i; + try { + i = 0; + } catch (Throwable ex2) { + ex2.printStackTrace();// 50 + return;// 52 + } + + while (true) { + String item; + try { + if (i >= items.size()) { + break; + } + + item = (String)items.get(i);// 42 + } catch (Throwable ex2) { + ex2.printStackTrace(); + break; + } + + System.out.println(i + ": " + item);// 44 + + try { + i++;// 41 + } catch (Throwable ex2) { + ex2.printStackTrace(); + break; + } + } } } @@ -141,6 +110,101 @@ class 'pkg/TestTryCatchNoIncrement' { 41 12 42 14 } + + method 'skippedInc (Ljava/util/List;)V' { + 0 19 + 1 19 + 2 19 + 3 19 + 4 19 + 5 19 + 6 19 + 7 19 + 8 19 + 9 19 + a 19 + b 19 + c 20 + d 20 + e 20 + f 20 + 10 20 + 11 20 + 12 20 + 13 20 + 14 20 + 15 20 + 16 20 + 17 21 + 18 21 + 19 21 + 21 21 + 25 21 + 26 21 + 2a 21 + 2e 21 + 2f 21 + 30 21 + 31 21 + 32 21 + 33 21 + 34 19 + 35 19 + 36 19 + 42 23 + 43 24 + 44 24 + 45 24 + 46 24 + 47 26 + } + + method 'skipPrinting (Ljava/util/List;)V' { + 0 33 + 1 33 + 2 42 + 3 42 + 4 42 + 5 42 + 6 42 + 7 42 + 8 42 + 9 42 + a 42 + b 42 + c 46 + d 46 + e 46 + f 46 + 10 46 + 11 46 + 12 46 + 13 46 + 14 46 + 15 46 + 16 46 + 17 52 + 18 52 + 19 52 + 21 52 + 25 52 + 26 52 + 2a 52 + 2e 52 + 2f 52 + 30 52 + 31 52 + 32 52 + 33 52 + 39 55 + 3a 55 + 3b 55 + 43 35 + 44 35 + 45 35 + 46 35 + 47 36 + } } Lines mapping: @@ -150,5 +214,26 @@ Lines mapping: 17 <-> 12 18 <-> 13 20 <-> 15 +24 <-> 20 +25 <-> 20 +26 <-> 21 +27 <-> 22 +29 <-> 20 +34 <-> 24 +35 <-> 25 +38 <-> 27 +41 <-> 56 +42 <-> 47 +44 <-> 53 +50 <-> 36 +52 <-> 37 Not mapped: 19 +30 +31 +32 +36 +45 +46 +49 +51 From 2a92cedfb8b63937d8cd44ea4e91e8018850a20b Mon Sep 17 00:00:00 2001 From: Kroppeb <7889478+Kroppeb@users.noreply.github.com> Date: Tue, 2 Jun 2026 05:26:01 +0200 Subject: [PATCH 13/29] Finally cleanup (#592) * temp commit to trigger diff machine * Fix mistake * Strict null * More cleanup and docs * More cleanup * I think I went too far * fix wrong cleanup * Fix typo's etc in the docs * comments * Don't use strings --- build.gradle | 2 +- docs/finally-processing.md | 235 +++++ .../decompiler/code/InstructionSequence.java | 23 + .../modules/decompiler/FinallyProcessor.java | 850 +++++++++--------- .../modules/decompiler/stats/Statement.java | 3 +- 5 files changed, 686 insertions(+), 427 deletions(-) create mode 100644 docs/finally-processing.md diff --git a/build.gradle b/build.gradle index b78f88ec85..3518c1641c 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { } dependencies { - implementation 'org.jetbrains:annotations:24.0.0' + implementation 'org.jetbrains:annotations:26.1.0' testImplementation("org.junit.jupiter:junit-jupiter-api:${project.junit_bom}") testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${project.junit_bom}") diff --git a/docs/finally-processing.md b/docs/finally-processing.md new file mode 100644 index 0000000000..409703ec7b --- /dev/null +++ b/docs/finally-processing.md @@ -0,0 +1,235 @@ +# Finally processing + +This document aims to explain how `finally` statements are detected and reconstructed. + +## What is a `finally` (in Java) + +You might have used a "try finally" statement before, but what does it do actually? + +Java 25 spec (14.20. The `try` statement): + +> A `try` statement executes a block. If a value is thrown and the `try` statement has one or more `catch` clauses that +> can catch it, then control will be transferred to the first such `catch` clause. If the `try` statement has a +> `finally` clause, then another block of code is executed, no matter whether the `try` block completes normally or +> abruptly, and no matter whether a `catch` clause is first given control. + +(This is later followed by a 17-step instruction plan on how to actually evaluate a try finally in section 14.20.2.) + +Unless you have experience reading the Java spec, that might not have been a great explanation at all. Let's digest it. +In short: A `try` statement will execute the first block it's given. If that block produces an error, it will look +through its `catch` blocks to see if any of them are able to handle the error. If so, the first one that is applicable +is selected and that block is executed. At the end of the execution of the code inside the `try` and (if applicable) +`catch` block, execution is ALWAYS transferred to the `finally` block. This includes exiting "normally" meaning that +execution has just reached the end of the block, and "abruptly" which means a (yet) uncaught `throw`, a `return`, +a `break`, a `continue` or a `yield` statement have been executed, and it's target (in case of `break`, `continue` and +`yield`) is outside the "try finally". + +Now, this is long and complex, but we can reduce this complex logic a bit. Although the spec doesn't mention this, the +following 2 code snippets are essentially equivalent. + +```java +try{ + // block 1 + }catch(...){ + // block 2 + }finally{ + // block 3 + } +``` + +is equivalent to + +```java +try{ + try{ + // block 1 + }catch(...){ + // block 2 + } + }finally{ + // block 3 + } +``` + +This simplification is used in Vineflower. A "try-catch-finally" is actually a "try-catch" inside the `try` block of +a "try-finally". When the statement tree is converted into java code, the "try-finally" will see that it's `try` block +is just a "try-catch" and will not write its own `try` block, but will instead just append its `finally` block to the +"try-catch". + +### Finally control flow hijacking. + +a.k.a. Why does my ide yell at me? + +Let's look at a simple example + +```java +int test(int x) { + while (true) { + try { + // ... + if (x < 20) { + return x + 5; + } + // ... + } finally { + // ... + continue; + } + } +} +``` + +A first naive thought might be that the `continue` is redundant, after all, it's the last statement executed inside a +while statement. If you open it in a smart editor however, you might get warnings along the lines of: + +* "`continue` in `finally`" +* "`finally` can't complete normally" + +Instead of a "redundant `continue`. What are these warnings about? + +The snippet from the specs copied above is only a short "informative" explanation of what a try-catch-finally does, and +it misses an important part compared to the 17-step normative specification. As mentioned, after the execution of the +`try` block (and maybe a `catch` block), execution is transferred to the `finally` block, but what happens after the +`finally` block? The spec differentiates 2 cases: + +* The `finally` block completes "normally" (it just ended, no thrown exception, no `return`, no `break`, `continue` or + `yield`). In this case, the execution will then go to wherever the `try` block (or `catch` block) wanted to go to. +* The `finally` block completes "abruptly" (it ended by throwing an exception, or running a `return`, `break`, + `continue` or `yield`). In this case, the execution will not resume where the `try` (or `catch`) block wanted to go + to, but instead, it will go wherever this "abrupt end" wants us to go to. Method exit in case of `return` or an + uncaught error, a `catch` block in case of a caught error, the end of a loop in case of `break`, the start of a loop + in case of a `continue`, the result of a `switch` expression in case of `yield`. + +The example code above will thus never `return` and instead run in an infinite loop. It will calculate the result of +`x + 5`, and store it in a temporary variable while it evaluates the `finally` block. But the `finally` block will +always end with the `continue` and thus always restart the loop and ignore the fact that there was a `return`. + +This behavior is almost never the intention of the user. This construct can occur in many languages (Java, Python, +JavaScript, ...). Some languages produce warnings, other give compile errors, and those that don't, have linters that +don't allow it. + +## How are `finally`s compiled + +(This section assumes the Vineflower simplification listed above) + +In the initial Java 1 implementations, `finally` blocks were compiled using the `jsr` and `ret` opcodes. This allowed +for the creation of mini-functions (subroutines) inside the larger function. At each point in the `try` block, right +before an exit out of that block (`return`, `break`, ... or just normally exiting) the subroutine with the code of the +`finally` block was called. Additionally, there is an exception handler present that catches all exceptions (VF: " +catch-all") in the code for the `try` block which jumps to a piece of code that stores the exception in a variable, also +jumps to the `finally` subroutine and then rethrows the caught exception. + +However, even though there are restrictions on the subroutines (no recursing, each subroutine can have at most one `ret` +instruction, and a nested subroutine call can no longer be returned from if an outer sub routine has already returned), +it made validating and optimizing the bytecode non-trivial. As a result, starting in Java 2-3, and required for classes +with classfile version 51.0 and above (Java 7), `jsr` and `ret` were no longer used and instead, each exit point and +the catch-all will jump to their own copied version of the `finally` block code. + +Handling `jsr` and `ret` instructions isn't only annoying for the Java Runtime, it's also annoying for Vineflower. +As a result, one of the very first processing steps on the parsed Control Flow Graph is the inlining of jsr +instructions. This means that we convert old Java 5 and before `finally`s into the version that we'd expect for Java 6+. +Given that in a later step we will need to deduplicate these, this might seem like a weird action to take but abusing +`jsr` and `ret` was really popular in obfuscators. This meant that assuming that these subroutines can always be +converted into "try-finally"'s isn't an option. + +## Decompiling `finally` + +The decompilation of `finally` happens currently in these 3 steps. + +1. Decompile the "try catch" blocks corresponding to the catch-all handler of the finally +2. Validate that the caught exception in the handler behaves correctly, and categorize the finally exits. +3. Find and remove all copy versions. + +Each of these 3 steps will give different results if that step fails. + +### Decompiling the `catch` block. + +Each exception handler in the bytecode has an exception type it catches. However, there is also an option to not +specify a type. In this case, ALL exception are caught. This ends up being equivalent to catching `Throwable` as all +types that can be thrown MUST inherit from `Throwable` in some way. These types of catches are thus called "catch all" + +In Java, there is no way to manually specify "catch all", and finally will always use "catch all". As a result, the +original creator of Fernflower (Stiver) decided to use this as a single source of truth of whether a `catch` block is +supposed to remain a `catch` block, or whether it is supposed to be a `finally`. These "catch all" handlers are not +eligible for the standard `CatchStatement` detection. Instead, they are converted into `CatchAllStatements` by the +`DomHelper`. All basic blocks that are only reachable by the `catch` handler will then be put inside the `catch` block. + +If anything goes wrong with detecting the `CatchAllStatement`, the decompilation process for the method will be halted +due to a "failure to decompose". + +### Validation of the `catch` handler and classification + +The next step is `getFinallyInformation`. The instructions are converted into initial exprents and SSA and SSAU analysis +are run. This is used to figure out if the caught exception behaves. In case the catch handler immediately stores the +exception variable inside a variable, this variable is considered the "exception var", otherwise the fake stack var will +be the "exception var". In the case of immediately storing the caught exception, the handler is considered to be a +`STORE` type handler. SSA processing is then used to group all reads and writes of each var into groups based on whether +they are connected in some way. Then all statements are analyzed. There should only be 2 types of accesses to the " +exception var". + +The first is the UNIQUE initial assignment at the start of the catch handler. In case of a `STORE` handler that is the +assignment of the real var, in all other cases, it is the virtual assignment to the fake stack var injected at the +start of the handler. + +All other accesses MUST be just throwing the exception var. If this is not a `STORE` handler, it must just be +`throw `. In case of a `STORE` handler, the process must be in 2 parts, as these are still raw exprents +without any inlining performed. It must be ` = `, followed by `throw `. Note that the +`throw` can be the next exprent in the basic block, or the first exprent in next basic block (assuming there is only one +single next block). + +Each of the basic blocks that end with the later access will be classified as `IMPLICIT_END`, these are the places (or +normally the single place, FIXME: VF assumes there is only 1 and misdecompiles) that (for the non exception case) lead +out of the finally that will continue the execution to the location the `try` block wanted to go to. + +The code classifies 2 other types of exits. Those that `return` or `throw` inside the `finally` handler are called +`METHOD_END`. They don't need any other processing so are kept separate. Finally, there is `EXPLICIT_END`. These are +exits that also interrupt the control flow and do not let control flow go to where the `try` block was planning to go. +These are also called `sideExits` in parts of the code. + +At the end there is a check to see whether there the catch handler is considered "empty". This analysis seems to be +broken though, and its goal is not clear. + +If the analysis results in an error (e.g. the "exception var" is used in an illegal way), the "catch-all" will just +decompile as a "catch Throwable" with a comment `"Could not inline inconsistent finally blocks"`. + +### Deduplication of finally handler + +The final step is to find all exit points of the `try` block and validate that they go to their own copy of the +`finally` block. + +All jumps out of the `try` block are identified, and one by one are compared with the `catch` block. For each so-called +"sample", we start with comparing the start block (sample block) against the first block of the catch handler (pattern +block) and start comparing instructions one by one. If they all(1)(2) match(3), then its successors are compared in the +same way, as long as the pattern successor blocks are still inside the finally catch handler. If not, then that edge is +a type +of "finally exit". Catch handlers on these sample & pattern blocks are also compared. The exception types must match +and the handlers are then also compared if they are inside the finally catch handler. + +The caveats: + +(1): In case of the very first block of the finally catch handler, an initial `pop` (discarding the exception) or +`astore` (storing the exception) instruction will be skipped in the comparison. Additionally, for the "normal" exit +out of the `finally` block, the `throw` (and previous `aload` in case of a `STORE` finally type) are also skipped. + +(2): It is permitted for a sample block to contain more instruction than its corresponding pattern block. In this case, +the remaining unmatched instructions will be split into a new basic block, taking over all the successors, copying the +exception handlers and becoming the sole successor of the original sample block + +(3): Matching instructions ignores a few things. First, variables defined inside a `finally` block can have different +variable indices between copies. The processor tries to keep a list of match ups but is actually too lenient. Jump +targets in jump and switch blocks are ignored. + +If everything looks okay, then the info is bundled into an `Area` object. If all the jumps out of the `try` block have +been validated, the `Area`s are deleted from the graph, and the exception handling instructions are removed from the +finally catch handler so it can be used as a proper `finally` block instead. + +If any of the jumps fails to validate, the `catch` block is still converted into a `finally` block, but a "semaphore" +variable is introduced. It is set to true when the `try` block is entered, and set to false when it is exited. The code +inside the `finally` block is then only executed if the value is set to true. effectively emulating a `catch` block with +a `finally` block. All other "copies" (those that do and those that don't match) are left as is. + +### Multiple `finally`'s + +After a CatchAllStatement is processed, the result is stored (did the `finally` successfully match or not, if not is +there a semaphore variable or not, and which variable is it). And the dom helper is run again. No attempt is made to +keep working on the original tree. \ No newline at end of file diff --git a/src/org/jetbrains/java/decompiler/code/InstructionSequence.java b/src/org/jetbrains/java/decompiler/code/InstructionSequence.java index 4f1bc33718..d489477657 100644 --- a/src/org/jetbrains/java/decompiler/code/InstructionSequence.java +++ b/src/org/jetbrains/java/decompiler/code/InstructionSequence.java @@ -20,6 +20,10 @@ public InstructionSequence(Collection instructions) { this.instructions = new ArrayList<>(instructions); } + private InstructionSequence(List instructions, boolean _alternateConstructor){ + this.instructions = instructions; + } + // ***************************************************************************** // public methods // ***************************************************************************** @@ -71,6 +75,25 @@ public boolean isEmpty() { return this.instructions.isEmpty(); } + public InstructionSequence split(int i){ + /// Remove all instructions starting at index i and put then in a new Sequence + List subInstruction = this.instructions.subList(i, this.instructions.size()); + InstructionSequence seq = new InstructionSequence(subInstruction); // will make a copy of the list + subInstruction.clear(); // will remove all of them from the instructions list. + return seq; + } + + public InstructionSequence subSequence(int fromIndex) { + return subSequence(fromIndex, length()); + } + + public InstructionSequence subSequence(int fromIndex, int toIndex) { + /// Same semantics as `List.subList`, using negative indices will count from the end. + int realFromIndex = fromIndex >= 0 ? fromIndex: fromIndex + length(); + int realToIndex = toIndex >= 0 ? toIndex: toIndex + length(); + return new InstructionSequence(this.instructions.subList(realFromIndex, realToIndex), true); + } + public String toString() { return toString(0); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java index 0f3a9e7fac..98cb9d4ad2 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java @@ -1,6 +1,8 @@ // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.modules.decompiler; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.java.decompiler.code.*; import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph; @@ -23,6 +25,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.sforms.SimpleSSAReassign; import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.DummyExitStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; @@ -33,24 +36,24 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.util.InterpreterUtil; +import org.jetbrains.java.decompiler.util.Pair; import org.jetbrains.java.decompiler.util.collections.ListStack; import java.util.*; import java.util.Map.Entry; +@NotNullByDefault public class FinallyProcessor { - private final Map finallyBlocks = new HashMap<>(); + private final Map finallyBlocks = new HashMap<>(); // seems to store catch-alls that can't be converted to a finally private final Set catchallBlocks = new HashSet<>(); - private final StructMethod mt; private final MethodDescriptor methodDescriptor; private final VarProcessor varProcessor; - private VarVersionsGraph ssuversions; - private Map instrRewrites; + private @Nullable VarVersionsGraph ssuversions; + private @Nullable Map instrRewrites; public FinallyProcessor(StructMethod mt, MethodDescriptor md, VarProcessor varProc) { - this.mt = mt; this.methodDescriptor = md; this.varProcessor = varProc; } @@ -66,21 +69,22 @@ public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, Statement stat = stack.pop(); Statement parent = stat.getParent(); - if (parent instanceof CatchAllStatement && stat == parent.getFirst() && !parent.isCopied()) { - - CatchAllStatement fin = (CatchAllStatement) parent; + if (parent instanceof CatchAllStatement fin && stat == parent.getFirst() && !parent.isCopied()) { BasicBlock head = fin.getBasichead().getBlock(); BasicBlock handler = fin.getHandler().getBasichead().getBlock(); //noinspection StatementWithEmptyBody if (this.catchallBlocks.contains(handler)) { + // Already checked, can't be replaced by a finally statement. // do nothing } else if (this.finallyBlocks.containsKey(handler)) { + // Already validated and transformed. This is a finally statement. fin.setFinally(true); Integer var = this.finallyBlocks.get(handler); fin.setMonitor(var == null ? null : new VarExprent(var, VarType.VARTYPE_INT, this.varProcessor)); } else { + // Check if this is a finally statement. Record inf = this.getFinallyInformation(cl, mt, root, fin); if (inf == null) { // inconsistent finally @@ -88,10 +92,12 @@ public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, root.addComment("$VF: Could not inline inconsistent finally blocks", true); } else { if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && this.verifyFinallyEx(graph, fin, inf)) { + // Finally transformation was successful. inlineReturnVar(graph, handler, inf); this.finallyBlocks.put(handler, null); } else { + // Finally merging failed. int varIndex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER); // Add the semaphore variable to the list so we can create a comment in the output this.varProcessor.getSyntheticSemaphores().add(varIndex); @@ -119,19 +125,30 @@ public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, return false; } - private static final class Record { - private final int firstCode; - private final int exceptionOffset; - private final Map mapLast; + private enum FinallyType { + OTHER, // Exception is kept in a stack var. + DROP, // Drop the exception immediately after catching it, can't be rethrown + STORE, // Store the exception immediately in a variable after catching it. + EMPTY, // The finally is empty? + } - private Record(int firstCode, int exceptionOffset, Map mapLast) { - this.firstCode = firstCode; - this.exceptionOffset = exceptionOffset; - this.mapLast = mapLast; - } + private enum ExitType { + IMPLICIT_EXIT, // Normal end of the finally + EXPLICIT_EXIT, // `break` and `continue` that leave a finally block + METHOD_EXIT, // `return` or `throw` inside a finally block } - private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) { + private record Record(FinallyType finallyType, int exceptionOffset, Map mapLast) { + } + + private record Area(BasicBlock start, Set sample, @Nullable BasicBlock next /* true exit */, + Set sideExits) { + } + + private record FinallyExit(BasicBlock source, BasicBlock succ, ExitType type) { + } + + private @Nullable Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) { ExprProcessor proc = new ExprProcessor(this.methodDescriptor, this.varProcessor); proc.processStatement(root, cl); @@ -151,7 +168,7 @@ private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatem StackVarsProcessor.setVersionsToNull(root); } - Map mapLast = new LinkedHashMap<>(); + Map mapLast = new LinkedHashMap<>(); BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead(); BasicBlock firstBasicBlock = firstBlockStatement.getBlock(); @@ -162,22 +179,22 @@ private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatem Instruction instrFirst = firstBasicBlock.getInstruction(0); - int firstcode = 0; - - switch (instrFirst.opcode) { - case CodeConstants.opc_pop: - firstcode = 1; - break; - case CodeConstants.opc_astore: - firstcode = 2; - } + FinallyType firstcode = switch (instrFirst.opcode) { + case CodeConstants.opc_pop -> FinallyType.DROP; + case CodeConstants.opc_astore -> FinallyType.STORE; + default -> FinallyType.OTHER; + }; SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); ssa.splitVariables(root, mt); List lstExprents = firstBlockStatement.getExprents(); + ValidationHelper.notNull(lstExprents); // All BBStatements will have exprents by now - VarVersionPair varpaar = new VarVersionPair((VarExprent) ((AssignmentExprent) lstExprents.get(firstcode == 2 ? 1 : 0)).getLeft()); + // A catch block always starts with an assignment from a fake catch var to stack index 0 + // In case of a STORE type, we don't care about this temp var, and immediately want to know where this stack var is + // saved instead. + VarVersionPair varpaar = new VarVersionPair((VarExprent) ((AssignmentExprent) lstExprents.get(firstcode == FinallyType.STORE ? 1 : 0)).getLeft()); FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); DirectGraph dgraph = flatthelper.buildDirectGraph(root); @@ -186,173 +203,187 @@ private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatem stack.add(dgraph.first); Set setVisited = new HashSet<>(); + Statement handler = fstat.getHandler(); while (!stack.isEmpty()) { DirectNode node = stack.removeFirst(); - if (setVisited.contains(node)) { + if (setVisited.contains(node) || node.statement instanceof DummyExitStatement) { + // skip dummy. + // this is related to how it selects the blockStatement and could be + // removed when the selection is changed. continue; } setVisited.add(node); - BasicBlockStatement blockStatement = null; + // Null means the catch var leaked in a way that can't happen with true "finally"s. + // This is thus not a true finally, return null. + // Will return "explicit" even if the block does not leave the handler. It indicates that + // IF this block is an exit, it's an explicit type. + @Nullable ExitType exitType = getExitType(firstcode, firstBlockStatement, node, varpaar); + if (exitType == null) return null; + + for (DirectEdge suc : node.getSuccessors(DirectEdgeType.REGULAR)) { + stack.add(suc.getDestination()); + } + + BasicBlockStatement blockStatement; if (node.block != null) { blockStatement = node.block; } else if (node.getPredecessors(DirectEdgeType.REGULAR).size() == 1) { - blockStatement = node.getPredecessors(DirectEdgeType.REGULAR).get(0).getSource().block; + DirectNode source = node.getPredecessors(DirectEdgeType.REGULAR).get(0).getSource(); + if (source.block == null) { + continue; + } + blockStatement = source.block; + } else { + continue; } - boolean isTrueExit = true; + if (blockStatement.getBlock() == null || !handler.containsStatement(blockStatement)) { + continue; + } - if (firstcode != 1) { + for (StatEdge edge : blockStatement.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) { + if (edge.getType() != StatEdge.TYPE_REGULAR && + !handler.containsStatement(edge.getDestination())) { - isTrueExit = false; + ExitType existingFlag = mapLast.get(blockStatement.getBlock()); - // Try to find the "true path" of the finally block by searching for a relevant 'athrow '. - // We should search from the initial expression of each block, except in the case where the block we're searching - // contains the relevant var itself, in which case we should search from the 2nd or 3rd expression, depending on - // the firstcode. This is because we might accidentally stumble into the same expression we were searching from, - // leading to a false failure of finally processing. - int startIdx = 0; - if (firstBlockStatement == node.block) { - // firstcode (only 0 or 2 here) determines which instruction to start from. - startIdx = firstcode == 2 ? 2 : 1; + if (existingFlag != ExitType.IMPLICIT_EXIT) { + mapLast.put(blockStatement.getBlock(), exitType); + break; + } } + } + } + + // empty finally block? + if (fstat.getHandler() instanceof BasicBlockStatement) { + + boolean isFirstLast = mapLast.containsKey(firstBasicBlock); + InstructionSequence seq = firstBasicBlock.getSeq(); + + // Check if empty + if (switch (firstcode) { + case OTHER -> isFirstLast && seq.length() == 1; + case DROP -> seq.length() == 1; + case STORE -> isFirstLast ? seq.length() == 3 : seq.length() == 1; + default -> false; + }) { + firstcode = FinallyType.EMPTY; + } + } + + return new Record(firstcode, instrFirst.startOffset, mapLast); + } + + private static @Nullable ExitType getExitType( + FinallyType finallyType, + BasicBlockStatement firstBlockStatement, + DirectNode node, + VarVersionPair varPair + ) { + // Try to find the "true path" of the finally block by searching for a relevant 'athrow '. + // If we encounter a usage of that isn't a throw, then, this isn't a valid finally. + + return switch (finallyType) { + case DROP -> ExitType.IMPLICIT_EXIT; // Why is this considered an implicit exit? + case EMPTY -> throw new IllegalStateException("Empty detection has not been done yet?"); + case STORE -> { + // Skip the `var10000 = varx;` and `vary = var10000` statements on the entry block + int startIdx = firstBlockStatement == node.block ? 2 : 0; for (int i = startIdx; i < node.exprents.size(); i++) { Exprent exprent = node.exprents.get(i); - if (firstcode == 0) { - List lst = exprent.getAllExprents(); - lst.add(exprent); - - boolean found = false; - for (Exprent expr : lst) { - if (expr instanceof VarExprent && new VarVersionPair((VarExprent) expr).equals(varpaar)) { - found = true; - break; + // The exception is in a var, so we need to look for ` = `, and then a `throw ` + if (exprent instanceof AssignmentExprent assExpr && + assExpr.getRight() instanceof VarExprent varExprent && + varExprent.getVarVersionPair().equals(varPair)) { + + Exprent next = null; + if (i != node.exprents.size() - 1) { + next = node.exprents.get(i + 1); + } else if (node.getSuccessors(DirectEdgeType.REGULAR).size() == 1) { + // TODO: make a test case that uses this. I don't feel like later code considers this scenario correctly + DirectNode nd = node.getSuccessors(DirectEdgeType.REGULAR).get(0).getDestination(); + if (!nd.exprents.isEmpty()) { + next = nd.exprents.get(0); } } - if (found) { - found = false; - if (exprent instanceof ExitExprent) { - ExitExprent exexpr = (ExitExprent) exprent; - if (exexpr.getExitType() == ExitExprent.Type.THROW && exexpr.getValue() instanceof VarExprent) { - found = true; - } - } - if (!found) { - return null; - } else { - isTrueExit = true; - } - } - } else if (firstcode == 2) { - // search for a load instruction - if (exprent instanceof AssignmentExprent) { - AssignmentExprent assexpr = (AssignmentExprent) exprent; - if (assexpr.getRight() instanceof VarExprent && - new VarVersionPair((VarExprent) assexpr.getRight()).equals(varpaar)) { - - Exprent next = null; - if (i == node.exprents.size() - 1) { - if (node.getSuccessors(DirectEdgeType.REGULAR).size() == 1) { - DirectNode nd = node.getSuccessors(DirectEdgeType.REGULAR).get(0).getDestination(); - if (!nd.exprents.isEmpty()) { - next = nd.exprents.get(0); - } - } - } else { - next = node.exprents.get(i + 1); - } - - boolean found = false; - if (next != null && next instanceof ExitExprent) { - ExitExprent exexpr = (ExitExprent) next; - if (exexpr.getExitType() == ExitExprent.Type.THROW && exexpr.getValue() instanceof VarExprent - && assexpr.getLeft().equals(exexpr.getValue())) { - found = true; - } - } - - if (!found) { - return null; - } else { - isTrueExit = true; - } - } + if (next instanceof ExitExprent exExpr && + exExpr.getExitType() == ExitExprent.Type.THROW && + exExpr.getValue() instanceof VarExprent && + assExpr.getLeft().equals(exExpr.getValue())) { + // found normal exit + yield ExitType.IMPLICIT_EXIT; + } else { + // found illegal usage of exception var. + yield null; } } - } - } - // find finally exits - if (blockStatement != null && blockStatement.getBlock() != null) { - Statement handler = fstat.getHandler(); - for (StatEdge edge : blockStatement.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) { - if (edge.getType() != StatEdge.TYPE_REGULAR && handler.containsStatement(blockStatement) - && !handler.containsStatement(edge.getDestination())) { - Boolean existingFlag = mapLast.get(blockStatement.getBlock()); - // note: the dummy node is also processed! - if (existingFlag == null || !existingFlag) { - mapLast.put(blockStatement.getBlock(), isTrueExit); - break; - } + if (exprent instanceof ExitExprent) { + // We found a method exit + yield ExitType.METHOD_EXIT; } } + yield ExitType.EXPLICIT_EXIT; } + case OTHER -> { + // Skip the `var10000 = varx` statement on the entry block + int startIdx = firstBlockStatement == node.block ? 1 : 0; - for (DirectEdge suc : node.getSuccessors(DirectEdgeType.REGULAR)) { - stack.add(suc.getDestination()); - } - } - - // empty finally block? - if (fstat.getHandler() instanceof BasicBlockStatement) { + for (int i = startIdx; i < node.exprents.size(); i++) { + Exprent exprent = node.exprents.get(i); - boolean isEmpty = false; - boolean isFirstLast = mapLast.containsKey(firstBasicBlock); - InstructionSequence seq = firstBasicBlock.getSeq(); + if (exprent instanceof ExitExprent exExpr && + exExpr.getExitType() == ExitExprent.Type.THROW && + exExpr.getValue() instanceof VarExprent varExpr && + varExpr.getVarVersionPair().equals(varPair)) { + // Found `throw ` + yield ExitType.IMPLICIT_EXIT; + } - switch (firstcode) { - case 0: - isEmpty = isFirstLast && seq.length() == 1; - break; - case 1: - isEmpty = seq.length() == 1; - break; - case 2: - isEmpty = isFirstLast ? seq.length() == 3 : seq.length() == 1; - } + for (VarVersionPair exprVar : exprent.getAllVariables()) { + if (exprVar.equals(varPair)) { + // Illegal usage of containing exception + yield null; + } + } - if (isEmpty) { - firstcode = 3; + if (exprent instanceof ExitExprent) { + // We found a method exit + yield ExitType.METHOD_EXIT; + } + } + yield ExitType.EXPLICIT_EXIT; } - } - - return new Record(firstcode, instrFirst.startOffset, mapLast); + }; } - private static void insertSemaphore(ControlFlowGraph graph, - Set setTry, - BasicBlock head, - BasicBlock handler, - int var, - Record information, - BytecodeVersion bytecode_version) { + private static void insertSemaphore( + ControlFlowGraph graph, + Set setTry, + BasicBlock head, + BasicBlock handler, + int var, + Record information, + BytecodeVersion bytecode_version) { Set setCopy = new HashSet<>(setTry); - int finallytype = information.firstCode; - Map mapLast = information.mapLast; + FinallyType finallytype = information.finallyType; + Map mapLast = information.mapLast(); // first and last statements removeExceptionInstructionsEx(handler, 1, finallytype); - for (Entry entry : mapLast.entrySet()) { + for (Entry entry : mapLast.entrySet()) { BasicBlock last = entry.getKey(); - if (entry.getValue()) { + if (entry.getValue() == ExitType.IMPLICIT_EXIT) { removeExceptionInstructionsEx(last, 2, finallytype); graph.getFinallyExits().add(last); } @@ -429,35 +460,35 @@ private static void insertSemaphore(ControlFlowGraph graph, } } - private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) { + private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldBlock, BasicBlock newBlock) { List lstTemp = new ArrayList<>(); - lstTemp.addAll(oldblock.getPreds()); - lstTemp.addAll(oldblock.getPredExceptions()); + lstTemp.addAll(oldBlock.getPreds()); + lstTemp.addAll(oldBlock.getPredExceptions()); // replace predecessors for (BasicBlock pred : lstTemp) { - pred.replaceSuccessor(oldblock, newblock); + pred.replaceSuccessor(oldBlock, newBlock); } // copy exception edges and extend protected ranges - for (BasicBlock hd : oldblock.getSuccExceptions()) { - newblock.addSuccessorException(hd); + for (BasicBlock hd : oldBlock.getSuccExceptions()) { + newBlock.addSuccessorException(hd); - ExceptionRangeCFG range = graph.getExceptionRange(hd, oldblock); - range.getProtectedRange().add(newblock); + ExceptionRangeCFG range = graph.getExceptionRange(hd, oldBlock); + range.getProtectedRange().add(newBlock); } // replace handler for (ExceptionRangeCFG range : graph.getExceptions()) { - if (range.getHandler() == oldblock) { - range.setHandler(newblock); + if (range.getHandler() == oldBlock) { + range.setHandler(newBlock); } } - newblock.addSuccessor(oldblock); - graph.getBlocks().addWithKey(newblock, newblock.id); - if (graph.getFirst() == oldblock) { - graph.setFirst(newblock); + newBlock.addSuccessor(oldBlock); + graph.getBlocks().addWithKey(newBlock, newBlock.id); + if (graph.getFirst() == oldBlock) { + graph.setFirst(newBlock); } } @@ -491,13 +522,13 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Set tryBlocks = getAllBasicBlocks(fstat.getFirst()); Set catchBlocks = getAllBasicBlocks(fstat.getHandler()); - int finallytype = information.firstCode; - Map mapLast = information.mapLast; + FinallyType finallytype = information.finallyType; + Map mapLast = information.mapLast(); BasicBlock first = fstat.getHandler().getBasichead().getBlock(); boolean skippedFirst = false; - if (finallytype == 3) { + if (finallytype == FinallyType.EMPTY) { // empty finally removeExceptionInstructionsEx(first, 3, finallytype); @@ -506,13 +537,14 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, } return true; - } else { - if (first.getSeq().length() == 1 && finallytype > 0) { - BasicBlock firstsuc = first.getSuccs().get(0); - if (catchBlocks.contains(firstsuc)) { - first = firstsuc; - skippedFirst = true; - } + } + + if (first.getSeq().length() == 1 && finallytype != FinallyType.OTHER) { + BasicBlock firstsuc = first.getSuccs().get(0); + if (catchBlocks.contains(firstsuc)) { + // Check if the first block is just a ` = ` assignment. + first = firstsuc; + skippedFirst = true; } } @@ -530,7 +562,7 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Set sideExits = null; for (BasicBlock start : startBlocks) { - Area arr = this.compareSubgraphsEx(graph, start, catchBlocks, first, finallytype, mapLast, skippedFirst); + @Nullable Area arr = this.compareSubgraphsEx(graph, start, catchBlocks, first, finallytype, mapLast, skippedFirst); if (arr == null) { return false; } @@ -544,25 +576,17 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, } } - // try { - // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true); - // } catch(Exception ex){ex.printStackTrace();} - // delete areas for (Area area : lstAreas) { deleteArea(graph, area); } - // try { - // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true); - // } catch(Exception ex){ex.printStackTrace();} - // INFO: empty basic blocks may remain in the graph! BasicBlock trueExit = null; - for (Entry entry : mapLast.entrySet()) { + for (Entry entry : mapLast.entrySet()) { BasicBlock last = entry.getKey(); - if (entry.getValue()) { + if (entry.getValue() == ExitType.IMPLICIT_EXIT) { removeExceptionInstructionsEx(last, 2, finallytype); graph.getFinallyExits().add(last); ValidationHelper.validateTrue(trueExit == null, "More than one true exit"); @@ -575,38 +599,22 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, return true; } - private static final class Area { - private final BasicBlock start; - private final Set sample; - private final BasicBlock next; // True exit - private final Set sideExits; - - private Area(BasicBlock start, Set sample, BasicBlock next, Set sideExits) { - this.start = start; - this.sample = sample; - this.next = next; - this.sideExits = sideExits; - } - } - - private Area compareSubgraphsEx(ControlFlowGraph graph, - BasicBlock startSample, - Set catchBlocks, - BasicBlock startCatch, - int finallytype, - Map mapLast, - boolean skippedFirst) { - class BlockStackEntry { - public final BasicBlock blockCatch; - public final BasicBlock blockSample; - + private @Nullable Area compareSubgraphsEx( + ControlFlowGraph graph, + BasicBlock startSample, + Set catchBlocks, + BasicBlock startCatch, + FinallyType finallytype, + Map mapLast, + boolean skippedFirst) { + + record BlockStackEntry( + BasicBlock blockCatch, + BasicBlock blockSample, // TODO: correct handling (merging) of multiple paths - public final List lstStoreVars; - - BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List lstStoreVars) { - this.blockCatch = blockCatch; - this.blockSample = blockSample; - this.lstStoreVars = new ArrayList<>(lstStoreVars); + List lstStoreVars) { + BlockStackEntry { + lstStoreVars = new ArrayList<>(lstStoreVars); } } @@ -614,7 +622,7 @@ class BlockStackEntry { Set setSample = new HashSet<>(); - Map mapNext = new HashMap<>(); + Map, FinallyExit> mapNext = new LinkedHashMap<>(); stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<>())); @@ -625,10 +633,15 @@ class BlockStackEntry { BasicBlock blockSample = entry.blockSample; boolean isFirstBlock = !skippedFirst && blockCatch == startCatch; - boolean isLastBlock = mapLast.containsKey(blockCatch); - boolean isTrueLastBlock = isLastBlock && mapLast.get(blockCatch); - - if (!this.compareBasicBlocksEx(graph, blockCatch, blockSample, (isFirstBlock ? 1 : 0) | (isTrueLastBlock ? 2 : 0), finallytype, + @Nullable ExitType exitType = mapLast.get(blockCatch); // null if not an exit + + if (!this.compareBasicBlocksEx( + graph, + blockCatch, + blockSample, + isFirstBlock, + mapLast.get(blockCatch) == ExitType.IMPLICIT_EXIT, + finallytype, entry.lstStoreVars)) { return null; } @@ -644,65 +657,53 @@ class BlockStackEntry { BasicBlock sucCatch = blockCatch.getSuccs().get(i); BasicBlock sucSample = blockSample.getSuccs().get(i); - if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) { - stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars)); + if (catchBlocks.contains(sucCatch)) { + if (!setSample.contains(sucSample)) { + stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars)); + } + } else { + if (exitType == ExitType.EXPLICIT_EXIT || exitType == ExitType.IMPLICIT_EXIT) { + mapNext.put(Pair.of(blockSample, sucSample), new FinallyExit(blockSample, sucSample, exitType)); + } } } // exception successors - if (isLastBlock && blockSample.getSeq().isEmpty()) { + if (exitType != null && blockSample.getSeq().isEmpty()) { // do nothing, blockSample will be removed anyway - } else { - if (blockCatch.getSuccExceptions().size() == blockSample.getSuccExceptions().size()) { - for (int i = 0; i < blockCatch.getSuccExceptions().size(); i++) { - BasicBlock sucCatch = blockCatch.getSuccExceptions().get(i); - BasicBlock sucSample = blockSample.getSuccExceptions().get(i); - - String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString(); - String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString(); - - // FIXME: compare handlers if possible - boolean equalexc = Objects.equals(excCatch, excSample); - - if (equalexc) { - if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) { - - List lst = entry.lstStoreVars; + continue; + } else if (blockCatch.getSuccExceptions().size() != blockSample.getSuccExceptions().size()) { + return null; + } - if (sucCatch.getSeq().length() > 0 && sucSample.getSeq().length() > 0) { - Instruction instrCatch = sucCatch.getSeq().getInstr(0); - Instruction instrSample = sucSample.getSeq().getInstr(0); + for (int i = 0; i < blockCatch.getSuccExceptions().size(); i++) { + BasicBlock sucCatch = blockCatch.getSuccExceptions().get(i); + BasicBlock sucSample = blockSample.getSuccExceptions().get(i); - if (instrCatch.opcode == CodeConstants.opc_astore && - instrSample.opcode == CodeConstants.opc_astore) { - lst = new ArrayList<>(lst); - lst.add(new int[]{instrCatch.operand(0), instrSample.operand(0)}); - } - } + String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString(); + String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString(); - stack.add(new BlockStackEntry(sucCatch, sucSample, lst)); - } - } else { - return null; - } - } - } else { + // FIXME: compare handlers if possible + if (!Objects.equals(excCatch, excSample)) { return null; } - } - if (isLastBlock) { - Set setSuccs = new HashSet<>(blockSample.getSuccs()); - setSuccs.removeAll(setSample); + if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) { + List lst = entry.lstStoreVars; - for (BlockStackEntry stackent : stack) { - setSuccs.remove(stackent.blockSample); - } + // Add variable mapping for catch vars? + if (!sucCatch.getSeq().isEmpty() && !sucSample.getSeq().isEmpty()) { + Instruction instrCatch = sucCatch.getSeq().getInstr(0); + Instruction instrSample = sucSample.getSeq().getInstr(0); - for (BasicBlock succ : setSuccs) { - if (graph.getLast() != succ) { // FIXME: why? - mapNext.put(blockSample.getId() + "#" + succ.getId(), new BasicBlock[]{blockSample, succ, isTrueLastBlock ? succ : null}); + if (instrCatch.opcode == CodeConstants.opc_astore && + instrSample.opcode == CodeConstants.opc_astore) { + lst = new ArrayList<>(lst); + lst.add(new int[]{instrCatch.operand(0), instrSample.operand(0)}); + } } + + stack.add(new BlockStackEntry(sucCatch, sucSample, lst)); } } } @@ -711,129 +712,122 @@ class BlockStackEntry { startSample, setSample, getUniqueNext(graph, new HashSet<>(mapNext.values())), - getSideExits(mapNext.values())); + getExplicitExits(mapNext.values())); } - private static Set getSideExits(Collection setNext) { + private static Set getExplicitExits(Collection setNext) { Set set = new HashSet<>(); - for (BasicBlock[] next : setNext) { - if (next[2] == null) { - set.add(next[1]); + for (FinallyExit next : setNext) { + if (next.type() == ExitType.EXPLICIT_EXIT) { + set.add(next.succ()); } } return set; } - private static BasicBlock getUniqueNext(ControlFlowGraph graph, Set setNext) { - // precondition: there is at most one true exit path in a finally statement + private static @Nullable BasicBlock getUniqueNext(ControlFlowGraph graph, Set setNext) { + // precondition: there is at most one true exit path in a "finally" statement BasicBlock next = null; boolean multiple = false; - for (BasicBlock[] arr : setNext) { + for (FinallyExit arr : setNext) { - if (arr[2] != null) { - next = arr[1]; - multiple = false; - break; - } else { - if (next == null) { - next = arr[1]; - } else if (next != arr[1]) { - multiple = true; - } + if (arr.type() == ExitType.IMPLICIT_EXIT) { + return arr.succ(); + } - if (arr[1].getPreds().size() == 1) { - next = arr[1]; - } + if (next == null) { + next = arr.succ(); + } else if (next != arr.succ()) { + multiple = true; + } + + if (arr.succ().getPreds().size() == 1) { + next = arr.succ(); } } - if (multiple) { // TODO: generic solution - for (BasicBlock[] arr : setNext) { - BasicBlock block = arr[1]; - - if (block != next) { - if (InterpreterUtil.equalSets(next.getSuccs(), block.getSuccs())) { - InstructionSequence seqNext = next.getSeq(); - InstructionSequence seqBlock = block.getSeq(); - - if (seqNext.length() == seqBlock.length()) { - for (int i = 0; i < seqNext.length(); i++) { - // TODO: can this be merged with the methods to check if instructions are equal? - Instruction instrNext = seqNext.getInstr(i); - Instruction instrBlock = seqBlock.getInstr(i); - - if (!Instruction.equals(instrNext, instrBlock)) { - return null; - } - for (int j = 0; j < instrNext.operandsCount(); j++) { - if (instrNext.operand(j) != instrBlock.operand(j)) { - return null; - } - } - } - } else { - return null; - } - } else { + if (!multiple) { + return next; + } + + // TODO: generic solution + for (FinallyExit arr : setNext) { + BasicBlock block = arr.succ(); + + if (block == next) { + continue; + } + + if (!InterpreterUtil.equalSets(next.getSuccs(), block.getSuccs())) { + return null; + } + + InstructionSequence seqNext = next.getSeq(); + InstructionSequence seqBlock = block.getSeq(); + + if (seqNext.length() != seqBlock.length()) { + return null; + } + for (int i = 0; i < seqNext.length(); i++) { + // TODO: can this be merged with the methods to check if instructions are equal? + Instruction instrNext = seqNext.getInstr(i); + Instruction instrBlock = seqBlock.getInstr(i); + + if (!Instruction.equals(instrNext, instrBlock)) { + return null; + } + for (int j = 0; j < instrNext.operandsCount(); j++) { + if (instrNext.operand(j) != instrBlock.operand(j)) { return null; } } } + } - // try { - // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true); - // } catch(IOException ex) { - // ex.printStackTrace(); - // } - - for (BasicBlock[] arr : setNext) { - if (arr[1] != next) { - // FIXME: exception edge possible? - arr[0].removeSuccessor(arr[1]); - arr[0].addSuccessor(next); - } + for (FinallyExit arr : setNext) { + if (arr.succ() != next) { + // FIXME: exception edge possible? + arr.source().removeSuccessor(arr.succ()); + arr.source().addSuccessor(next); } - - DeadCodeHelper.removeDeadBlocks(graph); } + DeadCodeHelper.removeDeadBlocks(graph); + return next; } - private boolean compareBasicBlocksEx(ControlFlowGraph graph, - BasicBlock pattern, - BasicBlock sample, - int type, - int finallytype, - List lstStoreVars) { + private boolean compareBasicBlocksEx( + ControlFlowGraph graph, + BasicBlock pattern, + BasicBlock sample, + boolean isFirstBlock, + boolean isTrueLastBlock, + FinallyType finallytype, + List lstStoreVars) { + InstructionSequence seqPattern = pattern.getSeq(); InstructionSequence seqSample = sample.getSeq(); - List instrOldOffsetsSample = sample.getInstrOldOffsets(); - if (type != 0) { - seqPattern = seqPattern.clone(); - - if ((type & 1) > 0) { // first - if (finallytype > 0) { - seqPattern.removeInstruction(0); - } + if (isFirstBlock) { // first + if (finallytype != FinallyType.OTHER) { + seqPattern = seqPattern.subSequence(1); // drop first instruction } + } - if ((type & 2) > 0) { // last - if (finallytype == 0 || finallytype == 2) { - seqPattern.removeLast(); - } - - if (finallytype == 2) { - seqPattern.removeLast(); - } + if (isTrueLastBlock) { // last + switch (finallytype) { + case OTHER -> seqPattern = seqPattern.subSequence(0, -1); // drop last + case STORE -> seqPattern = seqPattern.subSequence(0, -2); // drop last 2 // TODO: this is not always correct } } + // Sample is allowed to be longer, in that case it is split into 2 basic blocks. + // TODO: does this make sense for cases where the current block isn't an IMPLICIT_END (trueLastBlock)? if (seqPattern.length() > seqSample.length()) { return false; } @@ -842,103 +836,109 @@ private boolean compareBasicBlocksEx(ControlFlowGraph graph, Instruction instrPattern = seqPattern.getInstr(i); Instruction instrSample = seqSample.getInstr(i); - // compare instructions with respect to jumps + // compare instructions with respect to jumps and variables. if (!this.equalInstructions(instrPattern, instrSample, lstStoreVars)) { return false; } } if (seqPattern.length() < seqSample.length()) { // split in two blocks - InstructionSequence seq = new InstructionSequence(); - LinkedList oldOffsets = new LinkedList<>(); - for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) { - seq.addInstruction(0, seqSample.getInstr(i)); - oldOffsets.addFirst(sample.getOldOffset(i)); - seqSample.removeInstruction(i); - if (i < instrOldOffsetsSample.size()) { - instrOldOffsetsSample.remove(i); - } - } + splitBasicBlock(graph, sample, seqSample, seqPattern.length()); + } - BasicBlock newblock = new BasicBlock(++graph.last_id); - newblock.setSeq(seq); - newblock.getInstrOldOffsets().addAll(oldOffsets); + return true; + } - List lstTemp = new ArrayList<>(sample.getSuccs()); + private static void splitBasicBlock( + ControlFlowGraph graph, + BasicBlock block, + InstructionSequence seqSample, + int splitIndex) { - // move successors - for (BasicBlock suc : lstTemp) { - sample.removeSuccessor(suc); - newblock.addSuccessor(suc); - } + InstructionSequence seq = seqSample.split(splitIndex); + List oldOffsets = block.getInstrOldOffsets(); + List offsetSublist = oldOffsets.subList(Math.min(splitIndex, oldOffsets.size()), oldOffsets.size()); - sample.addSuccessor(newblock); + BasicBlock newBlock = new BasicBlock(++graph.last_id); + newBlock.setSeq(seq); + newBlock.getInstrOldOffsets().addAll(offsetSublist); + offsetSublist.clear(); // remove offsets from original block - graph.getBlocks().addWithKey(newblock, newblock.id); + List lstTemp = new ArrayList<>(block.getSuccs()); - Set setFinallyExits = graph.getFinallyExits(); - if (setFinallyExits.contains(sample)) { - setFinallyExits.remove(sample); - setFinallyExits.add(newblock); - } + // move successors + for (BasicBlock suc : lstTemp) { + block.removeSuccessor(suc); + newBlock.addSuccessor(suc); + } - // copy exception edges and extend protected ranges - for (int j = 0; j < sample.getSuccExceptions().size(); j++) { - BasicBlock hd = sample.getSuccExceptions().get(j); - newblock.addSuccessorException(hd); + block.addSuccessor(newBlock); - ExceptionRangeCFG range = graph.getExceptionRange(hd, sample); - range.getProtectedRange().add(newblock); - } + graph.getBlocks().addWithKey(newBlock, newBlock.id); + + Set setFinallyExits = graph.getFinallyExits(); + if (setFinallyExits.contains(block)) { + setFinallyExits.remove(block); + setFinallyExits.add(newBlock); } - return true; + // copy exception edges and extend protected ranges + for (int j = 0; j < block.getSuccExceptions().size(); j++) { + BasicBlock hd = block.getSuccExceptions().get(j); + newBlock.addSuccessorException(hd); + + ExceptionRangeCFG range = graph.getExceptionRange(hd, block); + range.getProtectedRange().add(newBlock); + } } public boolean equalInstructions(Instruction first, Instruction second, List lstStoreVars) { + ValidationHelper.notNull(this.instrRewrites); + ValidationHelper.notNull(this.ssuversions); if (!Instruction.equals(first, second)) { return false; } - if (first.group != CodeConstants.GROUP_JUMP && first.group != CodeConstants.GROUP_SWITCH) { // FIXME: switch comparison - // NOTE: seems like just checking group_switch works? Why does the above comment have a fix me? - - for (int i = 0; i < first.operandsCount(); i++) { - int firstOp = first.operand(i); - int secondOp = second.operand(i); - if (firstOp != secondOp) { - // a-load/store instructions - if (first.opcode == CodeConstants.opc_aload) { - for (int[] arr : lstStoreVars) { - if (arr[0] == firstOp && arr[1] == secondOp) { - return true; - } - } - } else if (first.opcode == CodeConstants.opc_astore) { - lstStoreVars.add(new int[]{firstOp, secondOp}); - return true; - } - - boolean ok = false; - if (isOpcVar(first.opcode)) { - // Find rewritten variables - if (this.instrRewrites.containsKey(first)) { - firstOp = this.instrRewrites.get(first); - } - if (this.instrRewrites.containsKey(second)) { - secondOp = this.instrRewrites.get(second); - } + if (first.group == CodeConstants.GROUP_JUMP || first.group == CodeConstants.GROUP_SWITCH) { + // FIXME: switch comparison + return true; + } - if (this.ssuversions.areVarsAnalogous(firstOp, secondOp)) { - ok = true; + for (int i = 0; i < first.operandsCount(); i++) { + int firstOp = first.operand(i); + int secondOp = second.operand(i); + if (firstOp != secondOp) { + // a-load/store instructions + if (first.opcode == CodeConstants.opc_aload) { + for (int[] arr : lstStoreVars) { + if (arr[0] == firstOp && arr[1] == secondOp) { + return true; } + } + } else if (first.opcode == CodeConstants.opc_astore) { + lstStoreVars.add(new int[]{firstOp, secondOp}); + return true; + } - // TODO: validate direct assignments + boolean ok = false; + if (isOpcVar(first.opcode)) { + // Find rewritten variables + if (this.instrRewrites.containsKey(first)) { + firstOp = this.instrRewrites.get(first); + } + if (this.instrRewrites.containsKey(second)) { + secondOp = this.instrRewrites.get(second); } - if (!ok) { - return false; + if (this.ssuversions.areVarsAnalogous(firstOp, secondOp)) { + ok = true; } + + // TODO: validate direct assignments + } + + if (!ok) { + return false; } } } @@ -1042,30 +1042,30 @@ private static void deleteArea(ControlFlowGraph graph, Area area) { } } - private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) { + private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, FinallyType finallytype) { InstructionSequence seq = block.getSeq(); List instrOldOffsets = block.getInstrOldOffsets(); - if (finallytype == 3) { // empty finally handler + if (finallytype == FinallyType.EMPTY) { // empty finally handler for (int i = seq.length() - 1; i >= 0; i--) { seq.removeInstruction(i); instrOldOffsets.remove(i); } } else { if ((blocktype & 1) > 0) { // first - if (finallytype == 2 || finallytype == 1) { // astore or pop + if (finallytype == FinallyType.STORE || finallytype == FinallyType.DROP) { // astore or pop seq.removeInstruction(0); instrOldOffsets.remove(0); } } if ((blocktype & 2) > 0) { // last - if (finallytype == 2 || finallytype == 0) { + if (finallytype == FinallyType.STORE || finallytype == FinallyType.DROP) { // astore or pop seq.removeLast(); instrOldOffsets.remove(instrOldOffsets.size() - 1); } - if (finallytype == 2) { // astore + if (finallytype == FinallyType.STORE) { // astore seq.removeLast(); instrOldOffsets.remove(instrOldOffsets.size() - 1); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java index 2499f5e9a6..1ea15a69d0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -947,7 +947,8 @@ public List getVarDefinitions() { return varDefinitions; } - // The exprents stored in the body, only nonnull for BasicBlockStatements. To find other exprents, use getStatExprents. + // The exprents stored in the body, only nonnull for BasicBlockStatements, but only if exprents have been generated. + // To find other exprents, use getStatExprents. public @Nullable List getExprents() { return exprents; } From a712f4c93068f73166200630a55f710846b85a34 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Fri, 5 Jun 2026 01:41:24 +0200 Subject: [PATCH 14/29] Add groovy tests --- .../java/decompiler/SingleClassesTest.java | 9 + .../pkg/TestGroovyFinallyBlockVariableUse.dec | 645 +++++++ .../results/pkg/TestGroovyFinallyThrow.dec | 395 ++++ .../results/pkg/TestGroovyFinallyVarDef.dec | 253 +++ .../results/pkg/TestGroovyTryCatchFinally.dec | 792 ++++++++ testData/results/pkg/TestGroovyTryFinally.dec | 589 ++++++ .../pkg/TestGroovyTryLoopReturnFinally.dec | 275 +++ .../pkg/TestGroovyTryLoopSimpleFinally.dec | 686 +++++++ testData/results/pkg/TestGroovyTryReturn.dec | 1696 +++++++++++++++++ testData/results/pkg/TestGroovyTrySplit.dec | 406 ++++ .../TestGroovyFinallyBlockVariableUse.groovy | 33 + .../groovy/pkg/TestGroovyFinallyThrow.groovy | 45 + .../groovy/pkg/TestGroovyFinallyVarDef.groovy | 25 + .../pkg/TestGroovyTryCatchFinally.groovy | 65 + .../groovy/pkg/TestGroovyTryFinally.groovy | 36 + .../pkg/TestGroovyTryLoopReturnFinally.groovy | 21 + .../pkg/TestGroovyTryLoopSimpleFinally.groovy | 37 + .../src/groovy/pkg/TestGroovyTryReturn.groovy | 222 +++ .../src/groovy/pkg/TestGroovyTrySplit.groovy | 51 + 19 files changed, 6281 insertions(+) create mode 100644 testData/results/pkg/TestGroovyFinallyBlockVariableUse.dec create mode 100644 testData/results/pkg/TestGroovyFinallyThrow.dec create mode 100644 testData/results/pkg/TestGroovyFinallyVarDef.dec create mode 100644 testData/results/pkg/TestGroovyTryCatchFinally.dec create mode 100644 testData/results/pkg/TestGroovyTryFinally.dec create mode 100644 testData/results/pkg/TestGroovyTryLoopReturnFinally.dec create mode 100644 testData/results/pkg/TestGroovyTryLoopSimpleFinally.dec create mode 100644 testData/results/pkg/TestGroovyTryReturn.dec create mode 100644 testData/results/pkg/TestGroovyTrySplit.dec create mode 100644 testData/src/groovy/pkg/TestGroovyFinallyBlockVariableUse.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyFinallyThrow.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyFinallyVarDef.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTryCatchFinally.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTryFinally.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTryLoopReturnFinally.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTryLoopSimpleFinally.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTryReturn.groovy create mode 100644 testData/src/groovy/pkg/TestGroovyTrySplit.groovy diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 142f503711..44884dd4b6 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -290,8 +290,17 @@ private void registerDefault() { register(JAVA_8, "TestInUse"); register(GROOVY, "TestGroovyClass"); + register(GROOVY, "TestGroovyFinallyBlockVariableUse"); + register(GROOVY, "TestGroovyFinallyThrow"); + register(GROOVY, "TestGroovyFinallyVarDef"); register(GROOVY, "TestGroovyTrait"); register(GROOVY, "TestGroovyTryCatch"); + register(GROOVY, "TestGroovyTryCatchFinally"); + register(GROOVY, "TestGroovyTryFinally"); + register(GROOVY, "TestGroovyTryLoopReturnFinally"); + register(GROOVY, "TestGroovyTryLoopSimpleFinally"); + register(GROOVY, "TestGroovyTryReturn"); + register(GROOVY, "TestGroovyTrySplit"); register(JAVA_8, "TestPrivateClasses"); register(KOTLIN, "TestSuspendLambdaKt"); register(KOTLIN, "TestRunSuspend"); diff --git a/testData/results/pkg/TestGroovyFinallyBlockVariableUse.dec b/testData/results/pkg/TestGroovyFinallyBlockVariableUse.dec new file mode 100644 index 0000000000..db1442c2d0 --- /dev/null +++ b/testData/results/pkg/TestGroovyFinallyBlockVariableUse.dec @@ -0,0 +1,645 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.BytecodeInterface8; +import org.codehaus.groovy.runtime.callsite.CallSite; +import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; + +public class TestGroovyFinallyBlockVariableUse implements GroovyObject { + @Generated + public TestGroovyFinallyBlockVariableUse() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public int test(String param1, int param2, int param3) { + // $VF: Couldn't be decompiled + // Bytecode: + // 000: nop + // 001: invokestatic pkg/TestGroovyFinallyBlockVariableUse.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 004: astore 4 + // 006: aload 4 + // 008: ldc 0 + // 00a: aaload + // 00b: aload 4 + // 00d: ldc 1 + // 00f: aaload + // 010: ldc java/lang/System + // 012: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 017: ldc "a" + // 019: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 01e: pop + // 01f: aload 4 + // 021: ldc 2 + // 023: aaload + // 024: aload 4 + // 026: ldc 3 + // 028: aaload + // 029: ldc java/lang/System + // 02b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 030: ldc "b" + // 032: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 037: pop + // 038: aload 4 + // 03a: ldc 4 + // 03c: aaload + // 03d: aload 4 + // 03f: ldc 5 + // 041: aaload + // 042: ldc java/lang/Integer + // 044: aload 1 + // 045: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 04a: iload 3 + // 04b: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 04e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 053: astore 5 + // 055: aload 5 + // 057: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.intUnbox (Ljava/lang/Object;)I + // 05a: istore 2 + // 05b: aload 5 + // 05d: pop + // 05e: iload 2 + // 05f: istore 6 + // 061: nop + // 062: nop + // 063: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigInt ()Z + // 066: ifeq 07e + // 069: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ ()Z + // 06c: ifeq 07e + // 06f: getstatic pkg/TestGroovyFinallyBlockVariableUse.__$stMC Z + // 072: ifne 07e + // 075: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass ()Z + // 078: ifne 07e + // 07b: goto 0d3 + // 07e: aload 4 + // 080: ldc 6 + // 082: aaload + // 083: iload 2 + // 084: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 087: iload 3 + // 088: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 08b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 090: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.intUnbox (Ljava/lang/Object;)I + // 093: istore 7 + // 095: iload 7 + // 097: pop + // 098: iload 7 + // 09a: bipush 0 + // 09b: if_icmple 0a2 + // 09e: bipush 1 + // 09f: goto 0a3 + // 0a2: bipush 0 + // 0a3: ifeq 0d0 + // 0a6: aload 4 + // 0a8: ldc 7 + // 0aa: aaload + // 0ab: aload 0 + // 0ac: bipush 4 + // 0ad: anewarray 4 + // 0b0: dup + // 0b1: bipush 0 + // 0b2: iload 7 + // 0b4: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 0b7: aastore + // 0b8: dup + // 0b9: bipush 1 + // 0ba: aload 1 + // 0bb: aastore + // 0bc: dup + // 0bd: bipush 2 + // 0be: iload 2 + // 0bf: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 0c2: aastore + // 0c3: dup + // 0c4: bipush 3 + // 0c5: iload 3 + // 0c6: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 0c9: aastore + // 0ca: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callCurrent (Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0cf: pop + // 0d0: goto 10e + // 0d3: iload 2 + // 0d4: iload 3 + // 0d5: isub + // 0d6: istore 8 + // 0d8: iload 8 + // 0da: pop + // 0db: iload 8 + // 0dd: bipush 0 + // 0de: if_icmple 0e5 + // 0e1: bipush 1 + // 0e2: goto 0e6 + // 0e5: bipush 0 + // 0e6: ifeq 10e + // 0e9: aload 0 + // 0eb: bipush 4 + // 0ec: anewarray 4 + // 0ef: dup + // 0f0: bipush 0 + // 0f1: iload 8 + // 0f3: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 0f6: aastore + // 0f7: dup + // 0f8: bipush 1 + // 0f9: aload 1 + // 0fa: aastore + // 0fb: dup + // 0fc: bipush 2 + // 0fd: iload 2 + // 0fe: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 101: aastore + // 102: dup + // 103: bipush 3 + // 104: iload 3 + // 105: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 108: aastore + // 109: invokespecial pkg/TestGroovyFinallyBlockVariableUse.accept ([Ljava/lang/Object;)V + // 10c: aconst_null + // 10d: pop + // 10e: nop + // 10f: iload 6 + // 111: ireturn + // 112: nop + // 113: nop + // 114: athrow + // 115: astore 9 + // 117: iload 3 + // 118: istore 10 + // 11a: iload 10 + // 11c: istore 2 + // 11d: iload 10 + // 11f: pop + // 120: aload 9 + // 122: checkcast java/lang/Throwable + // 125: athrow + // 126: athrow + // 127: nop + // 128: nop + // 129: athrow + // 12a: nop + // 12b: nop + // 12c: athrow + // 12d: astore 11 + // 12f: aload 11 + // 131: athrow + // 132: nop + // 133: nop + // 134: athrow + // 135: nop + // 136: nop + // 137: nop + // 138: nop + // 139: nop + // 13a: athrow + // 13b: nop + // 13c: nop + // 13d: nop + // 13e: nop + // 13f: nop + // 140: athrow + // 141: nop + // 142: nop + // 143: nop + // 144: nop + // 145: nop + // 146: athrow + // 147: nop + // 148: nop + // 149: nop + // 14a: nop + // 14b: nop + // 14c: athrow + // 14d: nop + // 14e: nop + // 14f: athrow + // 150: nop + // 151: nop + // 152: nop + // 153: nop + // 154: nop + // 155: nop + // 156: nop + // 157: nop + // 158: nop + // 159: nop + // 15a: nop + // 15b: nop + // 15c: nop + // 15d: nop + // 15e: nop + // 15f: nop + // 160: nop + // 161: nop + // 162: nop + // 163: nop + // 164: nop + // 165: nop + // 166: athrow + // 167: nop + // 168: nop + // 169: athrow + // 16a: nop + // 16b: nop + // 16c: nop + // 16d: nop + // 16e: nop + // 16f: athrow + // 170: nop + // 171: nop + // 172: nop + // 173: athrow + // 174: athrow + // 175: nop + // 176: nop + // 177: athrow + // 178: nop + // 179: nop + // 17a: nop + // 17b: nop + // 17c: nop + // 17d: nop + // 17e: nop + // 17f: nop + // 180: nop + // 181: nop + // 182: nop + // 183: nop + // 184: nop + // 185: nop + // 186: nop + // 187: nop + // 188: nop + // 189: nop + // 18a: nop + // 18b: nop + // 18c: nop + // 18d: nop + // 18e: nop + // 18f: nop + // 190: nop + // 191: nop + // 192: nop + // 193: nop + // 194: nop + // 195: nop + // 196: nop + // 197: nop + // 198: nop + // 199: nop + // 19a: nop + // 19b: nop + // 19c: nop + // 19d: nop + // 19e: nop + // 19f: nop + // 1a0: nop + // 1a1: athrow + // 1a2: nop + // 1a3: nop + // 1a4: athrow + // 1a5: nop + // 1a6: nop + // 1a7: nop + // 1a8: nop + // 1a9: athrow + // 1aa: nop + // 1ab: nop + // 1ac: athrow + // 1ad: nop + // 1ae: nop + // 1af: nop + // 1b0: nop + // 1b1: nop + // 1b2: athrow + // 1b3: nop + // 1b4: nop + // 1b5: nop + // 1b6: athrow + // 1b7: athrow + // 1b8: nop + // 1b9: nop + // 1ba: athrow + // 1bb: nop + // 1bc: nop + // 1bd: nop + // 1be: nop + // 1bf: nop + // 1c0: nop + // 1c1: nop + // 1c2: nop + // 1c3: nop + // 1c4: nop + // 1c5: nop + // 1c6: nop + // 1c7: nop + // 1c8: nop + // 1c9: nop + // 1ca: nop + // 1cb: nop + // 1cc: nop + // 1cd: nop + // 1ce: nop + // 1cf: nop + // 1d0: nop + // 1d1: nop + // 1d2: nop + // 1d3: nop + // 1d4: nop + // 1d5: nop + // 1d6: nop + // 1d7: nop + // 1d8: nop + // 1d9: nop + // 1da: nop + // 1db: nop + // 1dc: nop + // 1dd: nop + // 1de: nop + // 1df: athrow + // 1e0: nop + // 1e1: nop + // 1e2: athrow + // 1e3: astore 14 + // 1e5: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigInt ()Z + // 1e8: ifeq 200 + // 1eb: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ ()Z + // 1ee: ifeq 200 + // 1f1: getstatic pkg/TestGroovyFinallyBlockVariableUse.__$stMC Z + // 1f4: ifne 200 + // 1f7: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass ()Z + // 1fa: ifne 200 + // 1fd: goto 255 + // 200: aload 4 + // 202: ldc 10 + // 204: aaload + // 205: iload 2 + // 206: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 209: iload 3 + // 20a: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 20d: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 212: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.intUnbox (Ljava/lang/Object;)I + // 215: istore 15 + // 217: iload 15 + // 219: pop + // 21a: iload 15 + // 21c: bipush 0 + // 21d: if_icmple 224 + // 220: bipush 1 + // 221: goto 225 + // 224: bipush 0 + // 225: ifeq 252 + // 228: aload 4 + // 22a: ldc 11 + // 22c: aaload + // 22d: aload 0 + // 22e: bipush 4 + // 22f: anewarray 4 + // 232: dup + // 233: bipush 0 + // 234: iload 15 + // 236: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 239: aastore + // 23a: dup + // 23b: bipush 1 + // 23c: aload 1 + // 23d: aastore + // 23e: dup + // 23f: bipush 2 + // 240: iload 2 + // 241: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 244: aastore + // 245: dup + // 246: bipush 3 + // 247: iload 3 + // 248: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 24b: aastore + // 24c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callCurrent (Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 251: pop + // 252: goto 290 + // 255: iload 2 + // 256: iload 3 + // 257: isub + // 258: istore 16 + // 25a: iload 16 + // 25c: pop + // 25d: iload 16 + // 25f: bipush 0 + // 260: if_icmple 267 + // 263: bipush 1 + // 264: goto 268 + // 267: bipush 0 + // 268: ifeq 290 + // 26b: aload 0 + // 26d: bipush 4 + // 26e: anewarray 4 + // 271: dup + // 272: bipush 0 + // 273: iload 16 + // 275: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 278: aastore + // 279: dup + // 27a: bipush 1 + // 27b: aload 1 + // 27c: aastore + // 27d: dup + // 27e: bipush 2 + // 27f: iload 2 + // 280: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 283: aastore + // 284: dup + // 285: bipush 3 + // 286: iload 3 + // 287: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 28a: aastore + // 28b: invokespecial pkg/TestGroovyFinallyBlockVariableUse.accept ([Ljava/lang/Object;)V + // 28e: aconst_null + // 28f: pop + // 290: aload 14 + // 292: athrow + // 293: nop + // 294: nop + // 295: athrow + // try (25 -> 46): 147 java/lang/NumberFormatException + // try (142 -> 144): 147 java/lang/NumberFormatException + // try (25 -> 46): 164 null + // try (142 -> 144): 164 null + // try (147 -> 157): 164 null + // try (14 -> 47): 344 null + // try (142 -> 144): 344 null + // try (147 -> 157): 344 null + // try (164 -> 167): 344 null + } + + private boolean condition(int i) { + CallSite[] var2 = $getCallSiteArray(); + if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigZ() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + int var4 = i--;// 27 + return var4 > 0; + } else { + int var3 = i; + i = DefaultTypeTransformation.intUnbox(var2[12].call(i)); + return var3 > 0; + } + } + + private void accept(Object... args) { + CallSite[] var2 = $getCallSiteArray(); + }// 32 + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyFinallyBlockVariableUse' { + method ' ()V' { + 1 14 + 2 14 + 3 14 + 4 14 + 6 15 + 7 15 + 8 15 + 9 16 + a 16 + b 16 + c 16 + d 16 + e 17 + f 17 + 11 17 + 12 17 + 13 17 + 16 18 + } + + method 'condition (I)Z' { + 1 479 + 2 479 + 3 479 + 4 479 + 5 480 + 6 480 + 7 480 + 8 480 + 9 480 + a 480 + b 480 + c 480 + d 480 + e 480 + f 480 + 10 480 + 11 480 + 12 480 + 13 480 + 14 480 + 15 480 + 16 480 + 17 480 + 18 480 + 19 480 + 1a 480 + 1b 480 + 1c 480 + 20 484 + 22 484 + 23 485 + 24 485 + 25 485 + 26 485 + 28 485 + 29 485 + 2a 485 + 2b 485 + 2c 485 + 2d 485 + 2e 485 + 2f 485 + 31 485 + 32 485 + 33 485 + 34 485 + 36 486 + 37 486 + 38 486 + 39 486 + 3a 486 + 40 486 + 44 481 + 46 481 + 47 481 + 49 481 + 4d 482 + 4e 482 + 4f 482 + 50 482 + 51 482 + 52 482 + 58 482 + } + + method 'accept ([Ljava/lang/Object;)V' { + 1 491 + 2 491 + 3 491 + 4 491 + 5 492 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 498 + 1 498 + 2 498 + 3 498 + 5 498 + 6 498 + 7 498 + 8 499 + a 502 + c 502 + d 502 + e 502 + f 502 + 10 502 + 11 502 + 12 503 + 13 503 + 14 503 + 15 503 + 16 503 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 509 + 1 509 + 2 509 + 3 509 + 4 509 + 5 510 + } +} + +Lines mapping: +27 <-> 482 +32 <-> 493 diff --git a/testData/results/pkg/TestGroovyFinallyThrow.dec b/testData/results/pkg/TestGroovyFinallyThrow.dec new file mode 100644 index 0000000000..66de698e89 --- /dev/null +++ b/testData/results/pkg/TestGroovyFinallyThrow.dec @@ -0,0 +1,395 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.BytecodeInterface8; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyFinallyThrow implements GroovyObject { + @Generated + public TestGroovyFinallyThrow() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public void test(boolean param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyFinallyThrow.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 2 + // 05: aload 2 + // 06: ldc 0 + // 08: aaload + // 09: aload 2 + // 0a: ldc 1 + // 0c: aaload + // 0d: ldc java/lang/System + // 0f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 14: bipush 1 + // 15: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 18: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 1d: pop + // 1e: goto 21 + // 21: iload 1 + // 22: ifeq 41 + // 25: nop + // 26: aload 2 + // 27: ldc 2 + // 29: aaload + // 2a: aload 2 + // 2b: ldc 3 + // 2d: aaload + // 2e: ldc java/lang/System + // 30: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 35: bipush 2 + // 36: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 39: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 3e: pop + // 3f: nop + // 40: return + // 41: goto 4e + // 44: astore 3 + // 45: aload 3 + // 46: checkcast java/lang/Throwable + // 49: athrow + // 4a: athrow + // 4b: nop + // 4c: nop + // 4d: athrow + // 4e: aload 2 + // 4f: ldc 4 + // 51: aaload + // 52: aload 2 + // 53: ldc 5 + // 55: aaload + // 56: ldc java/lang/System + // 58: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 5d: bipush 2 + // 5e: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 61: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 66: pop + // 67: goto 88 + // 6a: astore 4 + // 6c: aload 2 + // 6d: ldc 6 + // 6f: aaload + // 70: aload 2 + // 71: ldc 7 + // 73: aaload + // 74: ldc java/lang/System + // 76: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 7b: bipush 2 + // 7c: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 7f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 84: pop + // 85: aload 4 + // 87: athrow + // 88: goto f9 + // 8b: astore 5 + // 8d: iload 1 + // 8e: ifeq ad + // 91: nop + // 92: aload 2 + // 93: ldc 8 + // 95: aaload + // 96: aload 2 + // 97: ldc 9 + // 99: aaload + // 9a: ldc java/lang/System + // 9c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // a1: bipush 2 + // a2: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // a5: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // aa: pop + // ab: nop + // ac: return + // ad: goto bc + // b0: astore 6 + // b2: aload 6 + // b4: checkcast java/lang/Throwable + // b7: athrow + // b8: athrow + // b9: nop + // ba: nop + // bb: athrow + // bc: aload 2 + // bd: ldc 10 + // bf: aaload + // c0: aload 2 + // c1: ldc 11 + // c3: aaload + // c4: ldc java/lang/System + // c6: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // cb: bipush 2 + // cc: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // cf: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // d4: pop + // d5: goto f6 + // d8: astore 7 + // da: aload 2 + // db: ldc 12 + // dd: aaload + // de: aload 2 + // df: ldc 13 + // e1: aaload + // e2: ldc java/lang/System + // e4: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // e9: bipush 2 + // ea: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // ed: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // f2: pop + // f3: aload 7 + // f5: athrow + // f6: aload 5 + // f8: athrow + // f9: goto 05 + // fc: athrow + // try (3 -> 16): 71 null + // try (16 -> 19): 34 java/lang/Exception + // try (32 -> 34): 34 java/lang/Exception + // try (16 -> 19): 55 null + // try (32 -> 34): 55 null + // try (34 -> 38): 55 null + // try (72 -> 75): 90 java/lang/Exception + // try (88 -> 90): 90 java/lang/Exception + // try (72 -> 75): 111 null + // try (88 -> 90): 111 null + // try (90 -> 94): 111 null + } + + public void test1(RuntimeException t) { + CallSite[] var2 = $getCallSiteArray(); + + try { + var2[14].call(var2[15].callGetProperty(System.class), 1);// 23 24 + } catch (Throwable e) {// 25 + var2[16].call(e);// 26 + } finally { + throw (Throwable)t;// 28 + } + } + + public void test2(RuntimeException t) { + CallSite[] var2 = $getCallSiteArray(); + + try { + var2[17].call(var2[18].callGetProperty(System.class), 1);// 34 35 + throw (Throwable)t;// 36 + } catch (Throwable e) {// 37 + var2[19].call(e);// 38 + } finally { + if (!__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) {// 39 + } + } + + throw (Throwable)t;// 43 + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyFinallyThrow' { + method ' ()V' { + 1 13 + 2 13 + 3 13 + 4 13 + 6 14 + 7 14 + 8 14 + 9 15 + a 15 + b 15 + c 15 + d 15 + e 16 + f 16 + 11 16 + 12 16 + 13 16 + 16 17 + } + + method 'test1 (Ljava/lang/RuntimeException;)V' { + 1 166 + 2 166 + 3 166 + 4 166 + 5 169 + 6 169 + 7 169 + 8 169 + 9 169 + a 169 + b 169 + c 169 + d 169 + e 169 + f 169 + 10 169 + 11 169 + 12 169 + 13 169 + 14 169 + 15 169 + 16 169 + 17 169 + 18 169 + 19 169 + 1a 169 + 1b 169 + 1c 169 + 21 170 + 22 171 + 23 171 + 24 171 + 25 171 + 26 171 + 27 171 + 28 171 + 29 171 + 2a 171 + 2b 171 + 3b 173 + 3c 173 + 3d 173 + 3e 173 + 3f 173 + } + + method 'test2 (Ljava/lang/RuntimeException;)V' { + 1 178 + 2 178 + 3 178 + 4 178 + 5 181 + 6 181 + 7 181 + 8 181 + 9 181 + a 181 + b 181 + c 181 + d 181 + e 181 + f 181 + 10 181 + 11 181 + 12 181 + 13 181 + 14 181 + 15 181 + 16 181 + 17 181 + 18 181 + 19 181 + 1a 181 + 1b 181 + 1c 181 + 1e 182 + 1f 182 + 20 182 + 21 182 + 22 182 + 26 183 + 27 184 + 28 184 + 29 184 + 2a 184 + 2b 184 + 2c 184 + 2d 184 + 2e 184 + 2f 184 + 30 184 + 4d 186 + 4e 186 + 4f 186 + 50 186 + 51 186 + 52 186 + 53 186 + 54 186 + 55 186 + 56 186 + 57 186 + 58 186 + 62 190 + 63 190 + 64 190 + 65 190 + 66 190 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 197 + 1 197 + 2 197 + 3 197 + 5 197 + 6 197 + 7 197 + 8 198 + a 201 + c 201 + d 201 + e 201 + f 201 + 10 201 + 11 201 + 12 202 + 13 202 + 14 202 + 15 202 + 16 202 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 208 + 1 208 + 2 208 + 3 208 + 4 208 + 5 209 + } +} + +Lines mapping: +23 <-> 170 +24 <-> 170 +25 <-> 171 +26 <-> 172 +28 <-> 174 +34 <-> 182 +35 <-> 182 +36 <-> 183 +37 <-> 184 +38 <-> 185 +39 <-> 187 +43 <-> 191 +Not mapped: +27 +29 +41 diff --git a/testData/results/pkg/TestGroovyFinallyVarDef.dec b/testData/results/pkg/TestGroovyFinallyVarDef.dec new file mode 100644 index 0000000000..0a666a307f --- /dev/null +++ b/testData/results/pkg/TestGroovyFinallyVarDef.dec @@ -0,0 +1,253 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyFinallyVarDef implements GroovyObject { + @Generated + public TestGroovyFinallyVarDef() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public void test1() { + CallSite[] var1 = $getCallSiteArray(); + int i = 0;// 5 + + try { + var1[0].call(var1[1].callGetProperty(System.class), "a");// 6 7 + } finally { + byte var5 = 5;// 9 + } + + var1[2].call(var1[3].callGetProperty(System.class), i);// 12 + } + + public void test2() { + CallSite[] var1 = $getCallSiteArray(); + int i = 2;// 16 + + try { + var1[4].call(var1[5].callGetProperty(System.class), "a");// 17 18 + } finally { + byte var5 = 5;// 20 + } + + var1[6].call(var1[7].callGetProperty(System.class), i);// 23 + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyFinallyVarDef' { + method ' ()V' { + 1 12 + 2 12 + 3 12 + 4 12 + 6 13 + 7 13 + 8 13 + 9 14 + a 14 + b 14 + c 14 + d 14 + e 15 + f 15 + 11 15 + 12 15 + 13 15 + 16 16 + } + + method 'test1 ()V' { + 1 19 + 2 19 + 3 19 + 4 19 + 5 20 + 6 20 + 7 20 + a 23 + b 23 + c 23 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 12 23 + 13 23 + 14 23 + 15 23 + 16 23 + 17 23 + 18 23 + 19 23 + 1a 23 + 1b 23 + 1c 23 + 1d 23 + 1e 23 + 1f 23 + 2f 25 + 30 25 + 31 25 + 3b 28 + 3c 28 + 3d 28 + 3e 28 + 3f 28 + 40 28 + 41 28 + 42 28 + 43 28 + 44 28 + 45 28 + 46 28 + 47 28 + 48 28 + 49 28 + 4a 28 + 4b 28 + 4c 28 + 4d 28 + 4e 28 + 4f 28 + 50 28 + 51 28 + 52 28 + 54 29 + } + + method 'test2 ()V' { + 1 32 + 2 32 + 3 32 + 4 32 + 5 33 + 6 33 + 9 36 + a 36 + b 36 + c 36 + d 36 + e 36 + f 36 + 10 36 + 11 36 + 12 36 + 13 36 + 14 36 + 15 36 + 16 36 + 17 36 + 18 36 + 19 36 + 1a 36 + 1b 36 + 1c 36 + 1d 36 + 1e 36 + 2e 38 + 2f 38 + 30 38 + 3a 41 + 3b 41 + 3c 41 + 3d 41 + 3e 41 + 3f 41 + 40 41 + 41 41 + 42 41 + 43 41 + 44 41 + 45 41 + 46 41 + 47 41 + 48 41 + 49 41 + 4a 41 + 4b 41 + 4c 41 + 4d 41 + 4e 41 + 4f 41 + 50 41 + 51 41 + 53 42 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 48 + 1 48 + 2 48 + 3 48 + 5 48 + 6 48 + 7 48 + 8 49 + a 52 + c 52 + d 52 + e 52 + f 52 + 10 52 + 11 52 + 12 53 + 13 53 + 14 53 + 15 53 + 16 53 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 59 + 1 59 + 2 59 + 3 59 + 4 59 + 5 60 + } +} + +Lines mapping: +5 <-> 21 +6 <-> 24 +7 <-> 24 +9 <-> 26 +12 <-> 29 +16 <-> 34 +17 <-> 37 +18 <-> 37 +20 <-> 39 +23 <-> 42 +Not mapped: +8 +10 +19 +21 diff --git a/testData/results/pkg/TestGroovyTryCatchFinally.dec b/testData/results/pkg/TestGroovyTryCatchFinally.dec new file mode 100644 index 0000000000..f54d072f22 --- /dev/null +++ b/testData/results/pkg/TestGroovyTryCatchFinally.dec @@ -0,0 +1,792 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.BytecodeInterface8; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyTryCatchFinally implements GroovyObject { + @Generated + public TestGroovyTryCatchFinally() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test1(String x) { + CallSite[] var2 = $getCallSiteArray(); + if (!__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + boolean var36 = false /* VF: Semaphore variable */; + + try { + var36 = true; + var2[8].call(var2[9].callGetProperty(System.class), "sout1");// 20 21 + var36 = false; + } catch (Exception e) { + try { + var2[10].call(var2[11].callGetProperty(System.class), "sout2");// 23 24 + } catch (Exception e2) { + } finally { + ; + } + + var36 = false; + } finally { + if (var36) { + var2[14].call(var2[15].callGetProperty(System.class), "finally");// 31 + } + } + + var2[12].call(var2[13].callGetProperty(System.class), "finally"); + } else { + boolean var19 = false /* VF: Semaphore variable */; + + try { + var19 = true; + var2[0].call(var2[1].callGetProperty(System.class), "sout1"); + var19 = false; + } catch (Exception e) { + try { + var2[2].call(var2[3].callGetProperty(System.class), "sout2"); + } catch (Exception e2) {// 25 + } finally { + ; + } + + var19 = false; + } finally { + if (var19) { + var2[6].call(var2[7].callGetProperty(System.class), "finally"); + } + } + + var2[4].call(var2[5].callGetProperty(System.class), "finally"); + } + }// 32 + + public int foo(int a) throws Exception { + CallSite[] var2 = $getCallSiteArray(); + if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigZ() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + if (a < 1) {// 36 + throw (Throwable)var2[18].callConstructor(RuntimeException.class);// 37 + } else if (a < 5) {// 38 + return a;// 39 + } else { + throw (Throwable)var2[19].callConstructor(Exception.class);// 42 + } + } else if (a < 1) { + throw (Throwable)var2[16].callConstructor(RuntimeException.class); + } else if (a < 5) { + return a; + } else { + throw (Throwable)var2[17].callConstructor(Exception.class); + } + } + + public int test(String param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryCatchFinally.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 2 + // 05: aload 2 + // 06: ldc 20 + // 08: aaload + // 09: ldc java/lang/Integer + // 0b: aload 1 + // 0c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 11: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.intUnbox (Ljava/lang/Object;)I + // 14: istore 3 + // 15: nop + // 16: aload 2 + // 17: ldc 21 + // 19: aaload + // 1a: aload 2 + // 1b: ldc 22 + // 1d: aaload + // 1e: ldc java/lang/System + // 20: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 25: ldc "Finally" + // 27: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 2c: pop + // 2d: nop + // 2e: iload 3 + // 2f: ireturn + // 30: nop + // 31: nop + // 32: athrow + // 33: astore 4 + // 35: aload 2 + // 36: ldc 23 + // 38: aaload + // 39: aload 2 + // 3a: ldc 24 + // 3c: aaload + // 3d: ldc java/lang/System + // 3f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 44: aload 2 + // 45: ldc 25 + // 47: aaload + // 48: ldc "Error" + // 4a: aload 4 + // 4c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 51: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 56: pop + // 57: nop + // 58: goto 5b + // 5b: aload 2 + // 5c: ldc 26 + // 5e: aaload + // 5f: aload 2 + // 60: ldc 27 + // 62: aaload + // 63: ldc java/lang/System + // 65: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 6a: ldc "Finally" + // 6c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 71: pop + // 72: goto 91 + // 75: astore 5 + // 77: aload 2 + // 78: ldc 28 + // 7a: aaload + // 7b: aload 2 + // 7c: ldc 29 + // 7e: aaload + // 7f: ldc java/lang/System + // 81: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 86: ldc "Finally" + // 88: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 8d: pop + // 8e: aload 5 + // 90: athrow + // 91: bipush -1 + // 93: invokestatic java/lang/Integer.valueOf (I)Ljava/lang/Integer; + // 96: invokevirtual java/lang/Integer.intValue ()I + // 99: ireturn + // try (3 -> 12): 29 java/lang/Exception + // try (24 -> 26): 29 java/lang/Exception + // try (3 -> 12): 60 null + // try (24 -> 26): 60 null + // try (29 -> 47): 60 null + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testEmptyCatch(String msg) { + CallSite[] var2 = $getCallSiteArray(); + if (!__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + boolean var16 = false /* VF: Semaphore variable */; + + try { + var16 = true; + var2[36].call(var2[37].callGetProperty(System.class), msg);// 58 59 + var16 = false; + } catch (RuntimeException ignored) { + var16 = false; + } finally { + if (var16) { + var2[40].call(var2[41].callGetProperty(System.class), "Bye");// 62 + } + } + + var2[38].call(var2[39].callGetProperty(System.class), "Bye"); + } else { + boolean var11 = false /* VF: Semaphore variable */; + + try { + var11 = true; + var2[30].call(var2[31].callGetProperty(System.class), msg); + var11 = false; + } catch (RuntimeException ignored) {// 60 + var11 = false; + } finally { + if (var11) { + var2[34].call(var2[35].callGetProperty(System.class), "Bye"); + } + } + + var2[32].call(var2[33].callGetProperty(System.class), "Bye"); + } + }// 63 + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyTryCatchFinally' { + method ' ()V' { + 1 13 + 2 13 + 3 13 + 4 13 + 6 14 + 7 14 + 8 14 + 9 15 + a 15 + b 15 + c 15 + d 15 + e 16 + f 16 + 11 16 + 12 16 + 13 16 + 16 17 + } + + method 'test1 (Ljava/lang/String;)V' { + 1 21 + 2 21 + 3 21 + 4 21 + 5 22 + 6 22 + 7 22 + 8 22 + 9 22 + a 22 + b 22 + c 22 + d 22 + e 22 + f 22 + 10 22 + 14 50 + 15 50 + 16 50 + 17 50 + 18 50 + 19 50 + 1a 50 + 1b 50 + 1c 50 + 1d 50 + 1e 50 + 1f 50 + 20 50 + 21 50 + 22 50 + 23 50 + 24 50 + 25 50 + 26 50 + 27 50 + 28 50 + 29 50 + 2f 54 + 30 54 + 31 54 + 32 54 + 33 54 + 34 54 + 35 54 + 36 54 + 37 54 + 38 54 + 39 54 + 3a 54 + 3b 54 + 3c 54 + 3d 54 + 3e 54 + 3f 54 + 40 54 + 41 54 + 42 54 + 43 54 + 44 54 + 49 55 + 5b 67 + 5c 67 + 5d 67 + 5e 67 + 5f 67 + 60 67 + 61 67 + 62 67 + 63 67 + 64 67 + 65 67 + 66 67 + 67 67 + 68 67 + 69 67 + 6a 67 + 6b 67 + 6c 67 + 6d 67 + 6e 67 + 6f 67 + 70 67 + 77 63 + 78 63 + 79 63 + 7a 63 + 7b 63 + 7c 63 + 7d 63 + 7e 63 + 7f 63 + 80 63 + 81 63 + 82 63 + 83 63 + 84 63 + 85 63 + 86 63 + 87 63 + 88 63 + 89 63 + 8a 63 + 8b 63 + 8c 63 + 94 27 + 95 27 + 96 27 + 97 27 + 98 27 + 99 27 + 9a 27 + 9b 27 + 9c 27 + 9d 27 + 9e 27 + 9f 27 + a0 27 + a1 27 + a2 27 + a3 27 + a4 27 + a5 27 + a6 27 + a7 27 + a8 27 + a9 27 + b0 31 + b1 31 + b2 31 + b3 31 + b4 31 + b5 31 + b6 31 + b7 31 + b8 31 + b9 31 + ba 31 + bb 31 + bc 31 + bd 31 + be 31 + bf 31 + c0 31 + c1 31 + c2 31 + c3 31 + c4 31 + c5 31 + ca 32 + dc 44 + dd 44 + de 44 + df 44 + e0 44 + e1 44 + e2 44 + e3 44 + e4 44 + e5 44 + e6 44 + e7 44 + e8 44 + e9 44 + ea 44 + eb 44 + ec 44 + ed 44 + ee 44 + ef 44 + f0 44 + f1 44 + f8 40 + f9 40 + fa 40 + fb 40 + fc 40 + fd 40 + fe 40 + ff 40 + 100 40 + 101 40 + 102 40 + 103 40 + 104 40 + 105 40 + 106 40 + 107 40 + 108 40 + 109 40 + 10a 40 + 10b 40 + 10c 40 + 10d 40 + 112 69 + } + + method 'foo (I)I' { + 1 72 + 2 72 + 3 72 + 4 72 + 5 73 + 6 73 + 7 73 + 8 73 + 9 73 + a 73 + b 73 + c 73 + d 73 + e 73 + f 73 + 10 73 + 11 73 + 12 73 + 13 73 + 14 73 + 15 73 + 16 73 + 17 73 + 18 73 + 19 73 + 1a 73 + 1b 73 + 1c 73 + 20 81 + 21 81 + 22 81 + 23 81 + 24 81 + 2a 81 + 2b 81 + 2c 81 + 2d 82 + 2e 82 + 2f 82 + 30 82 + 31 82 + 32 82 + 33 82 + 34 82 + 35 82 + 36 82 + 37 82 + 38 82 + 39 82 + 3a 82 + 3b 82 + 3f 83 + 40 83 + 41 83 + 42 83 + 43 83 + 49 83 + 4a 83 + 4b 83 + 4c 84 + 4d 84 + 51 86 + 52 86 + 53 86 + 54 86 + 55 86 + 56 86 + 57 86 + 58 86 + 59 86 + 5a 86 + 5b 86 + 5c 86 + 5d 86 + 5e 86 + 5f 86 + 63 74 + 64 74 + 65 74 + 66 74 + 67 74 + 6d 74 + 6e 74 + 6f 74 + 70 75 + 71 75 + 72 75 + 73 75 + 74 75 + 75 75 + 76 75 + 77 75 + 78 75 + 79 75 + 7a 75 + 7b 75 + 7c 75 + 7d 75 + 7e 75 + 82 76 + 83 76 + 84 76 + 85 76 + 86 76 + 8c 76 + 8d 76 + 8e 76 + 8f 77 + 90 77 + 94 79 + 95 79 + 96 79 + 97 79 + 98 79 + 99 79 + 9a 79 + 9b 79 + 9c 79 + 9d 79 + 9e 79 + 9f 79 + a0 79 + a1 79 + a2 79 + } + + method 'testEmptyCatch (Ljava/lang/String;)V' { + 1 180 + 2 180 + 3 180 + 4 180 + 5 181 + 6 181 + 7 181 + 8 181 + 9 181 + a 181 + b 181 + c 181 + d 181 + e 181 + f 181 + 10 181 + 14 202 + 15 202 + 16 202 + 17 202 + 18 202 + 19 202 + 1a 202 + 1b 202 + 1c 202 + 1d 202 + 1e 202 + 1f 202 + 20 202 + 21 202 + 22 202 + 23 202 + 24 202 + 25 202 + 26 202 + 27 202 + 28 202 + 2d 204 + 32 212 + 33 212 + 34 212 + 35 212 + 36 212 + 37 212 + 38 212 + 39 212 + 3a 212 + 3b 212 + 3c 212 + 3d 212 + 3e 212 + 3f 212 + 40 212 + 41 212 + 42 212 + 43 212 + 44 212 + 45 212 + 46 212 + 47 212 + 4e 208 + 4f 208 + 50 208 + 51 208 + 52 208 + 53 208 + 54 208 + 55 208 + 56 208 + 57 208 + 58 208 + 59 208 + 5a 208 + 5b 208 + 5c 208 + 5d 208 + 5e 208 + 5f 208 + 60 208 + 61 208 + 62 208 + 63 208 + 6b 186 + 6c 186 + 6d 186 + 6e 186 + 6f 186 + 70 186 + 71 186 + 72 186 + 73 186 + 74 186 + 75 186 + 76 186 + 77 186 + 78 186 + 79 186 + 7a 186 + 7b 186 + 7c 186 + 7d 186 + 7e 186 + 7f 186 + 84 188 + 8a 196 + 8b 196 + 8c 196 + 8d 196 + 8e 196 + 8f 196 + 90 196 + 91 196 + 92 196 + 93 196 + 94 196 + 95 196 + 96 196 + 97 196 + 98 196 + 99 196 + 9a 196 + 9b 196 + 9c 196 + 9d 196 + 9e 196 + 9f 196 + a6 192 + a7 192 + a8 192 + a9 192 + aa 192 + ab 192 + ac 192 + ad 192 + ae 192 + af 192 + b0 192 + b1 192 + b2 192 + b3 192 + b4 192 + b5 192 + b6 192 + b7 192 + b8 192 + b9 192 + ba 192 + bb 192 + c0 214 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 220 + 1 220 + 2 220 + 3 220 + 5 220 + 6 220 + 7 220 + 8 221 + a 224 + c 224 + d 224 + e 224 + f 224 + 10 224 + 11 224 + 12 225 + 13 225 + 14 225 + 15 225 + 16 225 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 231 + 1 231 + 2 231 + 3 231 + 4 231 + 5 232 + } +} + +Lines mapping: +20 <-> 28 +21 <-> 28 +23 <-> 32 +24 <-> 32 +25 <-> 56 +31 <-> 41 +32 <-> 70 +36 <-> 75 +37 <-> 76 +38 <-> 77 +39 <-> 78 +42 <-> 80 +58 <-> 187 +59 <-> 187 +60 <-> 205 +62 <-> 193 +63 <-> 215 +Not mapped: +22 +29 +30 +40 +43 +61 diff --git a/testData/results/pkg/TestGroovyTryFinally.dec b/testData/results/pkg/TestGroovyTryFinally.dec new file mode 100644 index 0000000000..2f0324cb9f --- /dev/null +++ b/testData/results/pkg/TestGroovyTryFinally.dec @@ -0,0 +1,589 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.BytecodeInterface8; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyTryFinally implements GroovyObject { + @Generated + public TestGroovyTryFinally() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public void test0() { + CallSite[] var1 = $getCallSiteArray(); + + try { + var1[0].call(var1[1].callGetProperty(System.class), "Hello");// 5 6 + } finally { + long l = 5;// 8 + } + }// 9 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test1() { + CallSite[] var1 = $getCallSiteArray(); + boolean var4 = false /* VF: Semaphore variable */; + + try { + var4 = true; + var1[2].call(var1[3].callGetProperty(System.class), "Hello");// 13 14 + var4 = false; + } finally { + if (var4) { + var1[6].call(var1[7].callGetProperty(System.class), "Finally");// 16 + } + } + + var1[4].call(var1[5].callGetProperty(System.class), "Finally"); + var1[8].call(var1[9].callGetProperty(System.class), "Bye");// 19 + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test2(int i) { + CallSite[] var2 = $getCallSiteArray(); + boolean var5 = false /* VF: Semaphore variable */; + + try { + var5 = true; + var2[10].call(var2[11].callGetProperty(System.class), "Hello");// 24 25 + var5 = false; + } finally { + if (var5) { + var2[18].call(var2[19].callGetProperty(System.class), "Finally");// 27 + if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigZ() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + if (i > 0) {// 28 + var2[22].call(var2[23].callGetProperty(System.class), i);// 29 + return;// 30 + } + } else if (i > 0) { + var2[20].call(var2[21].callGetProperty(System.class), i); + return; + } + } + } + + var2[12].call(var2[13].callGetProperty(System.class), "Finally"); + if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigZ() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + if (i > 0) { + var2[16].call(var2[17].callGetProperty(System.class), i); + return; + } + } else if (i > 0) { + var2[14].call(var2[15].callGetProperty(System.class), i); + return; + } + + var2[24].call(var2[25].callGetProperty(System.class), "Bye");// 34 + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyTryFinally' { + method ' ()V' { + 1 13 + 2 13 + 3 13 + 4 13 + 6 14 + 7 14 + 8 14 + 9 15 + a 15 + b 15 + c 15 + d 15 + e 16 + f 16 + 11 16 + 12 16 + 13 16 + 16 17 + } + + method 'test0 ()V' { + 1 20 + 2 20 + 3 20 + 4 20 + 5 23 + 6 23 + 7 23 + 8 23 + 9 23 + a 23 + b 23 + c 23 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 12 23 + 13 23 + 14 23 + 15 23 + 16 23 + 17 23 + 18 23 + 19 23 + 1a 23 + 29 25 + 2a 25 + 2b 25 + 2c 25 + 33 27 + } + + method 'test1 ()V' { + 1 31 + 2 31 + 3 31 + 4 31 + 5 36 + 6 36 + 7 36 + 8 36 + 9 36 + a 36 + b 36 + c 36 + d 36 + e 36 + f 36 + 10 36 + 11 36 + 12 36 + 13 36 + 14 36 + 15 36 + 16 36 + 17 36 + 18 36 + 19 36 + 1a 36 + 1f 44 + 20 44 + 21 44 + 22 44 + 23 44 + 24 44 + 25 44 + 26 44 + 27 44 + 28 44 + 29 44 + 2a 44 + 2b 44 + 2c 44 + 2d 44 + 2e 44 + 2f 44 + 30 44 + 31 44 + 32 44 + 33 44 + 34 44 + 3a 40 + 3b 40 + 3c 40 + 3d 40 + 3e 40 + 3f 40 + 40 40 + 41 40 + 42 40 + 43 40 + 44 40 + 45 40 + 46 40 + 47 40 + 48 40 + 49 40 + 4a 40 + 4b 40 + 4c 40 + 4d 40 + 4e 40 + 4f 40 + 53 45 + 54 45 + 55 45 + 56 45 + 57 45 + 58 45 + 59 45 + 5a 45 + 5b 45 + 5c 45 + 5d 45 + 5e 45 + 5f 45 + 60 45 + 61 45 + 62 45 + 63 45 + 64 45 + 65 45 + 66 45 + 67 45 + 68 45 + 6a 46 + } + + method 'test2 (I)V' { + 1 50 + 2 50 + 3 50 + 4 50 + 5 55 + 6 55 + 7 55 + 8 55 + 9 55 + a 55 + b 55 + c 55 + d 55 + e 55 + f 55 + 10 55 + 11 55 + 12 55 + 13 55 + 14 55 + 15 55 + 16 55 + 17 55 + 18 55 + 19 55 + 1a 55 + 1f 72 + 20 72 + 21 72 + 22 72 + 23 72 + 24 72 + 25 72 + 26 72 + 27 72 + 28 72 + 29 72 + 2a 72 + 2b 72 + 2c 72 + 2d 72 + 2e 72 + 2f 72 + 30 72 + 31 72 + 32 72 + 33 72 + 34 72 + 36 73 + 37 73 + 38 73 + 39 73 + 3a 73 + 3b 73 + 3c 73 + 3d 73 + 3e 73 + 3f 73 + 40 73 + 41 73 + 42 73 + 43 73 + 44 73 + 45 73 + 46 73 + 47 73 + 48 73 + 49 73 + 4a 73 + 4b 73 + 4c 73 + 4d 73 + 51 78 + 52 78 + 53 78 + 54 78 + 55 78 + 5b 78 + 5c 78 + 5d 78 + 5e 79 + 5f 79 + 60 79 + 61 79 + 62 79 + 63 79 + 64 79 + 65 79 + 66 79 + 67 79 + 68 79 + 69 79 + 6a 79 + 6b 79 + 6c 79 + 6d 79 + 6e 79 + 6f 79 + 70 79 + 71 79 + 72 79 + 73 79 + 74 79 + 75 79 + 77 80 + 7b 74 + 7c 74 + 7d 74 + 7e 74 + 7f 74 + 85 74 + 86 74 + 87 74 + 88 75 + 89 75 + 8a 75 + 8b 75 + 8c 75 + 8d 75 + 8e 75 + 8f 75 + 90 75 + 91 75 + 92 75 + 93 75 + 94 75 + 95 75 + 96 75 + 97 75 + 98 75 + 99 75 + 9a 75 + 9b 75 + 9c 75 + 9d 75 + 9e 75 + 9f 75 + a1 76 + a6 59 + a7 59 + a8 59 + a9 59 + aa 59 + ab 59 + ac 59 + ad 59 + ae 59 + af 59 + b0 59 + b1 59 + b2 59 + b3 59 + b4 59 + b5 59 + b6 59 + b7 59 + b8 59 + b9 59 + ba 59 + bb 59 + bd 60 + be 60 + bf 60 + c0 60 + c1 60 + c2 60 + c3 60 + c4 60 + c5 60 + c6 60 + c7 60 + c8 60 + c9 60 + ca 60 + cb 60 + cc 60 + cd 60 + ce 60 + cf 60 + d0 60 + d1 60 + d2 60 + d3 60 + d4 60 + d8 65 + d9 65 + da 65 + db 65 + dc 65 + e2 65 + e3 65 + e4 65 + e5 66 + e6 66 + e7 66 + e8 66 + e9 66 + ea 66 + eb 66 + ec 66 + ed 66 + ee 66 + ef 66 + f0 66 + f1 66 + f2 66 + f3 66 + f4 66 + f5 66 + f6 66 + f7 66 + f8 66 + f9 66 + fa 66 + fb 66 + fc 66 + fe 67 + 102 61 + 103 61 + 104 61 + 105 61 + 106 61 + 10c 61 + 10d 61 + 10e 61 + 10f 62 + 110 62 + 111 62 + 112 62 + 113 62 + 114 62 + 115 62 + 116 62 + 117 62 + 118 62 + 119 62 + 11a 62 + 11b 62 + 11c 62 + 11d 62 + 11e 62 + 11f 62 + 120 62 + 121 62 + 122 62 + 123 62 + 124 62 + 125 62 + 126 62 + 128 63 + 12b 83 + 12c 83 + 12d 83 + 12e 83 + 12f 83 + 130 83 + 131 83 + 132 83 + 133 83 + 134 83 + 135 83 + 136 83 + 137 83 + 138 83 + 139 83 + 13a 83 + 13b 83 + 13c 83 + 13d 83 + 13e 83 + 13f 83 + 140 83 + 142 84 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 90 + 1 90 + 2 90 + 3 90 + 5 90 + 6 90 + 7 90 + 8 91 + a 94 + c 94 + d 94 + e 94 + f 94 + 10 94 + 11 94 + 12 95 + 13 95 + 14 95 + 15 95 + 16 95 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 101 + 1 101 + 2 101 + 3 101 + 4 101 + 5 102 + } +} + +Lines mapping: +5 <-> 24 +6 <-> 24 +8 <-> 26 +9 <-> 28 +13 <-> 37 +14 <-> 37 +16 <-> 41 +19 <-> 46 +24 <-> 56 +25 <-> 56 +27 <-> 60 +28 <-> 62 +29 <-> 63 +30 <-> 64 +34 <-> 84 +Not mapped: +7 +15 +17 +26 +31 +32 diff --git a/testData/results/pkg/TestGroovyTryLoopReturnFinally.dec b/testData/results/pkg/TestGroovyTryLoopReturnFinally.dec new file mode 100644 index 0000000000..7024f00f38 --- /dev/null +++ b/testData/results/pkg/TestGroovyTryLoopReturnFinally.dec @@ -0,0 +1,275 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; +import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyTryLoopReturnFinally implements GroovyObject { + private boolean field; + + @Generated + public TestGroovyTryLoopReturnFinally() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test(File file) { + CallSite[] var2 = $getCallSiteArray(); + + while (true) { + boolean var8 = false /* VF: Semaphore variable */; + + label50: { + try { + var8 = true; + if (this.field) {// 7 8 + if (!ScriptBytecodeAdapter.compareEqual(file, null)) {// 9 + Scanner scanner = (Scanner)ScriptBytecodeAdapter.castToType(var2[2].callConstructor(Scanner.class, file), Scanner.class);// 11 13 + continue;// 14 + } + + var8 = false; + break label50; + } + + var8 = false; + } catch (FileNotFoundException e) {// 15 + var2[3].call(e);// 16 + var8 = false; + } finally { + if (var8) { + var2[6].call(var2[7].callGetProperty(System.class), "Finally");// 18 + } + } + + var2[4].call(var2[5].callGetProperty(System.class), "Finally"); + return; + } + + var2[0].call(var2[1].callGetProperty(System.class), "Finally"); + return;// 19 + } + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyTryLoopReturnFinally' { + method ' ()V' { + 1 18 + 2 18 + 3 18 + 4 18 + 6 19 + 7 19 + 8 19 + 9 20 + a 20 + b 20 + c 20 + d 20 + e 21 + f 21 + 11 21 + 12 21 + 13 21 + 16 22 + } + + method 'test (Ljava/io/File;)V' { + 1 26 + 2 26 + 3 26 + 4 26 + 5 34 + 6 34 + 7 34 + 8 34 + 9 34 + a 34 + b 34 + c 35 + d 35 + e 35 + f 35 + 10 35 + 11 35 + 12 35 + 13 35 + 15 58 + 16 58 + 17 58 + 18 58 + 19 58 + 1a 58 + 1b 58 + 1c 58 + 1d 58 + 1e 58 + 1f 58 + 20 58 + 21 58 + 22 58 + 23 58 + 24 58 + 25 58 + 26 58 + 27 58 + 28 58 + 29 58 + 2a 58 + 2d 59 + 2e 36 + 2f 36 + 30 36 + 31 36 + 32 36 + 33 36 + 34 36 + 35 36 + 36 36 + 37 36 + 38 36 + 39 36 + 3a 36 + 3b 36 + 3c 36 + 3d 36 + 3e 36 + 3f 36 + 40 36 + 41 36 + 42 36 + 45 37 + 4b 45 + 4d 46 + 4e 46 + 4f 46 + 50 46 + 51 46 + 52 46 + 53 46 + 54 46 + 55 46 + 56 46 + 57 46 + 5d 54 + 5e 54 + 5f 54 + 60 54 + 61 54 + 62 54 + 63 54 + 64 54 + 65 54 + 66 54 + 67 54 + 68 54 + 69 54 + 6a 54 + 6b 54 + 6c 54 + 6d 54 + 6e 54 + 6f 54 + 70 54 + 71 54 + 72 54 + 79 50 + 7a 50 + 7b 50 + 7c 50 + 7d 50 + 7e 50 + 7f 50 + 80 50 + 81 50 + 82 50 + 83 50 + 84 50 + 85 50 + 86 50 + 87 50 + 88 50 + 89 50 + 8a 50 + 8b 50 + 8c 50 + 8d 50 + 8e 50 + 93 55 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 67 + 1 67 + 2 67 + 3 67 + 5 67 + 6 67 + 7 67 + 8 68 + a 71 + c 71 + d 71 + e 71 + f 71 + 10 71 + 11 71 + 12 72 + 13 72 + 14 72 + 15 72 + 16 72 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 78 + 1 78 + 2 78 + 3 78 + 4 78 + 5 79 + } +} + +Lines mapping: +7 <-> 35 +8 <-> 35 +9 <-> 36 +11 <-> 37 +13 <-> 37 +14 <-> 38 +15 <-> 46 +16 <-> 47 +18 <-> 51 +19 <-> 60 +Not mapped: +10 +17 diff --git a/testData/results/pkg/TestGroovyTryLoopSimpleFinally.dec b/testData/results/pkg/TestGroovyTryLoopSimpleFinally.dec new file mode 100644 index 0000000000..929beeb516 --- /dev/null +++ b/testData/results/pkg/TestGroovyTryLoopSimpleFinally.dec @@ -0,0 +1,686 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Scanner; +import org.codehaus.groovy.runtime.BytecodeInterface8; +import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; +import org.codehaus.groovy.runtime.callsite.CallSite; +import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; + +public class TestGroovyTryLoopSimpleFinally implements GroovyObject { + private boolean field; + + @Generated + public TestGroovyTryLoopSimpleFinally() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test(File file) { + CallSite[] var2 = $getCallSiteArray(); + + while (true) { + boolean var8 = false /* VF: Semaphore variable */; + + try { + var8 = true; + if (!this.field) {// 10 11 + var8 = false; + break; + } + + Scanner scanner = (Scanner)ScriptBytecodeAdapter.castToType(var2[0].callConstructor(Scanner.class, file), Scanner.class);// 12 + } catch (FileNotFoundException e) {// 14 + var2[1].call(e);// 15 + var8 = false; + break; + } finally { + if (var8) { + var2[4].call(var2[5].callGetProperty(System.class), "Finally");// 17 + } + } + } + + var2[2].call(var2[3].callGetProperty(System.class), "Finally"); + }// 18 + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void test2(int x, Path file) throws IOException { + CallSite[] var3; + label171: { + label185: { + var3 = $getCallSiteArray(); + if (BytecodeInterface8.isOrigInt() && BytecodeInterface8.isOrigZ() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()) { + while (true) { + boolean var13 = false /* VF: Semaphore variable */; + + try { + var13 = true; + if (x >= 0) {// 22 23 + Scanner scanner = (Scanner)ScriptBytecodeAdapter.castToType(var3[18].callConstructor(Scanner.class, file), Scanner.class);// 24 + if (x % 11 == 0) {// 26 + var3[19].call(var3[20].callGetProperty(System.class), "nice");// 27 + var13 = false; + break label185; + } + + x = DefaultTypeTransformation.intUnbox(var3[23].call(x, var3[24].call(scanner)));// 29 31 + continue;// 32 + } + + var13 = false; + } finally { + if (var13) { + var3[27].call(var3[28].callGetProperty(System.class), "Finally");// 34 + } + } + + var3[25].call(var3[26].callGetProperty(System.class), "Finally"); + break;// 35 + } + } else { + while (true) { + boolean var10 = false /* VF: Semaphore variable */; + + try { + var10 = true; + if (x < 0) { + var10 = false; + break; + } + + Scanner scanner = (Scanner)ScriptBytecodeAdapter.castToType(var3[6].callConstructor(Scanner.class, file), Scanner.class); + if (DefaultTypeTransformation.intUnbox(var3[7].call(x, 11)) == 0) { + var3[8].call(var3[9].callGetProperty(System.class), "nice"); + var10 = false; + break label171; + } + + x = DefaultTypeTransformation.intUnbox(var3[12].call(x, var3[13].call(scanner))); + } finally { + if (var10) { + var3[16].call(var3[17].callGetProperty(System.class), "Finally"); + } + } + } + + var3[14].call(var3[15].callGetProperty(System.class), "Finally"); + } + + return; + } + + var3[21].call(var3[22].callGetProperty(System.class), "Finally"); + return; + } + + var3[10].call(var3[11].callGetProperty(System.class), "Finally"); + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyTryLoopSimpleFinally' { + method ' ()V' { + 1 22 + 2 22 + 3 22 + 4 22 + 6 23 + 7 23 + 8 23 + 9 24 + a 24 + b 24 + c 24 + d 24 + e 25 + f 25 + 11 25 + 12 25 + 13 25 + 16 26 + } + + method 'test (Ljava/io/File;)V' { + 1 30 + 2 30 + 3 30 + 4 30 + 5 37 + 6 37 + 7 37 + 8 37 + 9 37 + a 37 + b 37 + c 42 + d 42 + e 42 + f 42 + 10 42 + 11 42 + 12 42 + 13 42 + 14 42 + 15 42 + 16 42 + 17 42 + 18 42 + 19 42 + 1a 42 + 1b 42 + 1c 42 + 1d 42 + 1e 42 + 1f 42 + 20 42 + 29 43 + 2b 44 + 2c 44 + 2d 44 + 2e 44 + 2f 44 + 30 44 + 31 44 + 32 44 + 33 44 + 34 44 + 35 44 + 3b 54 + 3c 54 + 3d 54 + 3e 54 + 3f 54 + 40 54 + 41 54 + 42 54 + 43 54 + 44 54 + 45 54 + 46 54 + 47 54 + 48 54 + 49 54 + 4a 54 + 4b 54 + 4c 54 + 4d 54 + 4e 54 + 4f 54 + 50 54 + 57 49 + 58 49 + 59 49 + 5a 49 + 5b 49 + 5c 49 + 5d 49 + 5e 49 + 5f 49 + 60 49 + 61 49 + 62 49 + 63 49 + 64 49 + 65 49 + 66 49 + 67 49 + 68 49 + 69 49 + 6a 49 + 6b 49 + 6c 49 + 71 55 + } + + method 'test2 (ILjava/nio/file/Path;)V' { + 1 62 + 2 62 + 3 62 + 4 62 + 5 63 + 6 63 + 7 63 + 8 63 + 9 63 + a 63 + b 63 + c 63 + d 63 + e 63 + f 63 + 10 63 + 11 63 + 12 63 + 13 63 + 14 63 + 15 63 + 16 63 + 17 63 + 18 63 + 19 63 + 1a 63 + 1b 63 + 1c 63 + 20 97 + 21 97 + 22 97 + 23 97 + 24 97 + 2a 97 + 2b 97 + 2c 97 + 2d 102 + 2e 102 + 2f 102 + 30 102 + 31 102 + 32 102 + 33 102 + 34 102 + 35 102 + 36 102 + 37 102 + 38 102 + 39 102 + 3a 102 + 3b 102 + 3c 102 + 3d 102 + 3e 102 + 3f 102 + 40 102 + 41 102 + 42 102 + 46 103 + 47 103 + 48 103 + 49 103 + 4a 103 + 4b 103 + 4c 103 + 4d 103 + 4e 103 + 4f 103 + 50 103 + 51 103 + 52 103 + 53 103 + 54 103 + 55 103 + 56 103 + 57 103 + 58 103 + 59 103 + 5a 103 + 5b 103 + 5c 103 + 5d 103 + 5e 103 + 64 103 + 65 103 + 66 103 + 67 104 + 68 104 + 69 104 + 6a 104 + 6b 104 + 6c 104 + 6d 104 + 6e 104 + 6f 104 + 70 104 + 71 104 + 72 104 + 73 104 + 74 104 + 75 104 + 76 104 + 77 104 + 78 104 + 79 104 + 7a 104 + 7b 104 + 7c 104 + 7f 127 + 80 127 + 81 127 + 82 127 + 83 127 + 84 127 + 85 127 + 86 127 + 87 127 + 88 127 + 89 127 + 8a 127 + 8b 127 + 8c 127 + 8d 127 + 8e 127 + 8f 127 + 90 127 + 91 127 + 92 127 + 93 127 + 94 127 + 97 128 + 98 109 + 99 109 + 9a 109 + 9b 109 + 9c 109 + 9d 109 + 9e 109 + 9f 109 + a0 109 + a1 109 + a2 109 + a3 109 + a4 109 + a5 109 + a6 109 + a7 109 + a8 109 + a9 109 + aa 109 + ab 109 + ac 109 + ad 109 + ae 109 + af 109 + b1 109 + b2 109 + b3 109 + b4 109 + bc 117 + bd 117 + be 117 + bf 117 + c0 117 + c1 117 + c2 117 + c3 117 + c4 117 + c5 117 + c6 117 + c7 117 + c8 117 + c9 117 + ca 117 + cb 117 + cc 117 + cd 117 + ce 117 + cf 117 + d0 117 + d1 117 + d8 112 + d9 112 + da 112 + db 112 + dc 112 + dd 112 + de 112 + df 112 + e0 112 + e1 112 + e2 112 + e3 112 + e4 112 + e5 112 + e6 112 + e7 112 + e8 112 + e9 112 + ea 112 + eb 112 + ec 112 + ed 112 + f5 69 + f6 69 + f7 69 + f8 69 + f9 69 + ff 69 + 100 69 + 101 69 + 102 70 + 103 70 + 104 70 + 105 70 + 106 70 + 107 70 + 108 70 + 109 70 + 10a 70 + 10b 70 + 10c 70 + 10d 70 + 10e 70 + 10f 70 + 110 70 + 111 70 + 112 70 + 113 70 + 114 70 + 115 70 + 116 70 + 117 70 + 11b 71 + 11c 71 + 11d 71 + 11e 71 + 11f 71 + 120 71 + 121 71 + 122 71 + 128 71 + 129 71 + 12a 71 + 12b 72 + 12c 72 + 12d 72 + 12e 72 + 12f 72 + 130 72 + 131 72 + 132 72 + 133 72 + 134 72 + 135 72 + 136 72 + 137 72 + 138 72 + 139 72 + 13a 72 + 13b 72 + 13c 72 + 13d 72 + 13e 72 + 13f 72 + 140 72 + 143 123 + 144 123 + 145 123 + 146 123 + 147 123 + 148 123 + 149 123 + 14a 123 + 14b 123 + 14c 123 + 14d 123 + 14e 123 + 14f 123 + 150 123 + 151 123 + 152 123 + 153 123 + 154 123 + 155 123 + 156 123 + 157 123 + 158 123 + 15b 124 + 15c 77 + 15d 77 + 15e 77 + 15f 77 + 160 77 + 161 77 + 162 77 + 163 77 + 164 77 + 165 77 + 166 77 + 167 77 + 168 77 + 169 77 + 16a 77 + 16b 77 + 16c 77 + 16d 77 + 16e 77 + 16f 77 + 170 77 + 171 77 + 172 77 + 173 77 + 175 77 + 176 77 + 177 77 + 178 77 + 17a 78 + 180 88 + 181 88 + 182 88 + 183 88 + 184 88 + 185 88 + 186 88 + 187 88 + 188 88 + 189 88 + 18a 88 + 18b 88 + 18c 88 + 18d 88 + 18e 88 + 18f 88 + 190 88 + 191 88 + 192 88 + 193 88 + 194 88 + 195 88 + 197 89 + 19c 84 + 19d 84 + 19e 84 + 19f 84 + 1a0 84 + 1a1 84 + 1a2 84 + 1a3 84 + 1a4 84 + 1a5 84 + 1a6 84 + 1a7 84 + 1a8 84 + 1a9 84 + 1aa 84 + 1ab 84 + 1ac 84 + 1ad 84 + 1ae 84 + 1af 84 + 1b0 84 + 1b1 84 + 1b6 120 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 134 + 1 134 + 2 134 + 3 134 + 5 134 + 6 134 + 7 134 + 8 135 + a 138 + c 138 + d 138 + e 138 + f 138 + 10 138 + 11 138 + 12 139 + 13 139 + 14 139 + 15 139 + 16 139 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 145 + 1 145 + 2 145 + 3 145 + 4 145 + 5 146 + } +} + +Lines mapping: +10 <-> 38 +11 <-> 38 +12 <-> 43 +14 <-> 44 +15 <-> 45 +17 <-> 50 +18 <-> 56 +22 <-> 70 +23 <-> 70 +24 <-> 71 +26 <-> 72 +27 <-> 73 +29 <-> 78 +31 <-> 78 +32 <-> 79 +34 <-> 85 +35 <-> 90 +Not mapped: +13 +16 +28 +33 diff --git a/testData/results/pkg/TestGroovyTryReturn.dec b/testData/results/pkg/TestGroovyTryReturn.dec new file mode 100644 index 0000000000..f3ca7a3653 --- /dev/null +++ b/testData/results/pkg/TestGroovyTryReturn.dec @@ -0,0 +1,1696 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import java.util.Random; +import java.util.function.Supplier; +import org.codehaus.groovy.runtime.callsite.CallSite; +import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; + +public class TestGroovyTryReturn implements GroovyObject { + @Generated + public TestGroovyTryReturn() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public boolean test(Supplier param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 2 + // 05: aload 2 + // 06: ldc 0 + // 08: aaload + // 09: aload 1 + // 0a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0f: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z + // 12: istore 3 + // 13: nop + // 14: nop + // 15: iload 3 + // 16: ireturn + // 17: nop + // 18: nop + // 19: athrow + // 1a: astore 4 + // 1c: aload 2 + // 1d: ldc 1 + // 1f: aaload + // 20: ldc java/lang/RuntimeException + // 22: aload 4 + // 24: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 29: checkcast java/lang/Throwable + // 2c: athrow + // 2d: athrow + // 2e: nop + // 2f: nop + // 30: athrow + // 31: nop + // 32: nop + // 33: athrow + // 34: astore 5 + // 36: aload 5 + // 38: athrow + // 39: nop + // 3a: nop + // 3b: nop + // 3c: nop + // 3d: nop + // 3e: nop + // 3f: nop + // 40: nop + // 41: athrow + // try (3 -> 11): 17 java/lang/Exception + // try (12 -> 14): 17 java/lang/Exception + // try (3 -> 11): 33 null + // try (12 -> 14): 33 null + // try (17 -> 26): 33 null + } + + public boolean testFinally(Supplier param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 2 + // 05: aload 2 + // 06: ldc 2 + // 08: aaload + // 09: aload 1 + // 0a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0f: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z + // 12: istore 3 + // 13: nop + // 14: aload 2 + // 15: ldc 3 + // 17: aaload + // 18: aload 2 + // 19: ldc 4 + // 1b: aaload + // 1c: ldc java/lang/System + // 1e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 23: ldc "Finally" + // 25: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 2a: pop + // 2b: nop + // 2c: iload 3 + // 2d: ireturn + // 2e: nop + // 2f: nop + // 30: athrow + // 31: nop + // 32: nop + // 33: nop + // 34: nop + // 35: nop + // 36: nop + // 37: nop + // 38: nop + // 39: nop + // 3a: nop + // 3b: nop + // 3c: nop + // 3d: nop + // 3e: nop + // 3f: nop + // 40: nop + // 41: nop + // 42: nop + // 43: nop + // 44: nop + // 45: nop + // 46: nop + // 47: athrow + // 48: nop + // 49: nop + // 4a: athrow + // 4b: astore 4 + // 4d: aload 2 + // 4e: ldc 7 + // 50: aaload + // 51: aload 2 + // 52: ldc 8 + // 54: aaload + // 55: ldc java/lang/System + // 57: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 5c: ldc "Finally" + // 5e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 63: pop + // 64: aload 4 + // 66: athrow + // 67: nop + // 68: nop + // 69: nop + // 6a: nop + // 6b: nop + // 6c: nop + // 6d: nop + // 6e: nop + // 6f: athrow + // try (3 -> 11): 54 null + // try (23 -> 25): 54 null + } + + public void testFinally1(Supplier param1) { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 2 + // 05: aload 2 + // 06: ldc 9 + // 08: aaload + // 09: aload 2 + // 0a: ldc 10 + // 0c: aaload + // 0d: ldc java/lang/System + // 0f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 14: ldc "pred" + // 16: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 1b: pop + // 1c: aload 2 + // 1d: ldc 11 + // 1f: aaload + // 20: aload 1 + // 21: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 26: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z + // 29: ifeq 46 + // 2c: nop + // 2d: aload 2 + // 2e: ldc 12 + // 30: aaload + // 31: aload 2 + // 32: ldc 13 + // 34: aaload + // 35: ldc java/lang/System + // 37: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 3c: ldc "Finally" + // 3e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 43: pop + // 44: nop + // 45: return + // 46: goto 49 + // 49: aload 2 + // 4a: ldc 14 + // 4c: aaload + // 4d: aload 2 + // 4e: ldc 15 + // 50: aaload + // 51: ldc java/lang/System + // 53: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 58: ldc "Finally" + // 5a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 5f: pop + // 60: goto 7d + // 63: astore 3 + // 64: aload 2 + // 65: ldc 16 + // 67: aaload + // 68: aload 2 + // 69: ldc 17 + // 6b: aaload + // 6c: ldc java/lang/System + // 6e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 73: ldc "Finally" + // 75: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 7a: pop + // 7b: aload 3 + // 7c: athrow + // 7d: aload 2 + // 7e: ldc 18 + // 80: aaload + // 81: aload 2 + // 82: ldc 19 + // 84: aaload + // 85: ldc java/lang/System + // 87: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 8c: ldc "suc" + // 8e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 93: pop + // 94: return + // try (14 -> 22): 48 null + // try (34 -> 36): 48 null + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally2(Supplier supplier) { + CallSite[] var2 = $getCallSiteArray(); + boolean b = (boolean)0;// 38 + boolean var7 = false /* VF: Semaphore variable */; + + try { + var7 = true; + Object var4 = var2[20].call(supplier);// 39 40 + var9 = DefaultTypeTransformation.booleanUnbox(var4); + var7 = false; + } finally { + if (var7) { + var2[23].call(var2[24].callGetProperty(System.class), "Finally");// 42 + } + } + + var2[21].call(var2[22].callGetProperty(System.class), "Finally"); + return var9;// 45 + } + + public boolean testFinally3(boolean param1, boolean param2, int param3, Supplier param4) { + // $VF: Couldn't be decompiled + // Bytecode: + // 000: nop + // 001: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 004: astore 5 + // 006: iload 1 + // 007: ifeq 045 + // 00a: iload 2 + // 00b: ifeq 024 + // 00e: aload 5 + // 010: ldc 25 + // 012: aaload + // 013: aload 4 + // 015: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 01a: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z + // 01d: ifeq 024 + // 020: bipush 1 + // 021: goto 025 + // 024: bipush 0 + // 025: istore 6 + // 027: nop + // 028: aload 5 + // 02a: ldc 26 + // 02c: aaload + // 02d: aload 5 + // 02f: ldc 27 + // 031: aaload + // 032: ldc java/lang/System + // 034: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 039: ldc "Finally" + // 03b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 040: pop + // 041: nop + // 042: iload 6 + // 044: ireturn + // 045: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigInt ()Z + // 048: ifeq 060 + // 04b: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ ()Z + // 04e: ifeq 060 + // 051: getstatic pkg/TestGroovyTryReturn.__$stMC Z + // 054: ifne 060 + // 057: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass ()Z + // 05a: ifne 060 + // 05d: goto 09a + // 060: iload 3 + // 061: bipush 0 + // 062: if_icmple 069 + // 065: bipush 1 + // 066: goto 06a + // 069: bipush 0 + // 06a: ifeq 097 + // 06d: iload 3 + // 06e: bipush 1 + // 06f: if_icmpne 076 + // 072: bipush 1 + // 073: goto 077 + // 076: bipush 0 + // 077: istore 7 + // 079: nop + // 07a: aload 5 + // 07c: ldc 28 + // 07e: aaload + // 07f: aload 5 + // 081: ldc 29 + // 083: aaload + // 084: ldc java/lang/System + // 086: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 08b: ldc "Finally" + // 08d: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 092: pop + // 093: nop + // 094: iload 7 + // 096: ireturn + // 097: goto 0d1 + // 09a: iload 3 + // 09b: bipush 0 + // 09c: if_icmple 0a3 + // 09f: bipush 1 + // 0a0: goto 0a4 + // 0a3: bipush 0 + // 0a4: ifeq 0d1 + // 0a7: iload 3 + // 0a8: bipush 1 + // 0a9: if_icmpne 0b0 + // 0ac: bipush 1 + // 0ad: goto 0b1 + // 0b0: bipush 0 + // 0b1: istore 8 + // 0b3: nop + // 0b4: aload 5 + // 0b6: ldc 30 + // 0b8: aaload + // 0b9: aload 5 + // 0bb: ldc 31 + // 0bd: aaload + // 0be: ldc java/lang/System + // 0c0: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0c5: ldc "Finally" + // 0c7: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0cc: pop + // 0cd: nop + // 0ce: iload 8 + // 0d0: ireturn + // 0d1: aload 5 + // 0d3: ldc 32 + // 0d5: aaload + // 0d6: aload 4 + // 0d8: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0dd: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z + // 0e0: istore 9 + // 0e2: nop + // 0e3: aload 5 + // 0e5: ldc 33 + // 0e7: aaload + // 0e8: aload 5 + // 0ea: ldc 34 + // 0ec: aaload + // 0ed: ldc java/lang/System + // 0ef: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0f4: ldc "Finally" + // 0f6: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0fb: pop + // 0fc: nop + // 0fd: iload 9 + // 0ff: ireturn + // 100: nop + // 101: nop + // 102: athrow + // 103: nop + // 104: nop + // 105: nop + // 106: nop + // 107: nop + // 108: nop + // 109: nop + // 10a: nop + // 10b: nop + // 10c: nop + // 10d: nop + // 10e: nop + // 10f: nop + // 110: nop + // 111: nop + // 112: nop + // 113: nop + // 114: nop + // 115: nop + // 116: nop + // 117: nop + // 118: nop + // 119: nop + // 11a: nop + // 11b: athrow + // 11c: nop + // 11d: nop + // 11e: athrow + // 11f: astore 10 + // 121: aload 5 + // 123: ldc 37 + // 125: aaload + // 126: aload 5 + // 128: ldc 38 + // 12a: aaload + // 12b: ldc java/lang/System + // 12d: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 132: ldc "Finally" + // 134: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 139: pop + // 13a: aload 10 + // 13c: athrow + // 13d: nop + // 13e: nop + // 13f: nop + // 140: nop + // 141: nop + // 142: nop + // 143: nop + // 144: nop + // 145: athrow + // try (3 -> 19): 154 null + // try (31 -> 57): 154 null + // try (69 -> 87): 154 null + // try (99 -> 109): 154 null + // try (121 -> 123): 154 null + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally4(Supplier supplier) { + CallSite[] var2 = $getCallSiteArray(); + boolean b = false;// 65 + boolean var7 = false /* VF: Semaphore variable */; + + try { + var7 = true; + Object var4 = var2[39].call(supplier);// 66 67 + b = DefaultTypeTransformation.booleanUnbox(var4); + var7 = false; + } finally { + if (var7) { + var2[42].call(var2[43].callGetProperty(System.class), "Finally");// 69 + } + } + + var2[40].call(var2[41].callGetProperty(System.class), "Finally"); + return b;// 72 + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally5(Supplier supplier) { + CallSite[] var2 = $getCallSiteArray(); + boolean b = false;// 76 + boolean var10 = false /* VF: Semaphore variable */; + + try { + var10 = true; + Object var4 = var2[44].call(supplier);// 77 78 + b = DefaultTypeTransformation.booleanUnbox(var4); + var10 = false; + } catch (Exception e) {// 79 + var2[45].call(var2[46].callGetProperty(System.class), "Catch");// 80 + Object var6 = var2[47].call(supplier);// 81 + b = DefaultTypeTransformation.booleanUnbox(var6); + var10 = false; + } finally { + if (var10) { + var2[50].call(var2[51].callGetProperty(System.class), "Finally");// 83 + } + } + + var2[48].call(var2[49].callGetProperty(System.class), "Finally"); + return b;// 86 + } + + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally6(boolean a, Supplier supplier) { + CallSite[] var3 = $getCallSiteArray(); + boolean b = false;// 90 + boolean var12 = false /* VF: Semaphore variable */; + + try { + var12 = true; + if (a) {// 91 92 + boolean var5 = true;// 93 + var3[52].call(var3[53].callGetProperty(System.class), "If");// 94 + } + + Object var6 = var3[54].call(supplier);// 95 97 + b = DefaultTypeTransformation.booleanUnbox(var6); + var12 = false; + } catch (Exception e) {// 98 + var3[55].call(var3[56].callGetProperty(System.class), "Catch");// 99 + Object var8 = var3[57].call(supplier);// 100 + b = DefaultTypeTransformation.booleanUnbox(var8); + var12 = false; + } finally { + if (var12) { + var3[60].call(var3[61].callGetProperty(System.class), "Finally");// 102 + } + } + + var3[58].call(var3[59].callGetProperty(System.class), "Finally"); + return b;// 105 + } + + public void testLoopFinally() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 1 + // 05: bipush 1 + // 06: istore 2 + // 07: iload 2 + // 08: pop + // 09: iload 2 + // 0a: ifeq 27 + // 0d: nop + // 0e: aload 1 + // 0f: ldc 62 + // 11: aaload + // 12: aload 1 + // 13: ldc 63 + // 15: aaload + // 16: ldc java/lang/System + // 18: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 1d: ldc "Finally" + // 1f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 24: pop + // 25: nop + // 26: return + // 27: goto 2a + // 2a: aload 1 + // 2b: ldc 64 + // 2d: aaload + // 2e: aload 1 + // 2f: ldc 65 + // 31: aaload + // 32: ldc java/lang/System + // 34: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 39: ldc "Finally" + // 3b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 40: pop + // 41: goto 5e + // 44: astore 3 + // 45: aload 1 + // 46: ldc 66 + // 48: aaload + // 49: aload 1 + // 4a: ldc 67 + // 4c: aaload + // 4d: ldc java/lang/System + // 4f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 54: ldc "Finally" + // 56: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 5b: pop + // 5c: aload 3 + // 5d: athrow + // 5e: goto 09 + // 61: athrow + // try (7 -> 10): 36 null + // try (22 -> 24): 36 null + } + + public void testParsingFailureSimple() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 1 + // 05: aload 1 + // 06: ldc 68 + // 08: aaload + // 09: aload 1 + // 0a: ldc 69 + // 0c: aaload + // 0d: ldc java/lang/System + // 0f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 14: ldc "inner" + // 16: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 1b: pop + // 1c: goto 1f + // 1f: nop + // 20: aload 1 + // 21: ldc 70 + // 23: aaload + // 24: aload 1 + // 25: ldc 71 + // 27: aaload + // 28: ldc java/lang/System + // 2a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 2f: ldc "fin" + // 31: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 36: pop + // 37: nop + // 38: return + // 39: nop + // 3a: nop + // 3b: athrow + // 3c: astore 2 + // 3d: nop + // 3e: aload 1 + // 3f: ldc 72 + // 41: aaload + // 42: aload 1 + // 43: ldc 73 + // 45: aaload + // 46: ldc java/lang/System + // 48: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 4d: ldc "fin" + // 4f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 54: pop + // 55: nop + // 56: return + // 57: nop + // 58: athrow + // 59: nop + // 5a: nop + // 5b: athrow + // 5c: nop + // 5d: nop + // 5e: nop + // 5f: nop + // 60: nop + // 61: nop + // 62: nop + // 63: nop + // 64: nop + // 65: nop + // 66: nop + // 67: nop + // 68: nop + // 69: nop + // 6a: nop + // 6b: nop + // 6c: nop + // 6d: nop + // 6e: nop + // 6f: nop + // 70: nop + // 71: nop + // 72: athrow + // 73: nop + // 74: nop + // 75: athrow + // 76: astore 3 + // 77: aload 1 + // 78: ldc 76 + // 7a: aaload + // 7b: aload 1 + // 7c: ldc 77 + // 7e: aaload + // 7f: ldc java/lang/System + // 81: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 86: ldc "fin" + // 88: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 8d: pop + // 8e: aload 3 + // 8f: athrow + // 90: athrow + // try (3 -> 15): 32 null + // try (3 -> 16): 78 null + // try (28 -> 29): 78 null + // try (32 -> 34): 78 null + // try (46 -> 47): 78 null + } + + public void testPostdomFailure() { + CallSite[] var1 = $getCallSiteArray(); + String var1x = null;// 154 + var1[78].call(var1[79].callGetProperty(System.class), 1);// 155 + + while (DefaultTypeTransformation.booleanUnbox(var1[80].call(var1[81].callConstructor(Random.class)))) {// 157 + try { + try { + var1[82].call(var1[83].callGetProperty(System.class), 2);// 158 159 160 + } catch (Exception var9) {// 161 + var1[84].call(var1[85].callGetProperty(System.class), 3);// 162 + } finally { + continue; + } + } finally { + byte var10 = (byte)28;// 168 + } + } + }// 170 + + public void testVarWrong() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 1 + // 05: ldc 0 + // 07: istore 2 + // 08: iload 2 + // 09: pop + // 0a: aload 1 + // 0b: ldc 86 + // 0d: aaload + // 0e: aload 1 + // 0f: ldc 87 + // 11: aaload + // 12: ldc java/lang/System + // 14: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 19: ldc "Hi" + // 1b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 20: pop + // 21: goto 60 + // 24: astore 3 + // 25: aload 3 + // 26: aconst_null + // 27: invokestatic org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareNotEqual (Ljava/lang/Object;Ljava/lang/Object;)Z + // 2a: ifeq 3b + // 2d: nop + // 2e: getstatic pkg/TestGroovyTryReturn.$const$0 F + // 31: fstore 4 + // 33: fload 4 + // 35: pop + // 36: nop + // 37: return + // 38: nop + // 39: nop + // 3a: athrow + // 3b: aload 1 + // 3c: ldc 88 + // 3e: aaload + // 3f: aload 1 + // 40: ldc 89 + // 42: aaload + // 43: ldc java/lang/System + // 45: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 4a: aload 3 + // 4b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 50: pop + // 51: nop + // 52: getstatic pkg/TestGroovyTryReturn.$const$0 F + // 55: fstore 5 + // 57: fload 5 + // 59: pop + // 5a: nop + // 5b: return + // 5c: athrow + // 5d: nop + // 5e: nop + // 5f: athrow + // 60: getstatic pkg/TestGroovyTryReturn.$const$0 F + // 63: fstore 6 + // 65: fload 6 + // 67: pop + // 68: goto 78 + // 6b: astore 7 + // 6d: getstatic pkg/TestGroovyTryReturn.$const$0 F + // 70: fstore 8 + // 72: fload 8 + // 74: pop + // 75: aload 7 + // 77: athrow + // 78: return + // try (7 -> 19): 19 java/lang/Exception + // try (7 -> 19): 61 null + // try (19 -> 25): 61 null + // try (30 -> 31): 61 null + // try (34 -> 46): 61 null + // try (51 -> 52): 61 null + } + + public void testInvalidUse() { + // $VF: Couldn't be decompiled + // Bytecode: + // 000: nop + // 001: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 004: astore 1 + // 005: bipush 0 + // 006: istore 2 + // 007: iload 2 + // 008: pop + // 009: ldc "Hi!" + // 00b: astore 3 + // 00c: aload 3 + // 00d: pop + // 00e: aload 1 + // 00f: ldc 90 + // 011: aaload + // 012: aload 1 + // 013: ldc 91 + // 015: aaload + // 016: ldc java/lang/System + // 018: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 01d: iload 2 + // 01e: invokestatic java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean; + // 021: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 026: pop + // 027: nop + // 028: aload 1 + // 029: ldc 92 + // 02b: aaload + // 02c: aload 1 + // 02d: ldc 93 + // 02f: aaload + // 030: ldc java/lang/System + // 032: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 037: aload 3 + // 038: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 03d: pop + // 03e: nop + // 03f: return + // 040: nop + // 041: nop + // 042: athrow + // 043: astore 4 + // 045: aload 1 + // 046: ldc 94 + // 048: aaload + // 049: aload 1 + // 04a: ldc 95 + // 04c: aaload + // 04d: ldc java/lang/System + // 04f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 054: aload 4 + // 056: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 05b: pop + // 05c: goto 097 + // 05f: astore 5 + // 061: nop + // 062: aload 1 + // 063: ldc 96 + // 065: aaload + // 066: aload 1 + // 067: ldc 97 + // 069: aaload + // 06a: ldc java/lang/System + // 06c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 071: aload 4 + // 073: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 078: pop + // 079: nop + // 07a: aload 1 + // 07b: ldc 98 + // 07d: aaload + // 07e: aload 1 + // 07f: ldc_w 99 + // 082: aaload + // 083: ldc java/lang/System + // 085: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 08a: aload 3 + // 08b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 090: pop + // 091: nop + // 092: return + // 093: athrow + // 094: nop + // 095: nop + // 096: athrow + // 097: aload 1 + // 098: ldc_w 100 + // 09b: aaload + // 09c: aload 1 + // 09d: ldc_w 101 + // 0a0: aaload + // 0a1: ldc java/lang/System + // 0a3: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0a8: aload 4 + // 0aa: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0af: pop + // 0b0: goto 0d1 + // 0b3: astore 6 + // 0b5: aload 1 + // 0b6: ldc_w 102 + // 0b9: aaload + // 0ba: aload 1 + // 0bb: ldc_w 103 + // 0be: aaload + // 0bf: ldc java/lang/System + // 0c1: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0c6: aload 4 + // 0c8: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0cd: pop + // 0ce: aload 6 + // 0d0: athrow + // 0d1: nop + // 0d2: goto 0d5 + // 0d5: aload 1 + // 0d6: ldc_w 104 + // 0d9: aaload + // 0da: aload 1 + // 0db: ldc_w 105 + // 0de: aaload + // 0df: ldc java/lang/System + // 0e1: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 0e6: aload 3 + // 0e7: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 0ec: pop + // 0ed: goto 10d + // 0f0: astore 7 + // 0f2: aload 1 + // 0f3: ldc_w 106 + // 0f6: aaload + // 0f7: aload 1 + // 0f8: ldc_w 107 + // 0fb: aaload + // 0fc: ldc java/lang/System + // 0fe: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 103: aload 3 + // 104: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 109: pop + // 10a: aload 7 + // 10c: athrow + // 10d: return + // try (41 -> 53): 53 java/lang/Exception + // try (41 -> 53): 96 null + // try (53 -> 55): 96 null + // try (79 -> 80): 96 null + // try (11 -> 24): 40 java/lang/Exception + // try (36 -> 37): 40 java/lang/Exception + // try (11 -> 24): 124 null + // try (36 -> 37): 124 null + // try (40 -> 67): 124 null + // try (79 -> 80): 124 null + // try (84 -> 111): 124 null + } + + public void returnInCatch() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 1 + // 05: aload 1 + // 06: ldc_w 108 + // 09: aaload + // 0a: aload 1 + // 0b: ldc_w 109 + // 0e: aaload + // 0f: ldc java/lang/System + // 11: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 16: ldc "Hi!" + // 18: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 1d: pop + // 1e: goto 5d + // 21: astore 2 + // 22: aload 1 + // 23: ldc_w 110 + // 26: aaload + // 27: aload 1 + // 28: ldc_w 111 + // 2b: aaload + // 2c: ldc java/lang/System + // 2e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 33: ldc_w "hello" + // 36: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 3b: pop + // 3c: nop + // 3d: aload 1 + // 3e: ldc_w 112 + // 41: aaload + // 42: aload 1 + // 43: ldc_w 113 + // 46: aaload + // 47: ldc java/lang/System + // 49: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 4e: ldc_w "finally" + // 51: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 56: pop + // 57: nop + // 58: return + // 59: athrow + // 5a: nop + // 5b: nop + // 5c: athrow + // 5d: aload 1 + // 5e: ldc_w 114 + // 61: aaload + // 62: aload 1 + // 63: ldc_w 115 + // 66: aaload + // 67: ldc java/lang/System + // 69: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 6e: ldc_w "finally" + // 71: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 76: pop + // 77: goto 97 + // 7a: astore 3 + // 7b: aload 1 + // 7c: ldc_w 116 + // 7f: aaload + // 80: aload 1 + // 81: ldc_w 117 + // 84: aaload + // 85: ldc java/lang/System + // 87: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 8c: ldc_w "finally" + // 8f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 94: pop + // 95: aload 3 + // 96: athrow + // 97: aload 1 + // 98: ldc_w 118 + // 9b: aaload + // 9c: aload 1 + // 9d: ldc_w 119 + // a0: aaload + // a1: ldc java/lang/System + // a3: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // a8: ldc_w "post" + // ab: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // b0: pop + // b1: return + // try (3 -> 15): 15 java/lang/Exception + // try (3 -> 15): 57 null + // try (15 -> 28): 57 null + // try (40 -> 41): 57 null + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } + + static { + __$swapInit(); + } +} + +class 'pkg/TestGroovyTryReturn' { + method ' ()V' { + 1 15 + 2 15 + 3 15 + 4 15 + 6 16 + 7 16 + 8 16 + 9 17 + a 17 + b 17 + c 17 + d 17 + e 18 + f 18 + 11 18 + 12 18 + 13 18 + 16 19 + } + + method 'testFinally2 (Ljava/util/function/Supplier;)Z' { + 1 243 + 2 243 + 3 243 + 4 243 + 5 244 + 6 244 + 7 244 + a 249 + b 249 + c 249 + d 249 + e 249 + f 249 + 10 249 + 11 249 + 12 249 + 13 249 + 14 249 + 15 249 + 16 250 + 17 250 + 18 250 + 19 250 + 1a 250 + 1b 250 + 22 258 + 23 258 + 24 258 + 25 258 + 26 258 + 27 258 + 28 258 + 29 258 + 2a 258 + 2b 258 + 2c 258 + 2d 258 + 2e 258 + 2f 258 + 30 258 + 31 258 + 32 258 + 33 258 + 34 258 + 35 258 + 36 258 + 37 258 + 3e 254 + 3f 254 + 40 254 + 41 254 + 42 254 + 43 254 + 44 254 + 45 254 + 46 254 + 47 254 + 48 254 + 49 254 + 4a 254 + 4b 254 + 4c 254 + 4d 254 + 4e 254 + 4f 254 + 50 254 + 51 254 + 52 254 + 53 254 + 58 259 + 59 259 + } + + method 'testFinally4 (Ljava/util/function/Supplier;)Z' { + 1 451 + 2 451 + 3 451 + 4 451 + 5 452 + 6 452 + 9 457 + a 457 + b 457 + c 457 + d 457 + e 457 + f 457 + 10 457 + 11 457 + 12 457 + 13 457 + 14 457 + 15 458 + 16 458 + 17 458 + 18 458 + 19 458 + 1a 458 + 21 466 + 22 466 + 23 466 + 24 466 + 25 466 + 26 466 + 27 466 + 28 466 + 29 466 + 2a 466 + 2b 466 + 2c 466 + 2d 466 + 2e 466 + 2f 466 + 30 466 + 31 466 + 32 466 + 33 466 + 34 466 + 35 466 + 36 466 + 3d 462 + 3e 462 + 3f 462 + 40 462 + 41 462 + 42 462 + 43 462 + 44 462 + 45 462 + 46 462 + 47 462 + 48 462 + 49 462 + 4a 462 + 4b 462 + 4c 462 + 4d 462 + 4e 462 + 4f 462 + 50 462 + 51 462 + 52 462 + 57 467 + 58 467 + } + + method 'testFinally5 (Ljava/util/function/Supplier;)Z' { + 1 472 + 2 472 + 3 472 + 4 472 + 5 473 + 6 473 + 9 478 + a 478 + b 478 + c 478 + d 478 + e 478 + f 478 + 10 478 + 11 478 + 12 478 + 13 478 + 14 478 + 15 479 + 16 479 + 17 479 + 18 479 + 19 479 + 1a 479 + 21 481 + 23 482 + 24 482 + 25 482 + 26 482 + 27 482 + 28 482 + 29 482 + 2a 482 + 2b 482 + 2c 482 + 2d 482 + 2e 482 + 2f 482 + 30 482 + 31 482 + 32 482 + 33 482 + 34 482 + 35 482 + 36 482 + 37 482 + 38 482 + 3a 483 + 3b 483 + 3c 483 + 3d 483 + 3e 483 + 3f 483 + 40 483 + 41 483 + 42 483 + 43 483 + 44 483 + 45 483 + 46 484 + 47 484 + 48 484 + 49 484 + 4a 484 + 4b 484 + 53 492 + 54 492 + 55 492 + 56 492 + 57 492 + 58 492 + 59 492 + 5a 492 + 5b 492 + 5c 492 + 5d 492 + 5e 492 + 5f 492 + 60 492 + 61 492 + 62 492 + 63 492 + 64 492 + 65 492 + 66 492 + 67 492 + 68 492 + 6f 488 + 70 488 + 71 488 + 72 488 + 73 488 + 74 488 + 75 488 + 76 488 + 77 488 + 78 488 + 79 488 + 7a 488 + 7b 488 + 7c 488 + 7d 488 + 7e 488 + 7f 488 + 80 488 + 81 488 + 82 488 + 83 488 + 84 488 + 89 493 + 8a 493 + } + + method 'testFinally6 (ZLjava/util/function/Supplier;)Z' { + 1 498 + 2 498 + 3 498 + 4 498 + 5 499 + 6 499 + 7 499 + b 504 + c 504 + d 504 + e 504 + f 505 + 10 505 + 11 505 + 19 506 + 1a 506 + 1b 506 + 1c 506 + 1d 506 + 1e 506 + 1f 506 + 20 506 + 21 506 + 22 506 + 23 506 + 24 506 + 25 506 + 26 506 + 27 506 + 28 506 + 29 506 + 2a 506 + 2b 506 + 2c 506 + 2d 506 + 2e 506 + 30 509 + 31 509 + 32 509 + 33 509 + 34 509 + 35 509 + 36 509 + 37 509 + 38 509 + 39 509 + 3a 509 + 3b 509 + 3c 510 + 3d 510 + 3e 510 + 3f 510 + 40 510 + 41 510 + 42 510 + 49 512 + 4b 513 + 4c 513 + 4d 513 + 4e 513 + 4f 513 + 50 513 + 51 513 + 52 513 + 53 513 + 54 513 + 55 513 + 56 513 + 57 513 + 58 513 + 59 513 + 5a 513 + 5b 513 + 5c 513 + 5d 513 + 5e 513 + 5f 513 + 60 513 + 62 514 + 63 514 + 64 514 + 65 514 + 66 514 + 67 514 + 68 514 + 69 514 + 6a 514 + 6b 514 + 6c 514 + 6d 514 + 6e 515 + 6f 515 + 70 515 + 71 515 + 72 515 + 73 515 + 74 515 + 7c 523 + 7d 523 + 7e 523 + 7f 523 + 80 523 + 81 523 + 82 523 + 83 523 + 84 523 + 85 523 + 86 523 + 87 523 + 88 523 + 89 523 + 8a 523 + 8b 523 + 8c 523 + 8d 523 + 8e 523 + 8f 523 + 90 523 + 91 523 + 98 519 + 99 519 + 9a 519 + 9b 519 + 9c 519 + 9d 519 + 9e 519 + 9f 519 + a0 519 + a1 519 + a2 519 + a3 519 + a4 519 + a5 519 + a6 519 + a7 519 + a8 519 + a9 519 + aa 519 + ab 519 + ac 519 + ad 519 + b2 524 + b3 524 + b4 524 + } + + method 'testPostdomFailure ()V' { + 1 690 + 2 690 + 3 690 + 4 690 + 5 691 + 6 691 + 9 692 + a 692 + b 692 + c 692 + d 692 + e 692 + f 692 + 10 692 + 11 692 + 12 692 + 13 692 + 14 692 + 15 692 + 16 692 + 17 692 + 18 692 + 19 692 + 1a 692 + 1b 692 + 1c 692 + 1d 692 + 1e 692 + 1f 692 + 20 692 + 22 694 + 23 694 + 24 694 + 25 694 + 26 694 + 27 694 + 28 694 + 29 694 + 2a 694 + 2b 694 + 2c 694 + 2d 694 + 2e 694 + 2f 694 + 30 694 + 31 694 + 32 694 + 33 694 + 34 694 + 35 694 + 36 694 + 37 694 + 38 694 + 3c 697 + 3d 697 + 3e 697 + 3f 697 + 40 697 + 41 697 + 42 697 + 43 697 + 44 697 + 45 697 + 46 697 + 47 697 + 48 697 + 49 697 + 4a 697 + 4b 697 + 4c 697 + 4d 697 + 4e 697 + 4f 697 + 50 697 + 51 697 + 52 697 + 53 697 + 58 698 + 59 699 + 5a 699 + 5b 699 + 5c 699 + 5d 699 + 5e 699 + 5f 699 + 60 699 + 61 699 + 62 699 + 63 699 + 64 699 + 65 699 + 66 699 + 67 699 + 68 699 + 69 699 + 6a 699 + 6b 699 + 6c 699 + 6d 699 + 6e 699 + 6f 699 + 70 699 + c1 704 + c2 704 + c3 704 + c4 704 + c5 704 + cf 707 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 1040 + 1 1040 + 2 1040 + 3 1040 + 5 1040 + 6 1040 + 7 1040 + 8 1041 + a 1044 + c 1044 + d 1044 + e 1044 + f 1044 + 10 1044 + 11 1044 + 12 1045 + 13 1045 + 14 1045 + 15 1045 + 16 1045 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 1051 + 1 1051 + 2 1051 + 3 1051 + 4 1051 + 5 1052 + } + + method ' ()V' { + 0 1055 + 1 1055 + 2 1055 + 3 1056 + } +} + +Lines mapping: +38 <-> 245 +39 <-> 250 +40 <-> 250 +42 <-> 255 +45 <-> 260 +65 <-> 453 +66 <-> 458 +67 <-> 458 +69 <-> 463 +72 <-> 468 +76 <-> 474 +77 <-> 479 +78 <-> 479 +79 <-> 482 +80 <-> 483 +81 <-> 484 +83 <-> 489 +86 <-> 494 +90 <-> 500 +91 <-> 505 +92 <-> 505 +93 <-> 506 +94 <-> 507 +95 <-> 510 +97 <-> 510 +98 <-> 513 +99 <-> 514 +100 <-> 515 +102 <-> 520 +105 <-> 525 +154 <-> 692 +155 <-> 693 +157 <-> 695 +158 <-> 698 +159 <-> 698 +160 <-> 698 +161 <-> 699 +162 <-> 700 +168 <-> 705 +170 <-> 708 +Not mapped: +41 +43 +68 +70 +82 +84 +101 +103 +163 +164 +165 +166 +167 +169 diff --git a/testData/results/pkg/TestGroovyTrySplit.dec b/testData/results/pkg/TestGroovyTrySplit.dec new file mode 100644 index 0000000000..69892d76f8 --- /dev/null +++ b/testData/results/pkg/TestGroovyTrySplit.dec @@ -0,0 +1,406 @@ +package pkg; + +import groovy.lang.GroovyObject; +import groovy.lang.MetaClass; +import groovy.transform.Generated; +import groovy.transform.Internal; +import java.beans.Transient; +import org.codehaus.groovy.runtime.ScriptBytecodeAdapter; +import org.codehaus.groovy.runtime.callsite.CallSite; + +public class TestGroovyTrySplit implements GroovyObject { + @Generated + public TestGroovyTrySplit() { + CallSite[] var1 = $getCallSiteArray(); + super(); + MetaClass var2 = this.$getStaticMetaClass(); + this.metaClass = var2; + } + + public void test() { + // $VF: Couldn't be decompiled + // Bytecode: + // 00: nop + // 01: invokestatic pkg/TestGroovyTrySplit.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; + // 04: astore 1 + // 05: aconst_null + // 06: astore 2 + // 07: aload 2 + // 08: pop + // 09: aload 1 + // 0a: ldc 0 + // 0c: aaload + // 0d: ldc java/lang/Object + // 0f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callConstructor (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 14: astore 3 + // 15: aload 3 + // 16: astore 2 + // 17: aload 3 + // 18: pop + // 19: goto 72 + // 1c: astore 4 + // 1e: aload 2 + // 1f: aconst_null + // 20: invokestatic org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareNotEqual (Ljava/lang/Object;Ljava/lang/Object;)Z + // 23: ifeq 3d + // 26: aload 1 + // 27: ldc 1 + // 29: aaload + // 2a: aload 1 + // 2b: ldc 2 + // 2d: aaload + // 2e: ldc java/lang/System + // 30: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 35: ldc "a" + // 37: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 3c: pop + // 3d: aload 1 + // 3e: ldc 3 + // 40: aaload + // 41: ldc pkg/TestGroovyTrySplit + // 43: aload 1 + // 44: ldc 4 + // 46: aaload + // 47: aload 4 + // 49: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 4e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callStatic (Ljava/lang/Class;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 53: pop + // 54: nop + // 55: aload 1 + // 56: ldc 5 + // 58: aaload + // 59: aload 1 + // 5a: ldc 6 + // 5c: aaload + // 5d: ldc java/lang/System + // 5f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 64: ldc "b" + // 66: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 6b: pop + // 6c: nop + // 6d: return + // 6e: athrow + // 6f: nop + // 70: nop + // 71: athrow + // 72: aload 1 + // 73: ldc 7 + // 75: aaload + // 76: aload 1 + // 77: ldc 8 + // 79: aaload + // 7a: ldc java/lang/System + // 7c: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 81: ldc "b" + // 83: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // 88: pop + // 89: goto a8 + // 8c: astore 5 + // 8e: aload 1 + // 8f: ldc 9 + // 91: aaload + // 92: aload 1 + // 93: ldc 10 + // 95: aaload + // 96: ldc java/lang/System + // 98: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 + // 9d: ldc "b" + // 9f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 + // a4: pop + // a5: aload 5 + // a7: athrow + // a8: return + // try (7 -> 18): 18 java/lang/ArithmeticException + // try (7 -> 18): 75 null + // try (18 -> 46): 75 null + // try (58 -> 59): 75 null + } + + public void testFlat() { + CallSite[] var1 = $getCallSiteArray(); + Object obj = null;// 21 + + try { + try { + label91: { + try { + Object var3 = var1[11].callConstructor(Object.class);// 24 25 26 27 + obj = var3; + break label91;// 28 + } catch (ArithmeticException ex) { + if (ScriptBytecodeAdapter.compareNotEqual(obj, null)) {// 29 + var1[12].call(var1[13].callGetProperty(System.class), "a");// 30 + } + } + + var1[14].callStatic(TestGroovyTrySplit.class, var1[15].call(ex));// 31 33 + } + } finally { + ; + } + } catch (Throwable t) {// 37 + var1[16].call(var1[17].callGetProperty(System.class), "b");// 38 + throw (Throwable)t;// 39 + } finally { + ; + } + + var1[18].call(var1[19].callGetProperty(System.class), "b");// 42 + }// 43 + + public static void throwMyException(String message) { + CallSite[] var1 = $getCallSiteArray(); + throw (Throwable)var1[22].callConstructor(RuntimeException.class, message);// 49 + } + + @Generated + @Internal + @Transient + public MetaClass getMetaClass() { + if (this.metaClass != null) { + return this.metaClass; + } + + this.metaClass = this.$getStaticMetaClass(); + return this.metaClass; + } + + @Generated + @Internal + public void setMetaClass(MetaClass var1) { + this.metaClass = var1; + } +} + +class 'pkg/TestGroovyTrySplit' { + method ' ()V' { + 1 13 + 2 13 + 3 13 + 4 13 + 6 14 + 7 14 + 8 14 + 9 15 + a 15 + b 15 + c 15 + d 15 + e 16 + f 16 + 11 16 + 12 16 + 13 16 + 16 17 + } + + method 'testFlat ()V' { + 1 119 + 2 119 + 3 119 + 4 119 + 5 120 + 6 120 + 9 126 + a 126 + b 126 + c 126 + d 126 + e 126 + f 126 + 10 126 + 11 126 + 12 126 + 13 126 + 14 126 + 15 127 + 16 127 + 19 128 + 1c 129 + 1e 130 + 1f 130 + 20 130 + 21 130 + 22 130 + 23 130 + 24 130 + 25 130 + 26 131 + 27 131 + 28 131 + 29 131 + 2a 131 + 2b 131 + 2c 131 + 2d 131 + 2e 131 + 2f 131 + 30 131 + 31 131 + 32 131 + 33 131 + 34 131 + 35 131 + 36 131 + 37 131 + 38 131 + 39 131 + 3a 131 + 3b 131 + 3d 135 + 3e 135 + 3f 135 + 40 135 + 41 135 + 42 135 + 43 135 + 44 135 + 45 135 + 46 135 + 47 135 + 48 135 + 49 135 + 4a 135 + 4b 135 + 4c 135 + 4d 135 + 4e 135 + 4f 135 + 50 135 + 51 135 + 52 135 + 6e 140 + 70 141 + 71 141 + 72 141 + 73 141 + 74 141 + 75 141 + 76 141 + 77 141 + 78 141 + 79 141 + 7a 141 + 7b 141 + 7c 141 + 7d 141 + 7e 141 + 7f 141 + 80 141 + 81 141 + 82 141 + 83 141 + 84 141 + 85 141 + 87 142 + 88 142 + 89 142 + 8a 142 + 8b 142 + 8c 142 + 9f 147 + a0 147 + a1 147 + a2 147 + a3 147 + a4 147 + a5 147 + a6 147 + a7 147 + a8 147 + a9 147 + aa 147 + ab 147 + ac 147 + ad 147 + ae 147 + af 147 + b0 147 + b1 147 + b2 147 + b3 147 + b4 147 + b6 148 + } + + method 'throwMyException (Ljava/lang/String;)V' { + 1 151 + 2 151 + 3 151 + 4 151 + 5 152 + 6 152 + 7 152 + 8 152 + 9 152 + a 152 + b 152 + c 152 + d 152 + e 152 + f 152 + 10 152 + 11 152 + 12 152 + 13 152 + 14 152 + } + + method 'getMetaClass ()Lgroovy/lang/MetaClass;' { + 0 159 + 1 159 + 2 159 + 3 159 + 5 159 + 6 159 + 7 159 + 8 160 + a 163 + c 163 + d 163 + e 163 + f 163 + 10 163 + 11 163 + 12 164 + 13 164 + 14 164 + 15 164 + 16 164 + } + + method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { + 0 170 + 1 170 + 2 170 + 3 170 + 4 170 + 5 171 + } +} + +Lines mapping: +21 <-> 121 +24 <-> 127 +25 <-> 127 +26 <-> 127 +27 <-> 127 +28 <-> 129 +29 <-> 131 +30 <-> 132 +31 <-> 136 +33 <-> 136 +37 <-> 141 +38 <-> 142 +39 <-> 143 +42 <-> 148 +43 <-> 149 +49 <-> 153 +Not mapped: +34 +35 +36 +40 +41 +44 +45 diff --git a/testData/src/groovy/pkg/TestGroovyFinallyBlockVariableUse.groovy b/testData/src/groovy/pkg/TestGroovyFinallyBlockVariableUse.groovy new file mode 100644 index 0000000000..47099ac95d --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyFinallyBlockVariableUse.groovy @@ -0,0 +1,33 @@ +package pkg; + +public class TestGroovyFinallyBlockVariableUse { + public int test(String s, int i, int j) { + System.out.println("a"); + try { + System.out.println("b"); + try { + i = Integer.parseInt(s) - j; + + return i; + + } catch (NumberFormatException e) { + i = j; + throw e; + } + } finally { + int id = i - j; + if (id > 0) { + + accept(new Object[]{id, s, i, j}); + } + } + } + + private boolean condition(int i) { + return i-- > 0; + } + + private void accept(Object[] args) { + + } +} diff --git a/testData/src/groovy/pkg/TestGroovyFinallyThrow.groovy b/testData/src/groovy/pkg/TestGroovyFinallyThrow.groovy new file mode 100644 index 0000000000..547b1922ed --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyFinallyThrow.groovy @@ -0,0 +1,45 @@ +package pkg; + +public class TestGroovyFinallyThrow { + public void test(boolean b) { + while (true) { + try { + System.out.println(1); + } finally { + try { + if (b) { + return; + } + } catch (Exception e) { + throw e; + } finally { + System.out.println(2); + } + } + } + } + + public void test1(RuntimeException t) { + try { + System.out.println(1); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + throw t; + } + } + + // test1 decompiles as this: + public void test2(RuntimeException t) { + try { + System.out.println(1); + throw t; + } catch (Throwable e) { + e.printStackTrace(); + } finally { + + } + + throw t; + } +} diff --git a/testData/src/groovy/pkg/TestGroovyFinallyVarDef.groovy b/testData/src/groovy/pkg/TestGroovyFinallyVarDef.groovy new file mode 100644 index 0000000000..a2592684b8 --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyFinallyVarDef.groovy @@ -0,0 +1,25 @@ +package pkg; + +public class TestGroovyFinallyVarDef { + public void test1() { + int i; + try { + System.out.println("a"); + } finally { + i = 5; + } + + System.out.println(i); + } + + public void test2() { + int i = 2; + try { + System.out.println("a"); + } finally { + i = 5; + } + + System.out.println(i); + } +} diff --git a/testData/src/groovy/pkg/TestGroovyTryCatchFinally.groovy b/testData/src/groovy/pkg/TestGroovyTryCatchFinally.groovy new file mode 100644 index 0000000000..f4a92d3bfe --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTryCatchFinally.groovy @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pkg; + +public class TestGroovyTryCatchFinally { + public void test1(String x) { + try { + System.out.println("sout1"); + } catch (Exception e) { + try { + System.out.println("sout2"); + } catch (Exception e2) { + // Empty + // Empty + // Empty + } + } finally { + System.out.println("finally"); + } + } + + int foo(int a) throws Exception { + if (a < 1) { + throw new RuntimeException(); + } else if ( a <5) { + return a; + } + else { + throw new Exception(); + } + } + + public int test(String a) { + try { + return Integer.parseInt(a); + } catch (Exception e) { + System.out.println("Error" + e); + } finally { + System.out.println("Finally"); + } + return -1; + } + + void testEmptyCatch(String msg) { + try { + System.out.println(msg); + } catch (RuntimeException ignored){ + } finally { + System.out.println("Bye"); + } + } +} \ No newline at end of file diff --git a/testData/src/groovy/pkg/TestGroovyTryFinally.groovy b/testData/src/groovy/pkg/TestGroovyTryFinally.groovy new file mode 100644 index 0000000000..22ef0b035b --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTryFinally.groovy @@ -0,0 +1,36 @@ +package pkg; + +public class TestGroovyTryFinally { + public void test0() { + try { + System.out.println("Hello"); + } finally { + long l = 5; + } + } + + public void test1() { + try { + System.out.println("Hello"); + } finally { + System.out.println("Finally"); + } + + System.out.println("Bye"); + } + + + public void test2(int i) { + try { + System.out.println("Hello"); + } finally { + System.out.println("Finally"); + if(i > 0) { + System.out.println(i); + return; + } + } + + System.out.println("Bye"); + } +} diff --git a/testData/src/groovy/pkg/TestGroovyTryLoopReturnFinally.groovy b/testData/src/groovy/pkg/TestGroovyTryLoopReturnFinally.groovy new file mode 100644 index 0000000000..c1e3878d54 --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTryLoopReturnFinally.groovy @@ -0,0 +1,21 @@ +package pkg + +public class TestGroovyTryLoopReturnFinally { + private boolean field; + + public void test(File file) { + try { + while (this.field) { + if (file == null) { + return; + } + + Scanner scanner = new Scanner(file); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + System.out.println("Finally"); + } + } +} diff --git a/testData/src/groovy/pkg/TestGroovyTryLoopSimpleFinally.groovy b/testData/src/groovy/pkg/TestGroovyTryLoopSimpleFinally.groovy new file mode 100644 index 0000000000..321d560c59 --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTryLoopSimpleFinally.groovy @@ -0,0 +1,37 @@ +package pkg + + +import java.nio.file.Path + +public class TestGroovyTryLoopSimpleFinally { + private boolean field; + + public void test(File file) { + try { + while (this.field) { + Scanner scanner = new Scanner(file); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + System.out.println("Finally"); + } + } + + public void test2(int x, Path file) throws IOException { + try { + while (x >= 0) { + Scanner scanner = new Scanner(file); + + if (x % 11 == 0) { + System.out.println("nice"); + return; + } + + x -= scanner.nextInt(); + } + } finally { + System.out.println("Finally"); + } + } +} diff --git a/testData/src/groovy/pkg/TestGroovyTryReturn.groovy b/testData/src/groovy/pkg/TestGroovyTryReturn.groovy new file mode 100644 index 0000000000..e7ac730f06 --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTryReturn.groovy @@ -0,0 +1,222 @@ +package pkg + + +import java.util.function.Supplier; + +public class TestGroovyTryReturn { + public boolean test(Supplier supplier) { + try { + return supplier.get(); + } catch (Exception var3) { + throw new RuntimeException(var3); + } + } + + public boolean testFinally(Supplier supplier) { + try { + return supplier.get(); + } finally { + System.out.println("Finally"); + } + } + + public void testFinally1(Supplier supplier) { + System.out.println("pred"); + + try { + if (supplier.get()) { + return; + } + } finally { + System.out.println("Finally"); + } + + System.out.println("suc"); + } + + public boolean testFinally2(Supplier supplier) { + boolean b; + try { + b = supplier.get(); + } finally { + System.out.println("Finally"); + } + + return b; + } + + public boolean testFinally3(boolean b, boolean c, int a, Supplier supplier) { + try { + if (b) { + return c && supplier.get(); + } + + if (a > 0) { + return a == 1; + } + + return supplier.get(); + } finally { + System.out.println("Finally"); + } + } + + public boolean testFinally4(Supplier supplier) { + boolean b = false; + try { + b = supplier.get(); + } finally { + System.out.println("Finally"); + } + + return b; + } + + public boolean testFinally5(Supplier supplier) { + boolean b = false; + try { + b = supplier.get(); + } catch (Exception e) { + System.out.println("Catch"); + b = supplier.get(); + } finally { + System.out.println("Finally"); + } + + return b; + } + + public boolean testFinally6(boolean a, Supplier supplier) { + boolean b = false; + try { + if (a) { + b = true; + System.out.println("If"); + } + + b = supplier.get(); + } catch (Exception e) { + System.out.println("Catch"); + b = supplier.get(); + } finally { + System.out.println("Finally"); + } + + return b; + } + + public void testLoopFinally() { + boolean a = true; + + while (true) { + try { + if (a) { + return; + } + } finally { + System.out.println("Finally"); + } + } + } + +// public void testParsingFailure() { // Errors out the groovy compiler +// char var1 = 't'; +// try { +// if (var1 != 'q') { +// try { +// System.out.println(var1); +// } catch (Exception var6) { +// return; +// } finally { +// return; +// } +// } +// } finally { +// System.out.println(var1); +// return; +// } +// } + + public void testParsingFailureSimple() { + try { + try { + System.out.println("inner"); + } finally { + return; + } + } finally { + System.out.println("fin"); + } + } + + public void testPostdomFailure() { + // Load bearing useless string- removing this makes vf emit a parsing error??? + String var1; + System.out.println(1); + label: + while (new Random().nextBoolean()) { + try { + try { + System.out.println(2); + } catch (Exception var9) { + System.out.println(3); + return; + } finally { + continue label; + } + } finally { + byte var10 = 28; + } + } + } + + public void testVarWrong() { + int var1; + try { + System.out.println("Hi"); + } catch (Exception var2) { + if (var2 != null) { + return; + } else { + System.out.println(var2); + return; + } + } finally { + float var3 = 9.18F; + } + } + + public void testInvalidUse() { + boolean var1 = false; + String var3 = "Hi!"; + try { + System.out.println(var1); + return; + } catch (Exception var4) { + try { + System.out.println(var4); + } catch (Exception var5) { + return; + } finally { + // Unable to correctly guess this is var4 + System.out.println(var4); + } + } finally { + // The finally here causes the issue + System.out.println(var3); + } + } + + public void returnInCatch() { + try { + System.out.println("Hi!"); + } catch (Exception e) { + System.out.println("hello"); + return; + } finally { + System.out.println("finally"); + } + + System.out.println("post"); + } +} diff --git a/testData/src/groovy/pkg/TestGroovyTrySplit.groovy b/testData/src/groovy/pkg/TestGroovyTrySplit.groovy new file mode 100644 index 0000000000..b516e7307c --- /dev/null +++ b/testData/src/groovy/pkg/TestGroovyTrySplit.groovy @@ -0,0 +1,51 @@ +package pkg; + +public class TestGroovyTrySplit { + public void test() { + Object obj = null; + try { + obj = new Object(); + } catch (ArithmeticException ex) { + if (obj != null) { + System.out.println("a"); + } + + throwMyException(ex.getMessage()); + return; + } finally { + System.out.println("b"); + } + } + + public void testFlat() { + Object obj = null; + b1: + { + b2: do { // groovy only allows labeled breaks if it's inside a loop? + try { + try { + obj = new Object(); + } catch (ArithmeticException ex) { + if (obj != null) { + System.out.println("a"); + } + + throwMyException(ex.getMessage()); + break b2; + } + break b1; + } catch (Throwable t) { + System.out.println("b"); + throw t; + } + }while(false) + System.out.println("b"); + return; + } + System.out.println("b"); + } + + public static void throwMyException(String message) { + throw new RuntimeException(message); + } +} From 4810c360610cf7716950273107905ab520f26955 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:04:08 -0400 Subject: [PATCH 15/29] Fix crash in eclipse switch on string, add new tests --- .../modules/decompiler/SwitchHelper.java | 8 +- .../java/decompiler/SingleClassesTest.java | 1 + .../TestEclipseSwitchString2$Inner.class | Bin 0 -> 435 bytes .../custom/TestEclipseSwitchString2.class | Bin 0 -> 1019 bytes .../source/TestEclipseSwitchString2.java | 50 ++++ testData/results/TestEclipseSwitchString2.dec | 274 ++++++++++++++++++ 6 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 testData/classes/custom/TestEclipseSwitchString2$Inner.class create mode 100644 testData/classes/custom/TestEclipseSwitchString2.class create mode 100644 testData/classes/custom/source/TestEclipseSwitchString2.java create mode 100644 testData/results/TestEclipseSwitchString2.dec diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java index f2ece90fd0..0aa6e0f493 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java @@ -426,8 +426,12 @@ private static void mergeDuplicateCaseStats(StringSwitch switchInfo) { } Exprent realExpr = assignment.getRight(); - VarExprent headVar = (VarExprent) (switchHead.getValue() instanceof InvocationExprent val - ? val.getInstance() : switchHead.getValue()); + Exprent headEx = switchHead.getValue() instanceof InvocationExprent val + ? val.getInstance() : switchHead.getValue(); + + if (!(headEx instanceof VarExprent headVar)) { + return null; + } // If the dup var is not in the switch head, // and the dup var is referenced somewhere else other than the switch head... diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 44884dd4b6..3617a0843b 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -599,6 +599,7 @@ private void registerDefault() { register(JAVA_8, "TestWhile1"); registerRaw(CUSTOM, "TestEclipseSwitchEnum"); registerRaw(CUSTOM, "TestEclipseSwitchString"); + registerRaw(CUSTOM, "TestEclipseSwitchString2"); registerRaw(CUSTOM, "TestStringConcatJ19"); register(JAVA_8, "TestNestedAnonymousClass"); // TODO: ppmm not created in test4-5 diff --git a/testData/classes/custom/TestEclipseSwitchString2$Inner.class b/testData/classes/custom/TestEclipseSwitchString2$Inner.class new file mode 100644 index 0000000000000000000000000000000000000000..ab390d86f5be28461effb84d43454db751d7ace5 GIT binary patch literal 435 zcmaJ-yH3ME5S)!;J2nmpA<#ey5Jf_PB}50Ji9kY%pm3D_Y)%mRm`djL zhoi}t+UKd`7FG!$_zan;+>|2YCR&tvBF|Mt9{lC4Ey3P@M(c?S_QSDSg8?2^5O7^Vx9S-S^xBUzF`D=QK9Y&Xe@`oTh+dh@T5Ipwv)2B-W z1fuE8ra)|Ue_L6IB4NXTX`)L2oe(%;aC{Nkb$!Tsei#tuKB*I**FJDZ50(*7{;i9kzWv77&gW*E@19B z^&PE0gjq9@oJW*@1xKTYLLcRtZg={CjW}+_a$iCux3~a48asCze8#MiXo|dE)XtT5h+EPwlXd?9zV+~|;aw=R8 zH87Tw>2NI@kTP3rz?M1s4mnqxdBemAw44-Gg94)H!(9xZ#J+7}2wR-|BaZF~#&L;X z^uhRwoPl9Ji9{kE{}MvZpJ;EkwR_b55rbRDC^WHff`EH0@`EA8wPu*3X@=$h!7#z{ qlemv5Jj65}BLfFnY$JyX2~HRme`AQ?3Kc|f71tOoPGXR@gwF3VFuZF3 literal 0 HcmV?d00001 diff --git a/testData/classes/custom/source/TestEclipseSwitchString2.java b/testData/classes/custom/source/TestEclipseSwitchString2.java new file mode 100644 index 0000000000..0d713b0ef3 --- /dev/null +++ b/testData/classes/custom/source/TestEclipseSwitchString2.java @@ -0,0 +1,50 @@ +package pkg; + +// Compiled with ecj 3.45.0 +public class TestEclipseSwitchString2 { + String field = ""; + + public static class Inner { + public static String get() { + return ""; + } + + public String getVirtual() { + return ""; + } + } + + public String testInvokeStatic() { + String s = "a"; + switch (Inner.get()) { + case "1": + s = "b"; + break; + case "2": + s = "c"; + break; + case "3": + s = "d"; + break; + } + + return s; + } + + public String testInvokeVirtual() { + String s = "a"; + switch (new Inner().getVirtual()) { + case "1": + s = "b"; + break; + case "2": + s = "c"; + break; + case "3": + s = "d"; + break; + } + + return s; + } +} diff --git a/testData/results/TestEclipseSwitchString2.dec b/testData/results/TestEclipseSwitchString2.dec new file mode 100644 index 0000000000..1156a2159c --- /dev/null +++ b/testData/results/TestEclipseSwitchString2.dec @@ -0,0 +1,274 @@ +package pkg; + +public class TestEclipseSwitchString2 { + String field = "";// 5 + + public String testInvokeStatic() { + String var1 = "a";// 18 + String var2; + switch ((var2 = TestEclipseSwitchString2.Inner.get()).hashCode()) {// 19 + case 49: + if (var2.equals("1")) { + var1 = "b";// 21 + } + break; + case 50: + if (var2.equals("2")) { + var1 = "c";// 24 + } + break; + case 51: + if (var2.equals("3")) { + var1 = "d";// 27 + } + } + + return var1;// 31 + } + + public String testInvokeVirtual() { + String var1 = "a";// 35 + String var2; + switch ((var2 = new TestEclipseSwitchString2.Inner().getVirtual()).hashCode()) {// 36 + case 49: + if (var2.equals("1")) { + var1 = "b";// 38 + } + break; + case 50: + if (var2.equals("2")) { + var1 = "c";// 41 + } + break; + case 51: + if (var2.equals("3")) { + var1 = "d";// 44 + } + } + + return var1;// 48 + } + + public static class Inner { + public static String get() { + return "";// 9 + } + + public String getVirtual() { + return "";// 13 + } + } +} + +class 'pkg/TestEclipseSwitchString2' { + method ' ()V' { + 5 3 + 6 3 + } + + method 'testInvokeStatic ()Ljava/lang/String;' { + 0 6 + 1 6 + 2 6 + 3 8 + 4 8 + 5 8 + 7 8 + 8 8 + 9 8 + a 8 + b 8 + c 8 + d 8 + e 8 + f 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 8 + 15 8 + 16 8 + 17 8 + 18 8 + 19 8 + 1a 8 + 1b 8 + 1c 8 + 1d 8 + 1e 8 + 1f 8 + 20 8 + 21 8 + 22 8 + 23 8 + 24 8 + 25 8 + 26 8 + 27 8 + 28 8 + 29 8 + 2a 8 + 2b 8 + 2c 10 + 2d 10 + 2e 10 + 2f 10 + 30 10 + 31 10 + 32 10 + 33 10 + 34 10 + 38 15 + 39 15 + 3a 15 + 3b 15 + 3c 15 + 3d 15 + 3e 15 + 3f 15 + 40 15 + 44 20 + 45 20 + 46 20 + 47 20 + 48 20 + 49 20 + 4a 20 + 4b 20 + 4c 20 + 50 11 + 51 11 + 52 11 + 56 16 + 57 16 + 58 16 + 5c 21 + 5d 21 + 5e 21 + 5f 25 + 60 25 + } + + method 'testInvokeVirtual ()Ljava/lang/String;' { + 0 29 + 1 29 + 2 29 + a 31 + b 31 + c 31 + e 31 + f 31 + 10 31 + 11 31 + 12 31 + 13 31 + 14 31 + 15 31 + 16 31 + 17 31 + 18 31 + 19 31 + 1a 31 + 1b 31 + 1c 31 + 1d 31 + 1e 31 + 1f 31 + 20 31 + 21 31 + 22 31 + 23 31 + 24 31 + 25 31 + 26 31 + 27 31 + 28 31 + 29 31 + 2a 31 + 2b 31 + 2c 31 + 2d 31 + 2e 31 + 2f 31 + 30 31 + 31 31 + 32 31 + 33 31 + 34 33 + 35 33 + 36 33 + 37 33 + 38 33 + 39 33 + 3a 33 + 3b 33 + 3c 33 + 40 38 + 41 38 + 42 38 + 43 38 + 44 38 + 45 38 + 46 38 + 47 38 + 48 38 + 4c 43 + 4d 43 + 4e 43 + 4f 43 + 50 43 + 51 43 + 52 43 + 53 43 + 54 43 + 58 34 + 59 34 + 5a 34 + 5e 39 + 5f 39 + 60 39 + 64 44 + 65 44 + 66 44 + 67 48 + 68 48 + } +} + +class 'pkg/TestEclipseSwitchString2$Inner' { + method 'get ()Ljava/lang/String;' { + 0 53 + 1 53 + 2 53 + } + + method 'getVirtual ()Ljava/lang/String;' { + 0 57 + 1 57 + 2 57 + } +} + +Lines mapping: +5 <-> 4 +9 <-> 54 +13 <-> 58 +18 <-> 7 +19 <-> 9 +21 <-> 12 +24 <-> 17 +27 <-> 22 +31 <-> 26 +35 <-> 30 +36 <-> 32 +38 <-> 35 +41 <-> 40 +44 <-> 45 +48 <-> 49 +Not mapped: +4 +22 +25 +39 +42 \ No newline at end of file From f328617b03a585c32472a3a5a330b1d9cf8d17a5 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:20:04 +0200 Subject: [PATCH 16/29] Don't create validation errors for "definition var exprents" --- .../decompiler/modules/decompiler/sforms/SFormsConstructor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SFormsConstructor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SFormsConstructor.java index 2685a7f4f8..bb2996de81 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SFormsConstructor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SFormsConstructor.java @@ -161,7 +161,7 @@ public void varRead(VarMapHolder varMaps, Statement stat, boolean calcLiveVars, // TODO: shouldn't every path from the start of the method to a variable usage have an assignment? // seems to trigger with enhanced switches this.updateVarExprent(varExprent, stat, varmap, calcLiveVars); - ValidationHelper.validateTrue(false, "Variable read before assignment: " + varExprent); + ValidationHelper.validateTrue(varExprent.isDefinition(), "Variable read before assignment: " + varExprent); break; } case 1: { // size == 1 (var has only one discovered assignment) From ba0aedeff55ebd9c4d35c111824a4d65f7803a44 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:36:35 -0400 Subject: [PATCH 17/29] Fix arrays initialized with null merging into improper type Fixes #577 and #459 --- .../decompiler/vars/VarDefinitionHelper.java | 4 ++ .../java/decompiler/SingleClassesTest.java | 1 + testData/results/pkg/TestByteArrayMerge.dec | 64 +++++++++++++++++++ .../java8nodebug/pkg/TestByteArrayMerge.java | 19 ++++++ 4 files changed, 88 insertions(+) create mode 100644 testData/results/pkg/TestByteArrayMerge.dec create mode 100644 testData/src/java8nodebug/pkg/TestByteArrayMerge.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java index f435185ec3..1bf5795996 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java @@ -470,6 +470,9 @@ private void populateTypeBounds(VarProcessor proc, Statement stat) { if (exit.getExitType() == ExitExprent.Type.RETURN) { instance = exit.getValue(); target = exit.getRetType().value; + if (exit.getRetType().type != CodeType.OBJECT) { + continue; + } } } @@ -493,6 +496,7 @@ private void populateTypeBounds(VarProcessor proc, Statement stat) { } */ + // TODO: does this do anything? if (!newType.equals(oldMax)) { if (oldMax != null && oldMax.type == CodeType.OBJECT) { // If the old min is an instanceof the new target, EXA: List -> ArrayList diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 3617a0843b..bc2b824193 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -862,6 +862,7 @@ private void registerDefault() { register(JAVA_25, "/TestCompactSourceFileArgs"); register(JAVA_25, "/TestCompactSourceFileOtherMembers"); register(JAVA_25, "/TestCompactSourceFileOtherMembersStatic"); + register(JAVA_8_NODEBUG, "TestByteArrayMerge"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestByteArrayMerge.dec b/testData/results/pkg/TestByteArrayMerge.dec new file mode 100644 index 0000000000..b90f239900 --- /dev/null +++ b/testData/results/pkg/TestByteArrayMerge.dec @@ -0,0 +1,64 @@ +package pkg; + +public class TestByteArrayMerge { + private static byte[] decode(int var0, int var1) { + B var2 = null; + if (var0 > 0) { + var2 = new byte[var0]; + } else { + var2 = new byte[1]; + } + + int var3 = var1 & 0xFF; + + for (int var4 = 0; var4 < ((Object[])var2).length; var4++) { + ((Object[])var2)[var4] = (byte)var3; + } + + return (byte[])var2; + } +} + +class 'pkg/TestByteArrayMerge' { + method 'decode (II)[B' { + 0 4 + 1 4 + 2 5 + 3 5 + 4 5 + 5 5 + 6 6 + 9 6 + d 8 + 10 8 + 11 11 + 12 11 + 13 11 + 14 11 + 15 11 + 16 11 + 17 13 + 18 13 + 19 13 + 1a 13 + 1b 13 + 1c 13 + 1d 13 + 1e 13 + 1f 13 + 20 13 + 21 14 + 22 14 + 23 14 + 24 14 + 25 14 + 26 14 + 27 13 + 28 13 + 29 13 + 2d 17 + 2e 17 + } +} + +Lines mapping: \ No newline at end of file diff --git a/testData/src/java8nodebug/pkg/TestByteArrayMerge.java b/testData/src/java8nodebug/pkg/TestByteArrayMerge.java new file mode 100644 index 0000000000..6a2f723aac --- /dev/null +++ b/testData/src/java8nodebug/pkg/TestByteArrayMerge.java @@ -0,0 +1,19 @@ +package pkg; + +public class TestByteArrayMerge { + private static byte[] decode(int size, int step) { + byte[] pixels = null; + if (size > 0) { + pixels = new byte[size]; + } else { + pixels = new byte[1]; + } + + int value = step & 255; + for (int i = 0; i < pixels.length; i++) { + pixels[i] = (byte)value; + } + + return pixels; + } +} \ No newline at end of file From 2c280d45f0adb2f41a2174dc22930c41e2d33869 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:37:45 -0400 Subject: [PATCH 18/29] Update tests --- testData/results/pkg/TestByteArrayMerge.dec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testData/results/pkg/TestByteArrayMerge.dec b/testData/results/pkg/TestByteArrayMerge.dec index b90f239900..e2b3a1a805 100644 --- a/testData/results/pkg/TestByteArrayMerge.dec +++ b/testData/results/pkg/TestByteArrayMerge.dec @@ -2,7 +2,7 @@ package pkg; public class TestByteArrayMerge { private static byte[] decode(int var0, int var1) { - B var2 = null; + byte[] var2 = null; if (var0 > 0) { var2 = new byte[var0]; } else { @@ -11,11 +11,11 @@ public class TestByteArrayMerge { int var3 = var1 & 0xFF; - for (int var4 = 0; var4 < ((Object[])var2).length; var4++) { - ((Object[])var2)[var4] = (byte)var3; + for (int var4 = 0; var4 < var2.length; var4++) { + var2[var4] = (byte)var3; } - return (byte[])var2; + return var2; } } From ce4c6f9216092b4ba6fb6c97f915e5f0cf3b224d Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 20 Jun 2026 12:20:08 -0400 Subject: [PATCH 19/29] Fix common supertype crash with float ternaries Fixes #576 --- .../decompiler/exps/FunctionExprent.java | 33 ++++++- .../decompiler/vars/CheckTypesResult.java | 1 + .../java/decompiler/SingleClassesTest.java | 1 + .../results/pkg/TestFloatDupStoreTernary.dec | 85 +++++++++++++++++++ .../java8/pkg/TestFloatDupStoreTernary.java | 13 +++ 5 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 testData/results/pkg/TestFloatDupStoreTernary.dec create mode 100644 testData/src/java8/pkg/TestFloatDupStoreTernary.java diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java index 49af9bd357..4afbb61674 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -394,6 +394,35 @@ public CheckTypesResult checkExprTypeBounds() { result.addExprLowerBound(param1, implicitType); result.addExprUpperBound(param1, implicitType); break; + case LCMP: + result.addExprLowerBound(param1, VarType.VARTYPE_LONG); + result.addExprLowerBound(param2, VarType.VARTYPE_LONG); + case FCMPL: + case FCMPG: + result.addExprLowerBound(param1, VarType.VARTYPE_FLOAT); + result.addExprLowerBound(param2, VarType.VARTYPE_FLOAT); + break; + case DCMPL: + case DCMPG: + result.addExprLowerBound(param1, VarType.VARTYPE_DOUBLE); + result.addExprLowerBound(param2, VarType.VARTYPE_DOUBLE); + break; + case LT: + case GE: + case GT: + case LE: + // After secondary functions are identified, float and double comparisons (fcmp* and dcmp*) become regular comparisons. + // Without special handling here, we might introduce incorrect bounds and turn variables that should be floats/doubles into ints. + if (type1.equals(VarType.VARTYPE_FLOAT) && type2.equals(VarType.VARTYPE_FLOAT)) { + result.addExprLowerBound(param1, VarType.VARTYPE_FLOAT); + result.addExprLowerBound(param2, VarType.VARTYPE_FLOAT); + break; + } + if (type1.equals(VarType.VARTYPE_DOUBLE) && type2.equals(VarType.VARTYPE_DOUBLE)) { + result.addExprLowerBound(param1, VarType.VARTYPE_DOUBLE); + result.addExprLowerBound(param2, VarType.VARTYPE_DOUBLE); + break; + } case ADD: case SUB: case MUL: @@ -402,10 +431,6 @@ public CheckTypesResult checkExprTypeBounds() { case SHL: case SHR: case USHR: - case LT: - case GE: - case GT: - case LE: result.addExprLowerBound(param2, VarType.VARTYPE_BYTECHAR); case BIT_NOT: // case BOOL_NOT: diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java index 70b5b65ac6..7792ce01cf 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java @@ -3,6 +3,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.ValidationHelper; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; import org.jetbrains.java.decompiler.struct.gen.VarType; import java.util.ArrayList; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index bc2b824193..53632b6c13 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -863,6 +863,7 @@ private void registerDefault() { register(JAVA_25, "/TestCompactSourceFileOtherMembers"); register(JAVA_25, "/TestCompactSourceFileOtherMembersStatic"); register(JAVA_8_NODEBUG, "TestByteArrayMerge"); + register(JAVA_8, "TestFloatDupStoreTernary"); } private void registerEntireClassPath() { diff --git a/testData/results/pkg/TestFloatDupStoreTernary.dec b/testData/results/pkg/TestFloatDupStoreTernary.dec new file mode 100644 index 0000000000..5c606932c6 --- /dev/null +++ b/testData/results/pkg/TestFloatDupStoreTernary.dec @@ -0,0 +1,85 @@ +package pkg; + +public class TestFloatDupStoreTernary { + public static float min4(float a, float b, float c, float d) { + float t; + float var5; + return d < (var5 = c < (t = a < b ? a : b) ? c : t) ? d : var5;// 6 + } + + public static float max4(float a, float b, float c, float d) { + float t; + float var5; + return d > (var5 = c > (t = a > b ? a : b) ? c : t) ? d : var5;// 11 + } +} + +class 'pkg/TestFloatDupStoreTernary' { + method 'min4 (FFFF)F' { + 0 6 + 1 6 + 2 6 + 3 6 + 4 6 + 5 6 + 6 6 + 7 6 + 8 6 + c 6 + e 6 + f 6 + 10 6 + 11 6 + 12 6 + 13 6 + 14 6 + 18 6 + 19 6 + 1b 6 + 1c 6 + 1d 6 + 1e 6 + 1f 6 + 20 6 + 21 6 + 25 6 + 26 6 + 27 6 + } + + method 'max4 (FFFF)F' { + 0 12 + 1 12 + 2 12 + 3 12 + 4 12 + 5 12 + 6 12 + 7 12 + 8 12 + c 12 + e 12 + f 12 + 10 12 + 11 12 + 12 12 + 13 12 + 14 12 + 18 12 + 19 12 + 1b 12 + 1c 12 + 1d 12 + 1e 12 + 1f 12 + 20 12 + 21 12 + 25 12 + 26 12 + 27 12 + } +} + +Lines mapping: +6 <-> 7 +11 <-> 13 \ No newline at end of file diff --git a/testData/src/java8/pkg/TestFloatDupStoreTernary.java b/testData/src/java8/pkg/TestFloatDupStoreTernary.java new file mode 100644 index 0000000000..df9202b4ac --- /dev/null +++ b/testData/src/java8/pkg/TestFloatDupStoreTernary.java @@ -0,0 +1,13 @@ +package pkg; + +public class TestFloatDupStoreTernary { + public static float min4(float a, float b, float c, float d) { + float t; + return d < (t = c < (t = a < b ? a : b) ? c : t) ? d : t; + } + + public static float max4(float a, float b, float c, float d) { + float t; + return d > (t = c > (t = a > b ? a : b) ? c : t) ? d : t; + } +} \ No newline at end of file From 5c3607387f342e042e2232f62999e133f16ae2c9 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:12:16 +0200 Subject: [PATCH 20/29] Partial offsets fix (#597) * Add missing instruction offsets * Revert of MinecraftForge/ForgeFlower/pull/105 Revert of d88f743cbe3f18bbe7f54fe7b8d209e56c4fd51b Fixes #596 * temp undo * Fix dec file issues * Update kotlin dec file --- .../testData/results/pkg/TestTryReturn.dec | 5 +- .../modules/code/ExceptionDeobfuscator.java | 3 + .../modules/decompiler/FinallyProcessor.java | 4 - testData/results/pkg/TestGroovyTryReturn.dec | 2307 ++++++++++------- testData/results/pkg/TestLoopFinally.dec | 5 +- testData/results/pkg/TestTryCatchFinally.dec | 5 +- .../results/pkg/TestTryCatchNoIncrement.dec | 5 +- .../TestTryFinallyMarkerExceptionsInvalid.dec | 13 +- ...estTryFinallyMarkerExceptionsInvalid_1.dec | 13 +- ...estTryFinallyMarkerExceptionsInvalid_2.dec | 15 +- testData/results/pkg/TestTryReturn.dec | 5 +- 11 files changed, 1366 insertions(+), 1014 deletions(-) diff --git a/plugins/kotlin/testData/results/pkg/TestTryReturn.dec b/plugins/kotlin/testData/results/pkg/TestTryReturn.dec index ace9a9835e..0c4ec0512b 100644 --- a/plugins/kotlin/testData/results/pkg/TestTryReturn.dec +++ b/plugins/kotlin/testData/results/pkg/TestTryReturn.dec @@ -159,7 +159,7 @@ public class TestTryReturn { } catch (var10: Exception) {// 160 System.out.println(3)// 161 } finally { - continue; + continue;// 164 } } finally { val var3: Byte = 28// 167 @@ -622,6 +622,7 @@ class 'pkg/TestTryReturn' { 31 159 32 159 33 159 + 3c 161 44 164 45 164 46 164 @@ -791,6 +792,7 @@ Lines mapping: 159 <-> 158 160 <-> 159 161 <-> 160 +164 <-> 162 167 <-> 165 170 <-> 168 175 <-> 172 @@ -851,7 +853,6 @@ Not mapped: 157 158 162 -164 173 174 185 diff --git a/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java b/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java index a3c245da77..c1bef07b3c 100644 --- a/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java +++ b/src/org/jetbrains/java/decompiler/modules/code/ExceptionDeobfuscator.java @@ -99,6 +99,7 @@ public static void restorePopRanges(ControlFlowGraph graph) { newseq.addInstruction(firstinstr.clone()); newblock.setSeq(newseq); + newblock.getInstrOldOffsets().add(handler.getOldOffset(0)); graph.getBlocks().addWithKey(newblock, newblock.id); @@ -129,6 +130,7 @@ else if (range_ext.getProtectedRange().contains(handler)) { // remove the first pop in the handler seq.removeInstruction(0); + handler.getInstrOldOffsets().remove(0); } newblock.addSuccessorException(range_super.handler); @@ -495,6 +497,7 @@ public static void insertDummyExceptionHandlerBlocks(ControlFlowGraph graph, Byt // Duplicate block now BasicBlock newBlock = new BasicBlock(++graph.last_id); newBlock.setSeq(handler.getSeq().clone()); + newBlock.getInstrOldOffsets().addAll(handler.getInstrOldOffsets()); graph.getBlocks().addWithKey(newBlock, newBlock.id); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java index 98cb9d4ad2..23180279e3 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java @@ -1049,25 +1049,21 @@ private static void removeExceptionInstructionsEx(BasicBlock block, int blocktyp if (finallytype == FinallyType.EMPTY) { // empty finally handler for (int i = seq.length() - 1; i >= 0; i--) { seq.removeInstruction(i); - instrOldOffsets.remove(i); } } else { if ((blocktype & 1) > 0) { // first if (finallytype == FinallyType.STORE || finallytype == FinallyType.DROP) { // astore or pop seq.removeInstruction(0); - instrOldOffsets.remove(0); } } if ((blocktype & 2) > 0) { // last if (finallytype == FinallyType.STORE || finallytype == FinallyType.DROP) { // astore or pop seq.removeLast(); - instrOldOffsets.remove(instrOldOffsets.size() - 1); } if (finallytype == FinallyType.STORE) { // astore seq.removeLast(); - instrOldOffsets.remove(instrOldOffsets.size() - 1); } } } diff --git a/testData/results/pkg/TestGroovyTryReturn.dec b/testData/results/pkg/TestGroovyTryReturn.dec index f3ca7a3653..57f514bdc8 100644 --- a/testData/results/pkg/TestGroovyTryReturn.dec +++ b/testData/results/pkg/TestGroovyTryReturn.dec @@ -7,6 +7,7 @@ import groovy.transform.Internal; import java.beans.Transient; import java.util.Random; import java.util.function.Supplier; +import org.codehaus.groovy.runtime.BytecodeInterface8; import org.codehaus.groovy.runtime.callsite.CallSite; import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; @@ -74,169 +75,65 @@ public class TestGroovyTryReturn implements GroovyObject { // try (17 -> 26): 33 null } - public boolean testFinally(Supplier param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: nop - // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; - // 04: astore 2 - // 05: aload 2 - // 06: ldc 2 - // 08: aaload - // 09: aload 1 - // 0a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 0f: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z - // 12: istore 3 - // 13: nop - // 14: aload 2 - // 15: ldc 3 - // 17: aaload - // 18: aload 2 - // 19: ldc 4 - // 1b: aaload - // 1c: ldc java/lang/System - // 1e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 23: ldc "Finally" - // 25: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 2a: pop - // 2b: nop - // 2c: iload 3 - // 2d: ireturn - // 2e: nop - // 2f: nop - // 30: athrow - // 31: nop - // 32: nop - // 33: nop - // 34: nop - // 35: nop - // 36: nop - // 37: nop - // 38: nop - // 39: nop - // 3a: nop - // 3b: nop - // 3c: nop - // 3d: nop - // 3e: nop - // 3f: nop - // 40: nop - // 41: nop - // 42: nop - // 43: nop - // 44: nop - // 45: nop - // 46: nop - // 47: athrow - // 48: nop - // 49: nop - // 4a: athrow - // 4b: astore 4 - // 4d: aload 2 - // 4e: ldc 7 - // 50: aaload - // 51: aload 2 - // 52: ldc 8 - // 54: aaload - // 55: ldc java/lang/System - // 57: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 5c: ldc "Finally" - // 5e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 63: pop - // 64: aload 4 - // 66: athrow - // 67: nop - // 68: nop - // 69: nop - // 6a: nop - // 6b: nop - // 6c: nop - // 6d: nop - // 6e: nop - // 6f: athrow - // try (3 -> 11): 54 null - // try (23 -> 25): 54 null + // $VF: Duplicated exception handlers to handle obfuscated exceptions + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally(Supplier supplier) { + CallSite[] var2 = $getCallSiteArray(); + boolean var9 = false /* VF: Semaphore variable */; + + boolean var3; + try { + var9 = true; + var3 = DefaultTypeTransformation.booleanUnbox(var2[2].call(supplier));// 16 17 + var9 = false; + } finally { + if (var9) { + var2[7].call(var2[8].callGetProperty(System.class), "Finally");// 19 + } + } + + var2[3].call(var2[4].callGetProperty(System.class), "Finally"); + + try { + return var3;// 20 + } finally { + var2[7].call(var2[8].callGetProperty(System.class), "Finally"); + } } - public void testFinally1(Supplier param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: nop - // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; - // 04: astore 2 - // 05: aload 2 - // 06: ldc 9 - // 08: aaload - // 09: aload 2 - // 0a: ldc 10 - // 0c: aaload - // 0d: ldc java/lang/System - // 0f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 14: ldc "pred" - // 16: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 1b: pop - // 1c: aload 2 - // 1d: ldc 11 - // 1f: aaload - // 20: aload 1 - // 21: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 26: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z - // 29: ifeq 46 - // 2c: nop - // 2d: aload 2 - // 2e: ldc 12 - // 30: aaload - // 31: aload 2 - // 32: ldc 13 - // 34: aaload - // 35: ldc java/lang/System - // 37: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 3c: ldc "Finally" - // 3e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 43: pop - // 44: nop - // 45: return - // 46: goto 49 - // 49: aload 2 - // 4a: ldc 14 - // 4c: aaload - // 4d: aload 2 - // 4e: ldc 15 - // 50: aaload - // 51: ldc java/lang/System - // 53: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 58: ldc "Finally" - // 5a: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 5f: pop - // 60: goto 7d - // 63: astore 3 - // 64: aload 2 - // 65: ldc 16 - // 67: aaload - // 68: aload 2 - // 69: ldc 17 - // 6b: aaload - // 6c: ldc java/lang/System - // 6e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 73: ldc "Finally" - // 75: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 7a: pop - // 7b: aload 3 - // 7c: athrow - // 7d: aload 2 - // 7e: ldc 18 - // 80: aaload - // 81: aload 2 - // 82: ldc 19 - // 84: aaload - // 85: ldc java/lang/System - // 87: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 8c: ldc "suc" - // 8e: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 93: pop - // 94: return - // try (14 -> 22): 48 null - // try (34 -> 36): 48 null + // $VF: Duplicated exception handlers to handle obfuscated exceptions + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testFinally1(Supplier supplier) { + CallSite[] var2 = $getCallSiteArray(); + var2[9].call(var2[10].callGetProperty(System.class), "pred");// 24 + boolean var8 = false /* VF: Semaphore variable */; + + label60: { + try { + var8 = true; + if (!DefaultTypeTransformation.booleanUnbox(var2[11].call(supplier))) {// 26 27 + var8 = false; + break label60; + } + + var8 = false; + } finally { + if (var8) { + var2[16].call(var2[17].callGetProperty(System.class), "Finally");// 31 + } + } + + var2[12].call(var2[13].callGetProperty(System.class), "Finally"); + + try { + return;// 32 + } finally { + var2[16].call(var2[17].callGetProperty(System.class), "Finally"); + } + } + + var2[14].call(var2[15].callGetProperty(System.class), "Finally");// 30 + var2[18].call(var2[19].callGetProperty(System.class), "suc");// 34 } // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. @@ -260,191 +157,106 @@ public class TestGroovyTryReturn implements GroovyObject { return var9;// 45 } - public boolean testFinally3(boolean param1, boolean param2, int param3, Supplier param4) { - // $VF: Couldn't be decompiled - // Bytecode: - // 000: nop - // 001: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; - // 004: astore 5 - // 006: iload 1 - // 007: ifeq 045 - // 00a: iload 2 - // 00b: ifeq 024 - // 00e: aload 5 - // 010: ldc 25 - // 012: aaload - // 013: aload 4 - // 015: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 01a: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z - // 01d: ifeq 024 - // 020: bipush 1 - // 021: goto 025 - // 024: bipush 0 - // 025: istore 6 - // 027: nop - // 028: aload 5 - // 02a: ldc 26 - // 02c: aaload - // 02d: aload 5 - // 02f: ldc 27 - // 031: aaload - // 032: ldc java/lang/System - // 034: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 039: ldc "Finally" - // 03b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 040: pop - // 041: nop - // 042: iload 6 - // 044: ireturn - // 045: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigInt ()Z - // 048: ifeq 060 - // 04b: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ ()Z - // 04e: ifeq 060 - // 051: getstatic pkg/TestGroovyTryReturn.__$stMC Z - // 054: ifne 060 - // 057: invokestatic org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass ()Z - // 05a: ifne 060 - // 05d: goto 09a - // 060: iload 3 - // 061: bipush 0 - // 062: if_icmple 069 - // 065: bipush 1 - // 066: goto 06a - // 069: bipush 0 - // 06a: ifeq 097 - // 06d: iload 3 - // 06e: bipush 1 - // 06f: if_icmpne 076 - // 072: bipush 1 - // 073: goto 077 - // 076: bipush 0 - // 077: istore 7 - // 079: nop - // 07a: aload 5 - // 07c: ldc 28 - // 07e: aaload - // 07f: aload 5 - // 081: ldc 29 - // 083: aaload - // 084: ldc java/lang/System - // 086: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 08b: ldc "Finally" - // 08d: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 092: pop - // 093: nop - // 094: iload 7 - // 096: ireturn - // 097: goto 0d1 - // 09a: iload 3 - // 09b: bipush 0 - // 09c: if_icmple 0a3 - // 09f: bipush 1 - // 0a0: goto 0a4 - // 0a3: bipush 0 - // 0a4: ifeq 0d1 - // 0a7: iload 3 - // 0a8: bipush 1 - // 0a9: if_icmpne 0b0 - // 0ac: bipush 1 - // 0ad: goto 0b1 - // 0b0: bipush 0 - // 0b1: istore 8 - // 0b3: nop - // 0b4: aload 5 - // 0b6: ldc 30 - // 0b8: aaload - // 0b9: aload 5 - // 0bb: ldc 31 - // 0bd: aaload - // 0be: ldc java/lang/System - // 0c0: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 0c5: ldc "Finally" - // 0c7: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 0cc: pop - // 0cd: nop - // 0ce: iload 8 - // 0d0: ireturn - // 0d1: aload 5 - // 0d3: ldc 32 - // 0d5: aaload - // 0d6: aload 4 - // 0d8: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 0dd: invokestatic org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox (Ljava/lang/Object;)Z - // 0e0: istore 9 - // 0e2: nop - // 0e3: aload 5 - // 0e5: ldc 33 - // 0e7: aaload - // 0e8: aload 5 - // 0ea: ldc 34 - // 0ec: aaload - // 0ed: ldc java/lang/System - // 0ef: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 0f4: ldc "Finally" - // 0f6: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 0fb: pop - // 0fc: nop - // 0fd: iload 9 - // 0ff: ireturn - // 100: nop - // 101: nop - // 102: athrow - // 103: nop - // 104: nop - // 105: nop - // 106: nop - // 107: nop - // 108: nop - // 109: nop - // 10a: nop - // 10b: nop - // 10c: nop - // 10d: nop - // 10e: nop - // 10f: nop - // 110: nop - // 111: nop - // 112: nop - // 113: nop - // 114: nop - // 115: nop - // 116: nop - // 117: nop - // 118: nop - // 119: nop - // 11a: nop - // 11b: athrow - // 11c: nop - // 11d: nop - // 11e: athrow - // 11f: astore 10 - // 121: aload 5 - // 123: ldc 37 - // 125: aaload - // 126: aload 5 - // 128: ldc 38 - // 12a: aaload - // 12b: ldc java/lang/System - // 12d: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 132: ldc "Finally" - // 134: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 139: pop - // 13a: aload 10 - // 13c: athrow - // 13d: nop - // 13e: nop - // 13f: nop - // 140: nop - // 141: nop - // 142: nop - // 143: nop - // 144: nop - // 145: athrow - // try (3 -> 19): 154 null - // try (31 -> 57): 154 null - // try (69 -> 87): 154 null - // try (99 -> 109): 154 null - // try (121 -> 123): 154 null + // $VF: Duplicated exception handlers to handle obfuscated exceptions + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public boolean testFinally3(boolean b, boolean c, int a, Supplier supplier) { + CallSite[] var5 = $getCallSiteArray(); + boolean var39 = false /* VF: Semaphore variable */; + + boolean var6; + label381: { + try { + var39 = true; + if (b) {// 49 50 + var6 = c && DefaultTypeTransformation.booleanUnbox(var5[25].call(supplier));// 51 + var39 = false; + break label381; + } + + var39 = false; + } finally { + if (var39) { + var5[37].call(var5[38].callGetProperty(System.class), "Finally");// 60 + } + } + + boolean var33 = false /* VF: Semaphore variable */; + + boolean var7; + label367: { + boolean var8; + label383: { + label384: { + try { + var33 = true; + if (!BytecodeInterface8.isOrigInt() || !BytecodeInterface8.isOrigZ() || __$stMC || BytecodeInterface8.disabledStandardMetaClass()) {// 52 + if (a > 0) { + var7 = a == 1; + var33 = false; + break label367; + } + + var33 = false; + break label384; + } + + var33 = false; + } finally { + if (var33) { + var5[37].call(var5[38].callGetProperty(System.class), "Finally"); + } + } + + boolean var27 = false /* VF: Semaphore variable */; + + try { + var27 = true; + if (a > 0) {// 54 + var8 = a == 1;// 55 + var27 = false; + break label383; + } + + var27 = false; + } finally { + if (var27) { + var5[37].call(var5[38].callGetProperty(System.class), "Finally"); + } + } + } + + boolean var21 = false /* VF: Semaphore variable */; + + boolean var9; + try { + var21 = true; + var9 = DefaultTypeTransformation.booleanUnbox(var5[32].call(supplier));// 56 58 + var21 = false; + } finally { + if (var21) { + var5[37].call(var5[38].callGetProperty(System.class), "Finally"); + } + } + + var5[33].call(var5[34].callGetProperty(System.class), "Finally"); + + try { + return var9; + } finally { + var5[37].call(var5[38].callGetProperty(System.class), "Finally"); + } + } + + var5[30].call(var5[31].callGetProperty(System.class), "Finally"); + return var8; + } + + var5[28].call(var5[29].callGetProperty(System.class), "Finally"); + return var7; + } + + var5[26].call(var5[27].callGetProperty(System.class), "Finally"); + return var6;// 61 } // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. @@ -525,64 +337,40 @@ public class TestGroovyTryReturn implements GroovyObject { return b;// 105 } + // $VF: Duplicated exception handlers to handle obfuscated exceptions + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. public void testLoopFinally() { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: nop - // 01: invokestatic pkg/TestGroovyTryReturn.$getCallSiteArray ()[Lorg/codehaus/groovy/runtime/callsite/CallSite; - // 04: astore 1 - // 05: bipush 1 - // 06: istore 2 - // 07: iload 2 - // 08: pop - // 09: iload 2 - // 0a: ifeq 27 - // 0d: nop - // 0e: aload 1 - // 0f: ldc 62 - // 11: aaload - // 12: aload 1 - // 13: ldc 63 - // 15: aaload - // 16: ldc java/lang/System - // 18: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 1d: ldc "Finally" - // 1f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 24: pop - // 25: nop - // 26: return - // 27: goto 2a - // 2a: aload 1 - // 2b: ldc 64 - // 2d: aaload - // 2e: aload 1 - // 2f: ldc 65 - // 31: aaload - // 32: ldc java/lang/System - // 34: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 39: ldc "Finally" - // 3b: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 40: pop - // 41: goto 5e - // 44: astore 3 - // 45: aload 1 - // 46: ldc 66 - // 48: aaload - // 49: aload 1 - // 4a: ldc 67 - // 4c: aaload - // 4d: ldc java/lang/System - // 4f: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.callGetProperty (Ljava/lang/Object;)Ljava/lang/Object; 2 - // 54: ldc "Finally" - // 56: invokeinterface org/codehaus/groovy/runtime/callsite/CallSite.call (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 3 - // 5b: pop - // 5c: aload 3 - // 5d: athrow - // 5e: goto 09 - // 61: athrow - // try (7 -> 10): 36 null - // try (22 -> 24): 36 null - } + CallSite[] var1 = $getCallSiteArray(); + boolean a = true;// 109 + + while (true) { + boolean var8 = false /* VF: Semaphore variable */; + + try { + var8 = true; + if (a) {// 111 112 113 + var8 = false; + break; + } + + var8 = false; + } finally { + if (var8) { + var1[66].call(var1[67].callGetProperty(System.class), "Finally");// 117 + } + } + + var1[64].call(var1[65].callGetProperty(System.class), "Finally");// 116 + } + + var1[62].call(var1[63].callGetProperty(System.class), "Finally"); + + try { + ; + } finally { + var1[66].call(var1[67].callGetProperty(System.class), "Finally"); + } + }// 118 public void testParsingFailureSimple() { // $VF: Couldn't be decompiled @@ -699,7 +487,7 @@ public class TestGroovyTryReturn implements GroovyObject { } catch (Exception var9) {// 161 var1[84].call(var1[85].callGetProperty(System.class), 3);// 162 } finally { - continue; + continue;// 165 } } finally { byte var10 = (byte)28;// 168 @@ -1059,199 +847,987 @@ public class TestGroovyTryReturn implements GroovyObject { class 'pkg/TestGroovyTryReturn' { method ' ()V' { - 1 15 - 2 15 - 3 15 - 4 15 - 6 16 - 7 16 - 8 16 - 9 17 - a 17 - b 17 - c 17 - d 17 - e 18 - f 18 - 11 18 - 12 18 - 13 18 - 16 19 + 1 16 + 2 16 + 3 16 + 4 16 + 6 17 + 7 17 + 8 17 + 9 18 + a 18 + b 18 + c 18 + d 18 + e 19 + f 19 + 11 19 + 12 19 + 13 19 + 16 20 + } + + method 'testFinally (Ljava/util/function/Supplier;)Z' { + 1 80 + 2 80 + 3 80 + 4 80 + 5 86 + 6 86 + 7 86 + 8 86 + 9 86 + a 86 + b 86 + c 86 + d 86 + e 86 + f 86 + 10 86 + 11 86 + 12 86 + 14 94 + 15 94 + 16 94 + 17 94 + 18 94 + 19 94 + 1a 94 + 1b 94 + 1c 94 + 1d 94 + 1e 94 + 1f 94 + 20 94 + 21 94 + 22 94 + 23 94 + 24 94 + 25 94 + 26 94 + 27 94 + 28 94 + 29 94 + 2c 97 + 2d 97 + 4d 90 + 4e 90 + 4f 90 + 50 90 + 51 90 + 52 90 + 53 90 + 54 90 + 55 90 + 56 90 + 57 90 + 58 90 + 59 90 + 5a 90 + 5b 90 + 5c 90 + 5d 90 + 5e 90 + 5f 90 + 60 90 + 61 90 + 62 90 + } + + method 'testFinally1 (Ljava/util/function/Supplier;)V' { + 1 106 + 2 106 + 3 106 + 4 106 + 5 107 + 6 107 + 7 107 + 8 107 + 9 107 + a 107 + b 107 + c 107 + d 107 + e 107 + f 107 + 10 107 + 11 107 + 12 107 + 13 107 + 14 107 + 15 107 + 16 107 + 17 107 + 18 107 + 19 107 + 1a 107 + 1c 113 + 1d 113 + 1e 113 + 1f 113 + 20 113 + 21 113 + 22 113 + 23 113 + 24 113 + 25 113 + 26 113 + 27 113 + 28 113 + 29 113 + 2a 113 + 2b 113 + 2d 125 + 2e 125 + 2f 125 + 30 125 + 31 125 + 32 125 + 33 125 + 34 125 + 35 125 + 36 125 + 37 125 + 38 125 + 39 125 + 3a 125 + 3b 125 + 3c 125 + 3d 125 + 3e 125 + 3f 125 + 40 125 + 41 125 + 42 125 + 45 128 + 49 134 + 4a 134 + 4b 134 + 4c 134 + 4d 134 + 4e 134 + 4f 134 + 50 134 + 51 134 + 52 134 + 53 134 + 54 134 + 55 134 + 56 134 + 57 134 + 58 134 + 59 134 + 5a 134 + 5b 134 + 5c 134 + 5d 134 + 5e 134 + 64 121 + 65 121 + 66 121 + 67 121 + 68 121 + 69 121 + 6a 121 + 6b 121 + 6c 121 + 6d 121 + 6e 121 + 6f 121 + 70 121 + 71 121 + 72 121 + 73 121 + 74 121 + 75 121 + 76 121 + 77 121 + 78 121 + 79 121 + 7d 135 + 7e 135 + 7f 135 + 80 135 + 81 135 + 82 135 + 83 135 + 84 135 + 85 135 + 86 135 + 87 135 + 88 135 + 89 135 + 8a 135 + 8b 135 + 8c 135 + 8d 135 + 8e 135 + 8f 135 + 90 135 + 91 135 + 92 135 + 94 136 } method 'testFinally2 (Ljava/util/function/Supplier;)Z' { - 1 243 - 2 243 - 3 243 - 4 243 - 5 244 - 6 244 - 7 244 - a 249 - b 249 - c 249 - d 249 - e 249 - f 249 - 10 249 - 11 249 - 12 249 - 13 249 - 14 249 - 15 249 - 16 250 - 17 250 - 18 250 - 19 250 - 1a 250 - 1b 250 - 22 258 - 23 258 - 24 258 - 25 258 - 26 258 - 27 258 - 28 258 - 29 258 - 2a 258 - 2b 258 - 2c 258 - 2d 258 - 2e 258 - 2f 258 - 30 258 - 31 258 - 32 258 - 33 258 - 34 258 - 35 258 - 36 258 - 37 258 - 3e 254 - 3f 254 - 40 254 - 41 254 - 42 254 - 43 254 - 44 254 - 45 254 - 46 254 - 47 254 - 48 254 - 49 254 - 4a 254 - 4b 254 - 4c 254 - 4d 254 - 4e 254 - 4f 254 - 50 254 - 51 254 - 52 254 - 53 254 - 58 259 - 59 259 + 1 140 + 2 140 + 3 140 + 4 140 + 5 141 + 6 141 + 7 141 + a 146 + b 146 + c 146 + d 146 + e 146 + f 146 + 10 146 + 11 146 + 12 146 + 13 146 + 14 146 + 15 146 + 16 147 + 17 147 + 18 147 + 19 147 + 1a 147 + 1b 147 + 22 155 + 23 155 + 24 155 + 25 155 + 26 155 + 27 155 + 28 155 + 29 155 + 2a 155 + 2b 155 + 2c 155 + 2d 155 + 2e 155 + 2f 155 + 30 155 + 31 155 + 32 155 + 33 155 + 34 155 + 35 155 + 36 155 + 37 155 + 3e 151 + 3f 151 + 40 151 + 41 151 + 42 151 + 43 151 + 44 151 + 45 151 + 46 151 + 47 151 + 48 151 + 49 151 + 4a 151 + 4b 151 + 4c 151 + 4d 151 + 4e 151 + 4f 151 + 50 151 + 51 151 + 52 151 + 53 151 + 58 156 + 59 156 + } + + method 'testFinally3 (ZZILjava/util/function/Supplier;)Z' { + 1 162 + 2 162 + 3 162 + 4 162 + 5 162 + 6 169 + 7 169 + 8 169 + 9 169 + a 170 + b 170 + c 170 + d 170 + e 170 + f 170 + 10 170 + 11 170 + 12 170 + 13 170 + 14 170 + 15 170 + 16 170 + 17 170 + 18 170 + 19 170 + 1a 170 + 1b 170 + 1c 170 + 1d 170 + 1e 170 + 1f 170 + 25 170 + 26 170 + 28 257 + 29 257 + 2a 257 + 2b 257 + 2c 257 + 2d 257 + 2e 257 + 2f 257 + 30 257 + 31 257 + 32 257 + 33 257 + 34 257 + 35 257 + 36 257 + 37 257 + 38 257 + 39 257 + 3a 257 + 3b 257 + 3c 257 + 3d 257 + 3e 257 + 3f 257 + 42 258 + 43 258 + 44 258 + 45 191 + 46 191 + 47 191 + 48 191 + 49 191 + 4a 191 + 4b 191 + 4c 191 + 4d 191 + 4e 191 + 4f 191 + 50 191 + 51 191 + 52 191 + 53 191 + 54 191 + 55 191 + 56 191 + 57 191 + 58 191 + 59 191 + 5a 191 + 5b 191 + 5c 191 + 60 192 + 61 192 + 62 192 + 63 192 + 64 192 + 6a 192 + 6b 192 + 6c 192 + 6d 193 + 6e 193 + 6f 193 + 70 193 + 71 193 + 77 193 + 78 193 + 7a 253 + 7b 253 + 7c 253 + 7d 253 + 7e 253 + 7f 253 + 80 253 + 81 253 + 82 253 + 83 253 + 84 253 + 85 253 + 86 253 + 87 253 + 88 253 + 89 253 + 8a 253 + 8b 253 + 8c 253 + 8d 253 + 8e 253 + 8f 253 + 90 253 + 91 253 + 94 254 + 95 254 + 96 254 + 9a 213 + 9b 213 + 9c 213 + 9d 213 + 9e 213 + a4 213 + a5 213 + a6 213 + a7 214 + a8 214 + a9 214 + aa 214 + ab 214 + b1 214 + b2 214 + b4 249 + b5 249 + b6 249 + b7 249 + b8 249 + b9 249 + ba 249 + bb 249 + bc 249 + bd 249 + be 249 + bf 249 + c0 249 + c1 249 + c2 249 + c3 249 + c4 249 + c5 249 + c6 249 + c7 249 + c8 249 + c9 249 + ca 249 + cb 249 + ce 250 + cf 250 + d0 250 + d1 232 + d2 232 + d3 232 + d4 232 + d5 232 + d6 232 + d7 232 + d8 232 + d9 232 + da 232 + db 232 + dc 232 + dd 232 + de 232 + df 232 + e0 232 + e1 232 + e3 240 + e4 240 + e5 240 + e6 240 + e7 240 + e8 240 + e9 240 + ea 240 + eb 240 + ec 240 + ed 240 + ee 240 + ef 240 + f0 240 + f1 240 + f2 240 + f3 240 + f4 240 + f5 240 + f6 240 + f7 240 + f8 240 + f9 240 + fa 240 + fd 243 + fe 243 + ff 243 + 121 178 + 122 178 + 123 178 + 124 178 + 125 178 + 126 178 + 127 178 + 128 178 + 129 178 + 12a 178 + 12b 178 + 12c 178 + 12d 178 + 12e 178 + 12f 178 + 130 178 + 131 178 + 132 178 + 133 178 + 134 178 + 135 178 + 136 178 + 137 178 + 138 178 } method 'testFinally4 (Ljava/util/function/Supplier;)Z' { - 1 451 - 2 451 - 3 451 - 4 451 - 5 452 - 6 452 - 9 457 - a 457 - b 457 - c 457 - d 457 - e 457 - f 457 - 10 457 - 11 457 - 12 457 - 13 457 - 14 457 - 15 458 - 16 458 - 17 458 - 18 458 - 19 458 - 1a 458 - 21 466 - 22 466 - 23 466 - 24 466 - 25 466 - 26 466 - 27 466 - 28 466 - 29 466 - 2a 466 - 2b 466 - 2c 466 - 2d 466 - 2e 466 - 2f 466 - 30 466 - 31 466 - 32 466 - 33 466 - 34 466 - 35 466 - 36 466 - 3d 462 - 3e 462 - 3f 462 - 40 462 - 41 462 - 42 462 - 43 462 - 44 462 - 45 462 - 46 462 - 47 462 - 48 462 - 49 462 - 4a 462 - 4b 462 - 4c 462 - 4d 462 - 4e 462 - 4f 462 - 50 462 - 51 462 - 52 462 - 57 467 - 58 467 + 1 263 + 2 263 + 3 263 + 4 263 + 5 264 + 6 264 + 9 269 + a 269 + b 269 + c 269 + d 269 + e 269 + f 269 + 10 269 + 11 269 + 12 269 + 13 269 + 14 269 + 15 270 + 16 270 + 17 270 + 18 270 + 19 270 + 1a 270 + 21 278 + 22 278 + 23 278 + 24 278 + 25 278 + 26 278 + 27 278 + 28 278 + 29 278 + 2a 278 + 2b 278 + 2c 278 + 2d 278 + 2e 278 + 2f 278 + 30 278 + 31 278 + 32 278 + 33 278 + 34 278 + 35 278 + 36 278 + 3d 274 + 3e 274 + 3f 274 + 40 274 + 41 274 + 42 274 + 43 274 + 44 274 + 45 274 + 46 274 + 47 274 + 48 274 + 49 274 + 4a 274 + 4b 274 + 4c 274 + 4d 274 + 4e 274 + 4f 274 + 50 274 + 51 274 + 52 274 + 57 279 + 58 279 } method 'testFinally5 (Ljava/util/function/Supplier;)Z' { - 1 472 - 2 472 - 3 472 - 4 472 - 5 473 - 6 473 - 9 478 - a 478 - b 478 - c 478 - d 478 - e 478 - f 478 - 10 478 - 11 478 - 12 478 - 13 478 - 14 478 - 15 479 - 16 479 - 17 479 - 18 479 - 19 479 - 1a 479 - 21 481 + 1 284 + 2 284 + 3 284 + 4 284 + 5 285 + 6 285 + 9 290 + a 290 + b 290 + c 290 + d 290 + e 290 + f 290 + 10 290 + 11 290 + 12 290 + 13 290 + 14 290 + 15 291 + 16 291 + 17 291 + 18 291 + 19 291 + 1a 291 + 21 293 + 23 294 + 24 294 + 25 294 + 26 294 + 27 294 + 28 294 + 29 294 + 2a 294 + 2b 294 + 2c 294 + 2d 294 + 2e 294 + 2f 294 + 30 294 + 31 294 + 32 294 + 33 294 + 34 294 + 35 294 + 36 294 + 37 294 + 38 294 + 3a 295 + 3b 295 + 3c 295 + 3d 295 + 3e 295 + 3f 295 + 40 295 + 41 295 + 42 295 + 43 295 + 44 295 + 45 295 + 46 296 + 47 296 + 48 296 + 49 296 + 4a 296 + 4b 296 + 53 304 + 54 304 + 55 304 + 56 304 + 57 304 + 58 304 + 59 304 + 5a 304 + 5b 304 + 5c 304 + 5d 304 + 5e 304 + 5f 304 + 60 304 + 61 304 + 62 304 + 63 304 + 64 304 + 65 304 + 66 304 + 67 304 + 68 304 + 6f 300 + 70 300 + 71 300 + 72 300 + 73 300 + 74 300 + 75 300 + 76 300 + 77 300 + 78 300 + 79 300 + 7a 300 + 7b 300 + 7c 300 + 7d 300 + 7e 300 + 7f 300 + 80 300 + 81 300 + 82 300 + 83 300 + 84 300 + 89 305 + 8a 305 + } + + method 'testFinally6 (ZLjava/util/function/Supplier;)Z' { + 1 310 + 2 310 + 3 310 + 4 310 + 5 311 + 6 311 + 7 311 + b 316 + c 316 + d 316 + e 316 + f 317 + 10 317 + 11 317 + 19 318 + 1a 318 + 1b 318 + 1c 318 + 1d 318 + 1e 318 + 1f 318 + 20 318 + 21 318 + 22 318 + 23 318 + 24 318 + 25 318 + 26 318 + 27 318 + 28 318 + 29 318 + 2a 318 + 2b 318 + 2c 318 + 2d 318 + 2e 318 + 30 321 + 31 321 + 32 321 + 33 321 + 34 321 + 35 321 + 36 321 + 37 321 + 38 321 + 39 321 + 3a 321 + 3b 321 + 3c 322 + 3d 322 + 3e 322 + 3f 322 + 40 322 + 41 322 + 42 322 + 49 324 + 4b 325 + 4c 325 + 4d 325 + 4e 325 + 4f 325 + 50 325 + 51 325 + 52 325 + 53 325 + 54 325 + 55 325 + 56 325 + 57 325 + 58 325 + 59 325 + 5a 325 + 5b 325 + 5c 325 + 5d 325 + 5e 325 + 5f 325 + 60 325 + 62 326 + 63 326 + 64 326 + 65 326 + 66 326 + 67 326 + 68 326 + 69 326 + 6a 326 + 6b 326 + 6c 326 + 6d 326 + 6e 327 + 6f 327 + 70 327 + 71 327 + 72 327 + 73 327 + 74 327 + 7c 335 + 7d 335 + 7e 335 + 7f 335 + 80 335 + 81 335 + 82 335 + 83 335 + 84 335 + 85 335 + 86 335 + 87 335 + 88 335 + 89 335 + 8a 335 + 8b 335 + 8c 335 + 8d 335 + 8e 335 + 8f 335 + 90 335 + 91 335 + 98 331 + 99 331 + 9a 331 + 9b 331 + 9c 331 + 9d 331 + 9e 331 + 9f 331 + a0 331 + a1 331 + a2 331 + a3 331 + a4 331 + a5 331 + a6 331 + a7 331 + a8 331 + a9 331 + aa 331 + ab 331 + ac 331 + ad 331 + b2 336 + b3 336 + b4 336 + } + + method 'testLoopFinally ()V' { + 1 342 + 2 342 + 3 342 + 4 342 + 5 343 + 6 343 + 9 350 + a 350 + b 350 + c 350 + e 365 + f 365 + 10 365 + 11 365 + 12 365 + 13 365 + 14 365 + 15 365 + 16 365 + 17 365 + 18 365 + 19 365 + 1a 365 + 1b 365 + 1c 365 + 1d 365 + 1e 365 + 1f 365 + 20 365 + 21 365 + 22 365 + 23 365 + 26 372 + 2a 362 + 2b 362 + 2c 362 + 2d 362 + 2e 362 + 2f 362 + 30 362 + 31 362 + 32 362 + 33 362 + 34 362 + 35 362 + 36 362 + 37 362 + 38 362 + 39 362 + 3a 362 + 3b 362 + 3c 362 + 3d 362 + 3e 362 + 3f 362 + 45 358 + 46 358 + 47 358 + 48 358 + 49 358 + 4a 358 + 4b 358 + 4c 358 + 4d 358 + 4e 358 + 4f 358 + 50 358 + 51 358 + 52 358 + 53 358 + 54 358 + 55 358 + 56 358 + 57 358 + 58 358 + 59 358 + 5a 358 + } + + method 'testPostdomFailure ()V' { + 1 478 + 2 478 + 3 478 + 4 478 + 5 479 + 6 479 + 9 480 + a 480 + b 480 + c 480 + d 480 + e 480 + f 480 + 10 480 + 11 480 + 12 480 + 13 480 + 14 480 + 15 480 + 16 480 + 17 480 + 18 480 + 19 480 + 1a 480 + 1b 480 + 1c 480 + 1d 480 + 1e 480 + 1f 480 + 20 480 + 22 482 23 482 24 482 25 482 @@ -1274,423 +1850,192 @@ class 'pkg/TestGroovyTryReturn' { 36 482 37 482 38 482 - 3a 483 - 3b 483 - 3c 483 - 3d 483 - 3e 483 - 3f 483 - 40 483 - 41 483 - 42 483 - 43 483 - 44 483 - 45 483 - 46 484 - 47 484 - 48 484 - 49 484 - 4a 484 - 4b 484 - 53 492 - 54 492 - 55 492 - 56 492 - 57 492 - 58 492 - 59 492 - 5a 492 - 5b 492 - 5c 492 - 5d 492 - 5e 492 - 5f 492 - 60 492 - 61 492 - 62 492 - 63 492 - 64 492 - 65 492 - 66 492 - 67 492 - 68 492 - 6f 488 - 70 488 - 71 488 - 72 488 - 73 488 - 74 488 - 75 488 - 76 488 - 77 488 - 78 488 - 79 488 - 7a 488 - 7b 488 - 7c 488 - 7d 488 - 7e 488 - 7f 488 - 80 488 - 81 488 - 82 488 - 83 488 - 84 488 - 89 493 - 8a 493 - } - - method 'testFinally6 (ZLjava/util/function/Supplier;)Z' { - 1 498 - 2 498 - 3 498 - 4 498 - 5 499 - 6 499 - 7 499 - b 504 - c 504 - d 504 - e 504 - f 505 - 10 505 - 11 505 - 19 506 - 1a 506 - 1b 506 - 1c 506 - 1d 506 - 1e 506 - 1f 506 - 20 506 - 21 506 - 22 506 - 23 506 - 24 506 - 25 506 - 26 506 - 27 506 - 28 506 - 29 506 - 2a 506 - 2b 506 - 2c 506 - 2d 506 - 2e 506 - 30 509 - 31 509 - 32 509 - 33 509 - 34 509 - 35 509 - 36 509 - 37 509 - 38 509 - 39 509 - 3a 509 - 3b 509 - 3c 510 - 3d 510 - 3e 510 - 3f 510 - 40 510 - 41 510 - 42 510 - 49 512 - 4b 513 - 4c 513 - 4d 513 - 4e 513 - 4f 513 - 50 513 - 51 513 - 52 513 - 53 513 - 54 513 - 55 513 - 56 513 - 57 513 - 58 513 - 59 513 - 5a 513 - 5b 513 - 5c 513 - 5d 513 - 5e 513 - 5f 513 - 60 513 - 62 514 - 63 514 - 64 514 - 65 514 - 66 514 - 67 514 - 68 514 - 69 514 - 6a 514 - 6b 514 - 6c 514 - 6d 514 - 6e 515 - 6f 515 - 70 515 - 71 515 - 72 515 - 73 515 - 74 515 - 7c 523 - 7d 523 - 7e 523 - 7f 523 - 80 523 - 81 523 - 82 523 - 83 523 - 84 523 - 85 523 - 86 523 - 87 523 - 88 523 - 89 523 - 8a 523 - 8b 523 - 8c 523 - 8d 523 - 8e 523 - 8f 523 - 90 523 - 91 523 - 98 519 - 99 519 - 9a 519 - 9b 519 - 9c 519 - 9d 519 - 9e 519 - 9f 519 - a0 519 - a1 519 - a2 519 - a3 519 - a4 519 - a5 519 - a6 519 - a7 519 - a8 519 - a9 519 - aa 519 - ab 519 - ac 519 - ad 519 - b2 524 - b3 524 - b4 524 - } - - method 'testPostdomFailure ()V' { - 1 690 - 2 690 - 3 690 - 4 690 - 5 691 - 6 691 - 9 692 - a 692 - b 692 - c 692 - d 692 - e 692 - f 692 - 10 692 - 11 692 - 12 692 - 13 692 - 14 692 - 15 692 - 16 692 - 17 692 - 18 692 - 19 692 - 1a 692 - 1b 692 - 1c 692 - 1d 692 - 1e 692 - 1f 692 - 20 692 - 22 694 - 23 694 - 24 694 - 25 694 - 26 694 - 27 694 - 28 694 - 29 694 - 2a 694 - 2b 694 - 2c 694 - 2d 694 - 2e 694 - 2f 694 - 30 694 - 31 694 - 32 694 - 33 694 - 34 694 - 35 694 - 36 694 - 37 694 - 38 694 - 3c 697 - 3d 697 - 3e 697 - 3f 697 - 40 697 - 41 697 - 42 697 - 43 697 - 44 697 - 45 697 - 46 697 - 47 697 - 48 697 - 49 697 - 4a 697 - 4b 697 - 4c 697 - 4d 697 - 4e 697 - 4f 697 - 50 697 - 51 697 - 52 697 - 53 697 - 58 698 - 59 699 - 5a 699 - 5b 699 - 5c 699 - 5d 699 - 5e 699 - 5f 699 - 60 699 - 61 699 - 62 699 - 63 699 - 64 699 - 65 699 - 66 699 - 67 699 - 68 699 - 69 699 - 6a 699 - 6b 699 - 6c 699 - 6d 699 - 6e 699 - 6f 699 - 70 699 - c1 704 - c2 704 - c3 704 - c4 704 - c5 704 - cf 707 + 3c 485 + 3d 485 + 3e 485 + 3f 485 + 40 485 + 41 485 + 42 485 + 43 485 + 44 485 + 45 485 + 46 485 + 47 485 + 48 485 + 49 485 + 4a 485 + 4b 485 + 4c 485 + 4d 485 + 4e 485 + 4f 485 + 50 485 + 51 485 + 52 485 + 53 485 + 58 486 + 59 487 + 5a 487 + 5b 487 + 5c 487 + 5d 487 + 5e 487 + 5f 487 + 60 487 + 61 487 + 62 487 + 63 487 + 64 487 + 65 487 + 66 487 + 67 487 + 68 487 + 69 487 + 6a 487 + 6b 487 + 6c 487 + 6d 487 + 6e 487 + 6f 487 + 70 487 + a1 489 + c1 492 + c2 492 + c3 492 + c4 492 + c5 492 + cf 495 } method 'getMetaClass ()Lgroovy/lang/MetaClass;' { - 0 1040 - 1 1040 - 2 1040 - 3 1040 - 5 1040 - 6 1040 - 7 1040 - 8 1041 - a 1044 - c 1044 - d 1044 - e 1044 - f 1044 - 10 1044 - 11 1044 - 12 1045 - 13 1045 - 14 1045 - 15 1045 - 16 1045 + 0 828 + 1 828 + 2 828 + 3 828 + 5 828 + 6 828 + 7 828 + 8 829 + a 832 + c 832 + d 832 + e 832 + f 832 + 10 832 + 11 832 + 12 833 + 13 833 + 14 833 + 15 833 + 16 833 } method 'setMetaClass (Lgroovy/lang/MetaClass;)V' { - 0 1051 - 1 1051 - 2 1051 - 3 1051 - 4 1051 - 5 1052 + 0 839 + 1 839 + 2 839 + 3 839 + 4 839 + 5 840 } method ' ()V' { - 0 1055 - 1 1055 - 2 1055 - 3 1056 + 0 843 + 1 843 + 2 843 + 3 844 } } Lines mapping: -38 <-> 245 -39 <-> 250 -40 <-> 250 -42 <-> 255 -45 <-> 260 -65 <-> 453 -66 <-> 458 -67 <-> 458 -69 <-> 463 -72 <-> 468 -76 <-> 474 -77 <-> 479 -78 <-> 479 -79 <-> 482 -80 <-> 483 -81 <-> 484 -83 <-> 489 -86 <-> 494 -90 <-> 500 -91 <-> 505 -92 <-> 505 -93 <-> 506 -94 <-> 507 -95 <-> 510 -97 <-> 510 -98 <-> 513 -99 <-> 514 -100 <-> 515 -102 <-> 520 -105 <-> 525 -154 <-> 692 -155 <-> 693 -157 <-> 695 -158 <-> 698 -159 <-> 698 -160 <-> 698 -161 <-> 699 -162 <-> 700 -168 <-> 705 -170 <-> 708 +16 <-> 87 +17 <-> 87 +19 <-> 91 +20 <-> 98 +24 <-> 108 +26 <-> 114 +27 <-> 114 +30 <-> 135 +31 <-> 122 +32 <-> 129 +34 <-> 136 +38 <-> 142 +39 <-> 147 +40 <-> 147 +42 <-> 152 +45 <-> 157 +49 <-> 170 +50 <-> 170 +51 <-> 171 +52 <-> 192 +54 <-> 214 +55 <-> 215 +56 <-> 233 +58 <-> 233 +60 <-> 179 +61 <-> 259 +65 <-> 265 +66 <-> 270 +67 <-> 270 +69 <-> 275 +72 <-> 280 +76 <-> 286 +77 <-> 291 +78 <-> 291 +79 <-> 294 +80 <-> 295 +81 <-> 296 +83 <-> 301 +86 <-> 306 +90 <-> 312 +91 <-> 317 +92 <-> 317 +93 <-> 318 +94 <-> 319 +95 <-> 322 +97 <-> 322 +98 <-> 325 +99 <-> 326 +100 <-> 327 +102 <-> 332 +105 <-> 337 +109 <-> 344 +111 <-> 351 +112 <-> 351 +113 <-> 351 +116 <-> 363 +117 <-> 359 +118 <-> 373 +154 <-> 480 +155 <-> 481 +157 <-> 483 +158 <-> 486 +159 <-> 486 +160 <-> 486 +161 <-> 487 +162 <-> 488 +165 <-> 490 +168 <-> 493 +170 <-> 496 Not mapped: +18 +28 +29 41 43 +59 68 70 82 84 101 103 +114 +115 +119 163 164 -165 166 167 169 diff --git a/testData/results/pkg/TestLoopFinally.dec b/testData/results/pkg/TestLoopFinally.dec index c025c78894..2d547d239b 100644 --- a/testData/results/pkg/TestLoopFinally.dec +++ b/testData/results/pkg/TestLoopFinally.dec @@ -284,7 +284,7 @@ public class TestLoopFinally { public void test10(File file, int i) { try { new Scanner(file);// 282 - } catch (Exception var8) { + } catch (Exception var8) {// 283 } finally { for (int k = 0; k < i; k++) {// 285 System.out.println(k);// 286 @@ -842,6 +842,7 @@ class 'pkg/TestLoopFinally' { method 'test10 (Ljava/io/File;I)V' { 4 285 + 20 286 3a 288 3b 288 3c 288 @@ -967,6 +968,7 @@ Lines mapping: 277 <-> 278 278 <-> 279 282 <-> 286 +283 <-> 287 285 <-> 289 286 <-> 290 289 <-> 293 @@ -999,5 +1001,4 @@ Not mapped: 254 274 275 -283 288 diff --git a/testData/results/pkg/TestTryCatchFinally.dec b/testData/results/pkg/TestTryCatchFinally.dec index dc0b2eacf6..f1d406015e 100644 --- a/testData/results/pkg/TestTryCatchFinally.dec +++ b/testData/results/pkg/TestTryCatchFinally.dec @@ -39,7 +39,7 @@ public class TestTryCatchFinally { void testEmptyCatch(String msg) { try { System.out.println(msg);// 62 - } catch (RuntimeException var6) { + } catch (RuntimeException var6) {// 63 } finally { System.out.println("Bye");// 65 } @@ -132,6 +132,7 @@ class 'pkg/TestTryCatchFinally' { 4 40 5 40 6 40 + 12 41 1f 43 20 43 21 43 @@ -161,6 +162,7 @@ Lines mapping: 55 <-> 33 57 <-> 36 62 <-> 41 +63 <-> 42 65 <-> 44 67 <-> 46 Not mapped: @@ -168,5 +170,4 @@ Not mapped: 32 35 56 -63 66 diff --git a/testData/results/pkg/TestTryCatchNoIncrement.dec b/testData/results/pkg/TestTryCatchNoIncrement.dec index 1ff3dacdd9..f1a3d351c9 100644 --- a/testData/results/pkg/TestTryCatchNoIncrement.dec +++ b/testData/results/pkg/TestTryCatchNoIncrement.dec @@ -45,7 +45,7 @@ public class TestTryCatchNoIncrement { } item = (String)items.get(i);// 42 - } catch (Throwable ex2) { + } catch (Throwable ex2) {// 49 ex2.printStackTrace(); break; } @@ -199,6 +199,7 @@ class 'pkg/TestTryCatchNoIncrement' { 39 55 3a 55 3b 55 + 42 47 43 35 44 35 45 35 @@ -225,6 +226,7 @@ Lines mapping: 41 <-> 56 42 <-> 47 44 <-> 53 +49 <-> 48 50 <-> 36 52 <-> 37 Not mapped: @@ -235,5 +237,4 @@ Not mapped: 36 45 46 -49 51 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec index a85d8a65e3..730e4fe67d 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec @@ -41,7 +41,7 @@ public class TestTryFinallyMarkerExceptionsInvalid { System.out.println("Hello");// 44 var5 = false; break label26; - } catch (NullPointerException npe) { + } catch (NullPointerException npe) {// 45 var5 = false; } finally { if (var5) { @@ -91,8 +91,8 @@ public class TestTryFinallyMarkerExceptionsInvalid { try { System.out.println("Hello");// 81 break label26; - } catch (NullPointerException var5) { - npe = var5;// 82 + } catch (NullPointerException var5) {// 82 + npe = var5; } finally { System.out.println("Finally");// 86 } @@ -486,6 +486,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 40 6 40 7 40 + b 43 c 51 d 51 e 51 @@ -530,7 +531,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 91 6 91 7 91 - b 94 + b 93 14 99 15 99 16 99 @@ -1508,13 +1509,14 @@ Lines mapping: 36 <-> 31 37 <-> 32 44 <-> 41 +45 <-> 44 46 <-> 52 48 <-> 48 52 <-> 55 55 <-> 56 56 <-> 57 81 <-> 92 -82 <-> 95 +82 <-> 94 84 <-> 100 86 <-> 97 93 <-> 103 @@ -1665,7 +1667,6 @@ Not mapped: 12 25 31 -45 47 49 50 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec index 6e39fa1f5e..dcdab4677f 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec @@ -41,7 +41,7 @@ public class TestTryFinallyMarkerExceptionsInvalid { System.out.println("Hello");// 44 var5 = false; break label26; - } catch (NullPointerException npe) { + } catch (NullPointerException npe) {// 45 var5 = false; } finally { if (var5) { @@ -91,8 +91,8 @@ public class TestTryFinallyMarkerExceptionsInvalid { try { System.out.println("Hello");// 81 break label26; - } catch (NullPointerException var5) { - npe = var5;// 82 + } catch (NullPointerException var5) {// 82 + npe = var5; } finally { System.out.println("Finally");// 86 } @@ -486,6 +486,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 40 6 40 7 40 + b 43 c 51 d 51 e 51 @@ -530,7 +531,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 91 6 91 7 91 - b 94 + b 93 14 99 15 99 16 99 @@ -1508,13 +1509,14 @@ Lines mapping: 36 <-> 31 37 <-> 32 44 <-> 41 +45 <-> 44 46 <-> 52 48 <-> 48 52 <-> 55 55 <-> 56 56 <-> 57 81 <-> 92 -82 <-> 95 +82 <-> 94 84 <-> 100 86 <-> 97 93 <-> 103 @@ -1665,7 +1667,6 @@ Not mapped: 12 25 31 -45 47 49 50 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec index 79c9104aca..e3af2683ea 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec @@ -41,7 +41,7 @@ public class TestTryFinallyMarkerExceptionsInvalid { System.out.println("Hello");// 44 var5 = false; break label26; - } catch (NullPointerException npe) { + } catch (NullPointerException npe) {// 45 var5 = false; } finally { if (var5) { @@ -91,8 +91,8 @@ public class TestTryFinallyMarkerExceptionsInvalid { try { System.out.println("Hello");// 81 break label26; - } catch (NullPointerException var5) { - npe = var5;// 82 + } catch (NullPointerException var5) {// 82 + npe = var5; } finally { System.out.println("Finally");// 86 } @@ -486,6 +486,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 40 6 40 7 40 + b 43 c 51 d 51 e 51 @@ -530,7 +531,7 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5 91 6 91 7 91 - b 94 + b 93 14 99 15 99 16 99 @@ -1508,13 +1509,14 @@ Lines mapping: 36 <-> 31 37 <-> 32 44 <-> 41 +45 <-> 44 46 <-> 52 48 <-> 48 52 <-> 55 55 <-> 56 56 <-> 57 81 <-> 92 -82 <-> 95 +82 <-> 94 84 <-> 100 86 <-> 97 93 <-> 103 @@ -1665,7 +1667,6 @@ Not mapped: 12 25 31 -45 47 49 50 @@ -1759,4 +1760,4 @@ Not mapped: 431 438 439 -444 +444 \ No newline at end of file diff --git a/testData/results/pkg/TestTryReturn.dec b/testData/results/pkg/TestTryReturn.dec index 76f5c13342..51009991df 100644 --- a/testData/results/pkg/TestTryReturn.dec +++ b/testData/results/pkg/TestTryReturn.dec @@ -197,7 +197,7 @@ public class TestTryReturn { } catch (Exception var9) {// 161 System.out.println(3);// 162 } finally { - continue; + continue;// 165 } } finally { byte var7 = 28;// 168 @@ -587,6 +587,7 @@ class 'pkg/TestTryReturn' { 26 197 27 197 28 197 + 2f 199 3a 202 3b 202 3c 202 @@ -755,6 +756,7 @@ Lines mapping: 160 <-> 196 161 <-> 197 162 <-> 198 +165 <-> 200 168 <-> 203 171 <-> 206 176 <-> 210 @@ -792,7 +794,6 @@ Not mapped: 84 103 118 -165 169 186 203 From 4bd694591cd072784462b36bb3abdf689895ccb5 Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Sat, 20 Jun 2026 20:05:04 +0200 Subject: [PATCH 21/29] Fix bug when the implicit exits don't match (#598) --- .../modules/decompiler/FinallyProcessor.java | 15 +- .../TestTryFinallyMarkerExceptionsInvalid.dec | 2232 +++++++++-------- ...estTryFinallyMarkerExceptionsInvalid_1.dec | 1763 ------------- ...estTryFinallyMarkerExceptionsInvalid_2.dec | 1763 ------------- ...TestTryFinallyMarkerExceptionsInvalid.java | 32 +- 5 files changed, 1243 insertions(+), 4562 deletions(-) delete mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec delete mode 100644 testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java index 23180279e3..d6a06dea8d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java @@ -582,15 +582,12 @@ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, } // INFO: empty basic blocks may remain in the graph! - BasicBlock trueExit = null; for (Entry entry : mapLast.entrySet()) { BasicBlock last = entry.getKey(); if (entry.getValue() == ExitType.IMPLICIT_EXIT) { removeExceptionInstructionsEx(last, 2, finallytype); graph.getFinallyExits().add(last); - ValidationHelper.validateTrue(trueExit == null, "More than one true exit"); - trueExit = last; } } @@ -626,6 +623,8 @@ record BlockStackEntry( stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<>())); + BasicBlock implicitNext = null; + while (!stack.isEmpty()) { BlockStackEntry entry = stack.remove(0); @@ -662,8 +661,16 @@ record BlockStackEntry( stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars)); } } else { - if (exitType == ExitType.EXPLICIT_EXIT || exitType == ExitType.IMPLICIT_EXIT) { + if (exitType == ExitType.EXPLICIT_EXIT) { + mapNext.put(Pair.of(blockSample, sucSample), new FinallyExit(blockSample, sucSample, exitType)); + } else if (exitType == ExitType.IMPLICIT_EXIT) { mapNext.put(Pair.of(blockSample, sucSample), new FinallyExit(blockSample, sucSample, exitType)); + if (implicitNext == null) { + implicitNext = sucSample; + } else if (implicitNext != sucSample){ + // Exits don't match + return null; + } } } } diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec index 730e4fe67d..ed14e967e0 100644 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec +++ b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid.dec @@ -166,227 +166,261 @@ public class TestTryFinallyMarkerExceptionsInvalid { System.out.println("Bye");// 141 }// 142 - public void testMultiImplicitExits(int i) { + // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. + public void testMultiImplicitExitsBad(int i) { + boolean var4 = false /* VF: Semaphore variable */; + try { + var4 = true; System.out.println("Hello");// 146 + var4 = false; } finally { - System.out.println("Finally");// 148 - if (i > 0) {// 149 - System.out.println("Positive!");// 150 - } else if (i == 0) {// 152 - System.out.println("ZERO");// 153 - } else { - System.out.println("Negative!");// 156 + if (var4) { + System.out.println("Finally");// 148 + if (i > 0) {// 149 + System.out.println("Positive!");// 150 + } else if (i == 0) {// 152 + System.out.println("ZERO");// 153 + } else { + System.out.println("Negative!");// 156 + } } } - System.out.println("Bye 2");// 167 + System.out.println("Finally");// 161 + if (i > 0) {// 162 + System.out.println("Positive!");// 163 + System.out.println("Bye 1");// 164 + } else if (i == 0) {// 165 + System.out.println("ZERO");// 166 + System.out.println("Bye 2");// 167 + } else { + System.out.println("Negative!");// 169 + System.out.println("Bye 3");// 170 + } }// 173 + public void testMultiImplicitExitsGood(int i) { + try { + System.out.println("Hello");// 178 + } finally { + System.out.println("Finally");// 180 + if (i > 0) {// 181 + System.out.println("Positive!");// 182 + } else if (i == 0) {// 184 + System.out.println("ZERO");// 185 + } else { + System.out.println("Negative!");// 188 + } + } + + System.out.println("Bye");// 202 + }// 203 + public void testConfusion1(String a, String b) { try { - System.out.println("Hello");// 177 + System.out.println("Hello");// 207 } finally { - System.out.println("Finally");// 179 - System.out.println(a);// 180 + System.out.println("Finally");// 209 + System.out.println(a);// 210 } - System.out.println("Bye");// 187 - }// 188 + System.out.println("Bye");// 217 + }// 218 public void testConfusion2() { try { - System.out.println("Hello");// 193 + System.out.println("Hello");// 223 } finally { - System.out.println("Finally");// 195 - String x = "X";// 196 - String y = "Y";// 197 - String z = "Z";// 198 - x = x + z;// 199 - y = y + x;// 200 - z = z + y;// 201 - System.out.println(z);// 202 + System.out.println("Finally");// 225 + String x = "X";// 226 + String y = "Y";// 227 + String z = "Z";// 228 + x = x + z;// 229 + y = y + x;// 230 + z = z + y;// 231 + System.out.println(z);// 232 } - System.out.println("Bye");// 215 - }// 216 + System.out.println("Bye");// 245 + }// 246 public void testMismatchedSwitch(int i) { try { - System.out.println("Hello");// 221 + System.out.println("Hello");// 251 } finally { - System.out.println("Finally");// 223 - switch (i) {// 224 + System.out.println("Finally");// 253 + switch (i) {// 254 case 10: - System.out.println("10");// 226 + System.out.println("10");// 256 case 9: - System.out.println("9");// 228 + System.out.println("9");// 258 case 8: - System.out.println("8");// 230 + System.out.println("8");// 260 case 7: - System.out.println("7");// 232 + System.out.println("7");// 262 case 6: - System.out.println("6");// 234 + System.out.println("6");// 264 case 5: - System.out.println("5");// 236 + System.out.println("5");// 266 case 4: - System.out.println("4");// 238 + System.out.println("4");// 268 case 3: - System.out.println("3");// 240 + System.out.println("3");// 270 case 2: - System.out.println("2");// 242 + System.out.println("2");// 272 case 1: - System.out.println("1");// 244 + System.out.println("1");// 274 case 0: - System.out.println("Lift off!");// 246 + System.out.println("Lift off!");// 276 } } - System.out.println("Bye");// 277 - }// 278 + System.out.println("Bye");// 307 + }// 308 public void testMismatchedOutputExit(int a, int b) { label53: - while (a > 0) {// 282 - System.out.println("A: " + a);// 283 - a--;// 284 + while (a > 0) {// 312 + System.out.println("A: " + a);// 313 + a--;// 314 - for (; b > 0; System.out.println("Beep")) {// 286 310 - a++;// 287 - System.out.println("B: " + b);// 288 + for (; b > 0; System.out.println("Beep")) {// 316 340 + a++;// 317 + System.out.println("B: " + b);// 318 try { - b--;// 291 - System.out.println("Hello");// 292 + b--;// 321 + System.out.println("Hello");// 322 } finally { - System.out.println("Finally");// 294 - if (a > b) {// 295 - a--;// 296 - continue label53;// 297 + System.out.println("Finally");// 324 + if (a > b) {// 325 + a--;// 326 + continue label53;// 327 } - System.out.println("Boop");// 299 + System.out.println("Boop");// 329 } } - System.out.println("BLORB");// 312 + System.out.println("BLORB");// 342 } - System.out.println("Bye");// 314 - }// 315 + System.out.println("Bye");// 344 + }// 345 public void testMismatchedOutputExit3(int a, int b, int c) { label84: - while (a > 0) {// 320 - System.out.println("A: " + a);// 321 - a--;// 322 + while (a > 0) {// 350 + System.out.println("A: " + a);// 351 + a--;// 352 label82: - while (b > 0) {// 324 - a++;// 325 - System.out.println("B: " + b);// 326 + while (b > 0) {// 354 + a++;// 355 + System.out.println("B: " + b);// 356 - for (; c > 0; System.out.println("Lost")) {// 329 371 - c -= b;// 330 + for (; c > 0; System.out.println("Lost")) {// 359 401 + c -= b;// 360 try { - b--;// 337 - System.out.println("Hello");// 338 - if (c < a) {// 339 + b--;// 367 + System.out.println("Hello");// 368 + if (c < a) {// 369 continue label82; } } finally { - System.out.println("Finally");// 343 - if (a > b) {// 344 - a--;// 345 - continue label84;// 346 + System.out.println("Finally");// 373 + if (a > b) {// 374 + a--;// 375 + continue label84;// 376 } - System.out.println("Boop");// 348 + System.out.println("Boop");// 378 } } - System.out.println("Beep");// 373 + System.out.println("Beep");// 403 } - System.out.println("BLORB");// 375 + System.out.println("BLORB");// 405 } - System.out.println("Bye");// 377 - }// 378 + System.out.println("Bye");// 407 + }// 408 public void testMismatchedOutputExitReturn(int a, int b) { label54: - while (a > 0) {// 383 - System.out.println("A: " + a);// 384 - a--;// 385 + while (a > 0) {// 413 + System.out.println("A: " + a);// 414 + a--;// 415 - for (; b > 0; System.out.println("Beep")) {// 387 411 - a++;// 388 - System.out.println("B: " + b);// 389 + for (; b > 0; System.out.println("Beep")) {// 417 441 + a++;// 418 + System.out.println("B: " + b);// 419 try { - b--;// 392 - System.out.println("Hello");// 393 + b--;// 422 + System.out.println("Hello");// 423 } finally { - System.out.println("Finally");// 395 - if (a > b) {// 396 - a--;// 397 - continue label54;// 398 + System.out.println("Finally");// 425 + if (a > b) {// 426 + a--;// 427 + continue label54;// 428 } - System.out.println("Boop");// 400 + System.out.println("Boop");// 430 } } - System.out.println("BLORB");// 413 + System.out.println("BLORB");// 443 } - System.out.println("Bye");// 415 - }// 416 + System.out.println("Bye");// 445 + }// 446 // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. public void testMismatchedOutputExitReturnInner(int a, int b) { - while (a > 0) {// 420 - System.out.println("A: " + a);// 421 - a--;// 422 + while (a > 0) {// 450 + System.out.println("A: " + a);// 451 + a--;// 452 - while (b > 0) {// 424 - a++;// 425 - System.out.println("B: " + b);// 426 + while (b > 0) {// 454 + a++;// 455 + System.out.println("B: " + b);// 456 boolean var5 = false /* VF: Semaphore variable */; try { var5 = true; - b--;// 429 - System.out.println("Hello");// 430 + b--;// 459 + System.out.println("Hello");// 460 var5 = false; } finally { if (var5) { - System.out.println("Finally");// 432 - if (a > b) {// 433 - a--;// 434 - return;// 435 + System.out.println("Finally");// 462 + if (a > b) {// 463 + a--;// 464 + return;// 465 } - System.out.println("Boop");// 437 + System.out.println("Boop");// 467 } } - System.out.println("Finally");// 441 - if (a > b) {// 442 - a--;// 443 + System.out.println("Finally");// 471 + if (a > b) {// 472 + a--;// 473 } else { - System.out.println("Boop");// 446 - System.out.println("Beep");// 448 + System.out.println("Boop");// 476 + System.out.println("Beep");// 478 } } - System.out.println("BLORB");// 450 + System.out.println("BLORB");// 480 } - System.out.println("Bye");// 452 - }// 453 + System.out.println("Bye");// 482 + }// 483 } class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { @@ -709,714 +743,728 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 52 166 } - method 'testMultiImplicitExits (I)V' { - 0 170 - 1 170 - 2 170 - 3 170 - 4 170 - 5 170 - 6 170 - 7 170 - c 172 - d 172 - e 172 - f 172 - 10 172 - 11 172 - 12 172 - 13 172 - 14 173 - 15 173 - 16 173 - 17 173 - 18 174 - 19 174 - 1a 174 - 1b 174 - 1c 174 - 1d 174 - 1e 174 - 1f 174 - 22 175 - 23 175 - 24 175 - 25 175 - 26 176 - 27 176 - 28 176 - 29 176 - 2a 176 - 2b 176 - 2c 176 - 2d 176 - 30 178 - 31 178 - 32 178 - 33 178 - 34 178 - 35 178 - 36 178 - 37 178 - 65 182 - 66 182 - 67 182 - 68 182 - 69 182 - 6a 182 - 6b 182 - 6c 182 - 80 183 + method 'testMultiImplicitExitsBad (I)V' { + 0 174 + 1 174 + 2 174 + 3 174 + 4 174 + 5 174 + 6 174 + 7 174 + c 178 + d 178 + e 178 + f 178 + 10 178 + 11 178 + 12 178 + 13 178 + 14 179 + 15 179 + 16 179 + 17 179 + 18 180 + 19 180 + 1a 180 + 1b 180 + 1c 180 + 1d 180 + 1e 180 + 1f 180 + 22 181 + 23 181 + 24 181 + 25 181 + 26 182 + 27 182 + 28 182 + 29 182 + 2a 182 + 2b 182 + 2c 182 + 2d 182 + 30 184 + 31 184 + 32 184 + 33 184 + 34 184 + 35 184 + 36 184 + 37 184 + 3a 189 + 3b 189 + 3c 189 + 3d 189 + 3e 189 + 3f 189 + 40 189 + 41 189 + 42 190 + 43 190 + 44 190 + 45 190 + 46 191 + 47 191 + 48 191 + 49 191 + 4a 191 + 4b 191 + 4c 191 + 4d 191 + 4e 192 + 4f 192 + 50 192 + 51 192 + 52 192 + 53 192 + 54 192 + 55 192 + 59 193 + 5a 193 + 5b 193 + 5c 193 + 5d 194 + 5e 194 + 5f 194 + 60 194 + 61 194 + 62 194 + 63 194 + 64 194 + 65 195 + 66 195 + 67 195 + 68 195 + 69 195 + 6a 195 + 6b 195 + 6c 195 + 70 197 + 71 197 + 72 197 + 73 197 + 74 197 + 75 197 + 76 197 + 77 197 + 78 198 + 79 198 + 7a 198 + 7b 198 + 7c 198 + 7d 198 + 7e 198 + 7f 198 + 80 200 + } + + method 'testMultiImplicitExitsGood (I)V' { + 0 204 + 1 204 + 2 204 + 3 204 + 4 204 + 5 204 + 6 204 + 7 204 + c 206 + d 206 + e 206 + f 206 + 10 206 + 11 206 + 12 206 + 13 206 + 14 207 + 15 207 + 16 207 + 17 207 + 18 208 + 19 208 + 1a 208 + 1b 208 + 1c 208 + 1d 208 + 1e 208 + 1f 208 + 22 209 + 23 209 + 24 209 + 25 209 + 26 210 + 27 210 + 28 210 + 29 210 + 2a 210 + 2b 210 + 2c 210 + 2d 210 + 30 212 + 31 212 + 32 212 + 33 212 + 34 212 + 35 212 + 36 212 + 37 212 + 68 216 + 69 216 + 6a 216 + 6b 216 + 6c 216 + 6d 216 + 6e 216 + 6f 216 + 70 217 } method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { - 0 187 - 1 187 - 2 187 - 3 187 - 4 187 - 5 187 - 6 187 - 7 187 - c 189 - d 189 - e 189 - f 189 - 10 189 - 11 189 - 12 189 - 13 189 - 14 190 - 15 190 - 16 190 - 17 190 - 18 190 - 19 190 - 1a 190 - 2c 193 - 2d 193 - 2e 193 - 2f 193 - 30 193 - 31 193 - 32 193 - 33 193 - 34 194 + 0 221 + 1 221 + 2 221 + 3 221 + 4 221 + 5 221 + 6 221 + 7 221 + c 223 + d 223 + e 223 + f 223 + 10 223 + 11 223 + 12 223 + 13 223 + 14 224 + 15 224 + 16 224 + 17 224 + 18 224 + 19 224 + 1a 224 + 2c 227 + 2d 227 + 2e 227 + 2f 227 + 30 227 + 31 227 + 32 227 + 33 227 + 34 228 } method 'testConfusion2 ()V' { - 0 198 - 1 198 - 2 198 - 3 198 - 4 198 - 5 198 - 6 198 - 7 198 - d 200 - e 200 - f 200 - 10 200 - 11 200 - 12 200 - 13 200 - 14 200 - 15 201 - 16 201 - 17 201 - 18 202 - 19 202 - 1a 202 - 1b 203 - 1c 203 - 1d 203 - 25 204 - 29 204 - 2d 204 - 2e 204 - 2f 204 - 30 204 - 38 205 - 3c 205 - 40 205 - 41 205 - 42 205 - 43 205 - 4b 206 - 4f 206 - 53 206 - 54 206 - 55 206 - 56 206 - 57 207 - 58 207 - 59 207 - 5a 207 - 5b 207 - 5c 207 - 5d 207 - b2 210 - b3 210 - b4 210 - b5 210 - b6 210 - b7 210 - b8 210 - b9 210 - ba 211 + 0 232 + 1 232 + 2 232 + 3 232 + 4 232 + 5 232 + 6 232 + 7 232 + d 234 + e 234 + f 234 + 10 234 + 11 234 + 12 234 + 13 234 + 14 234 + 15 235 + 16 235 + 17 235 + 18 236 + 19 236 + 1a 236 + 1b 237 + 1c 237 + 1d 237 + 25 238 + 29 238 + 2d 238 + 2e 238 + 2f 238 + 30 238 + 38 239 + 3c 239 + 40 239 + 41 239 + 42 239 + 43 239 + 4b 240 + 4f 240 + 53 240 + 54 240 + 55 240 + 56 240 + 57 241 + 58 241 + 59 241 + 5a 241 + 5b 241 + 5c 241 + 5d 241 + b2 244 + b3 244 + b4 244 + b5 244 + b6 244 + b7 244 + b8 244 + b9 244 + ba 245 } method 'testMismatchedSwitch (I)V' { - 0 215 - 1 215 - 2 215 - 3 215 - 4 215 - 5 215 - 6 215 - 7 215 - c 217 - d 217 - e 217 - f 217 - 10 217 - 11 217 - 12 217 - 13 217 - 14 218 - 15 218 - 16 218 - 17 218 - 18 218 - 19 218 - 1a 218 - 1b 218 - 1c 218 - 1d 218 - 1e 218 - 1f 218 - 20 218 - 21 218 - 22 218 - 23 218 - 24 218 - 25 218 - 26 218 - 27 218 - 28 218 - 29 218 - 2a 218 - 2b 218 - 2c 218 - 2d 218 - 2e 218 - 2f 218 - 30 218 - 31 218 - 32 218 - 33 218 - 34 218 - 35 218 - 36 218 - 37 218 - 38 218 - 39 218 - 3a 218 - 3b 218 - 3c 218 - 3d 218 - 3e 218 - 3f 218 - 40 218 - 41 218 - 42 218 - 43 218 - 44 218 - 45 218 - 46 218 - 47 218 - 48 218 - 49 218 - 4a 218 - 4b 218 - 4c 218 - 4d 218 - 4e 218 - 4f 218 - 50 220 - 51 220 - 52 220 - 53 220 - 54 220 - 55 220 - 56 220 - 57 220 - 58 222 - 59 222 - 5a 222 - 5b 222 - 5c 222 - 5d 222 - 5e 222 - 5f 222 - 60 224 - 61 224 - 62 224 - 63 224 - 64 224 - 65 224 - 66 224 - 67 224 - 68 226 - 69 226 - 6a 226 - 6b 226 - 6c 226 - 6d 226 - 6e 226 - 6f 226 - 70 228 - 71 228 - 72 228 - 73 228 - 74 228 - 75 228 - 76 228 - 77 228 - 78 230 - 79 230 - 7a 230 - 7b 230 - 7c 230 - 7d 230 - 7e 230 - 7f 230 - 80 232 - 81 232 - 82 232 - 83 232 - 84 232 - 85 232 - 86 232 - 87 232 - 88 234 - 89 234 - 8a 234 - 8b 234 - 8c 234 - 8d 234 - 8e 234 - 8f 234 - 90 236 - 91 236 - 92 236 - 93 236 - 94 236 - 95 236 - 96 236 - 97 236 - 98 238 - 99 238 - 9a 238 - 9b 238 - 9c 238 - 9d 238 - 9e 238 - 9f 238 - a0 240 - a1 240 - a2 240 - a3 240 - a4 240 - a5 240 - a6 240 - a7 240 - 144 244 - 145 244 - 146 244 - 147 244 - 148 244 - 149 244 - 14a 244 - 14b 244 - 14c 245 - } - - method 'testMismatchedOutputExit (II)V' { 0 249 1 249 2 249 3 249 - 4 250 - 5 250 - 6 250 - e 250 - f 250 - 13 250 - 17 250 - 18 250 - 19 250 - 1a 250 - 1b 250 - 1c 250 - 1d 251 - 1e 251 - 1f 251 - 20 253 - 21 253 - 22 253 - 23 253 - 24 254 - 25 254 - 26 254 - 27 255 - 28 255 - 29 255 - 31 255 - 32 255 - 36 255 - 3a 255 - 3b 255 - 3c 255 - 3d 255 - 3e 255 - 3f 255 - 40 258 - 41 258 - 42 258 - 43 259 - 44 259 - 45 259 - 46 259 - 47 259 - 48 259 - 49 259 - 4a 259 - 4f 261 - 50 261 - 51 261 - 52 261 - 53 261 - 54 261 - 55 261 - 56 261 - 57 262 - 58 262 - 59 262 - 5a 262 - 5b 262 - 5c 263 - 5d 263 - 5e 263 - 5f 264 - 62 267 - 63 267 - 64 267 - 65 267 - 66 267 - 67 267 - 68 267 - 69 267 - 87 253 - 88 253 - 89 253 - 8a 253 - 8b 253 - 8c 253 - 8d 253 - 8e 253 - 92 271 - 93 271 - 94 271 - 95 271 - 96 271 - 97 271 - 98 271 - 99 271 - 9d 274 - 9e 274 - 9f 274 + 4 249 + 5 249 + 6 249 + 7 249 + c 251 + d 251 + e 251 + f 251 + 10 251 + 11 251 + 12 251 + 13 251 + 14 252 + 15 252 + 16 252 + 17 252 + 18 252 + 19 252 + 1a 252 + 1b 252 + 1c 252 + 1d 252 + 1e 252 + 1f 252 + 20 252 + 21 252 + 22 252 + 23 252 + 24 252 + 25 252 + 26 252 + 27 252 + 28 252 + 29 252 + 2a 252 + 2b 252 + 2c 252 + 2d 252 + 2e 252 + 2f 252 + 30 252 + 31 252 + 32 252 + 33 252 + 34 252 + 35 252 + 36 252 + 37 252 + 38 252 + 39 252 + 3a 252 + 3b 252 + 3c 252 + 3d 252 + 3e 252 + 3f 252 + 40 252 + 41 252 + 42 252 + 43 252 + 44 252 + 45 252 + 46 252 + 47 252 + 48 252 + 49 252 + 4a 252 + 4b 252 + 4c 252 + 4d 252 + 4e 252 + 4f 252 + 50 254 + 51 254 + 52 254 + 53 254 + 54 254 + 55 254 + 56 254 + 57 254 + 58 256 + 59 256 + 5a 256 + 5b 256 + 5c 256 + 5d 256 + 5e 256 + 5f 256 + 60 258 + 61 258 + 62 258 + 63 258 + 64 258 + 65 258 + 66 258 + 67 258 + 68 260 + 69 260 + 6a 260 + 6b 260 + 6c 260 + 6d 260 + 6e 260 + 6f 260 + 70 262 + 71 262 + 72 262 + 73 262 + 74 262 + 75 262 + 76 262 + 77 262 + 78 264 + 79 264 + 7a 264 + 7b 264 + 7c 264 + 7d 264 + 7e 264 + 7f 264 + 80 266 + 81 266 + 82 266 + 83 266 + 84 266 + 85 266 + 86 266 + 87 266 + 88 268 + 89 268 + 8a 268 + 8b 268 + 8c 268 + 8d 268 + 8e 268 + 8f 268 + 90 270 + 91 270 + 92 270 + 93 270 + 94 270 + 95 270 + 96 270 + 97 270 + 98 272 + 99 272 + 9a 272 + 9b 272 + 9c 272 + 9d 272 + 9e 272 + 9f 272 a0 274 a1 274 a2 274 a3 274 a4 274 - a5 275 + a5 274 + a6 274 + a7 274 + 144 278 + 145 278 + 146 278 + 147 278 + 148 278 + 149 278 + 14a 278 + 14b 278 + 14c 279 } - method 'testMismatchedOutputExit3 (III)V' { - 0 279 - 1 279 - 2 279 - 3 279 - 4 280 - 5 280 - 6 280 - e 280 - f 280 - 13 280 - 17 280 - 18 280 - 19 280 - 1a 280 - 1b 280 - 1c 280 - 1d 281 - 1e 281 - 1f 281 - 20 284 - 21 284 - 22 284 - 23 284 - 24 285 - 25 285 - 26 285 - 27 286 - 28 286 - 29 286 - 31 286 - 32 286 - 36 286 - 3a 286 - 3b 286 - 3c 286 - 3d 286 - 3e 286 - 3f 286 - 40 288 - 41 288 - 42 288 - 43 288 - 45 289 - 47 289 - 48 292 - 49 292 - 4a 292 - 4b 293 - 4c 293 - 4d 293 - 4e 293 - 4f 293 - 50 293 - 51 293 - 52 293 - 53 294 - 54 294 - 55 294 - 56 294 - 57 294 - 60 298 - 61 298 - 62 298 - 63 298 - 64 298 - 65 298 - 66 298 - 67 298 - 68 299 - 69 299 - 6a 299 - 6b 299 - 6c 299 - 6d 300 - 6e 300 - 6f 300 - 70 301 - 73 304 - 74 304 - 75 304 - 76 304 - 77 304 - 78 304 - 79 304 - 7a 304 - ba 288 - bb 288 - bc 288 - bd 288 - be 288 - bf 288 - c0 288 - c1 288 - c5 308 - c6 308 - c7 308 - c8 308 - c9 308 - ca 308 - cb 308 - cc 308 - d0 311 - d1 311 - d2 311 - d3 311 - d4 311 - d5 311 - d6 311 - d7 311 - db 314 - dc 314 - dd 314 - de 314 - df 314 - e0 314 - e1 314 - e2 314 - e3 315 + method 'testMismatchedOutputExit (II)V' { + 0 283 + 1 283 + 2 283 + 3 283 + 4 284 + 5 284 + 6 284 + e 284 + f 284 + 13 284 + 17 284 + 18 284 + 19 284 + 1a 284 + 1b 284 + 1c 284 + 1d 285 + 1e 285 + 1f 285 + 20 287 + 21 287 + 22 287 + 23 287 + 24 288 + 25 288 + 26 288 + 27 289 + 28 289 + 29 289 + 31 289 + 32 289 + 36 289 + 3a 289 + 3b 289 + 3c 289 + 3d 289 + 3e 289 + 3f 289 + 40 292 + 41 292 + 42 292 + 43 293 + 44 293 + 45 293 + 46 293 + 47 293 + 48 293 + 49 293 + 4a 293 + 4f 295 + 50 295 + 51 295 + 52 295 + 53 295 + 54 295 + 55 295 + 56 295 + 57 296 + 58 296 + 59 296 + 5a 296 + 5b 296 + 5c 297 + 5d 297 + 5e 297 + 5f 298 + 62 301 + 63 301 + 64 301 + 65 301 + 66 301 + 67 301 + 68 301 + 69 301 + 87 287 + 88 287 + 89 287 + 8a 287 + 8b 287 + 8c 287 + 8d 287 + 8e 287 + 92 305 + 93 305 + 94 305 + 95 305 + 96 305 + 97 305 + 98 305 + 99 305 + 9d 308 + 9e 308 + 9f 308 + a0 308 + a1 308 + a2 308 + a3 308 + a4 308 + a5 309 } - method 'testMismatchedOutputExitReturn (II)V' { - 0 319 - 1 319 - 2 319 - 3 319 - 4 320 - 5 320 - 6 320 - e 320 - f 320 - 13 320 - 17 320 - 18 320 - 19 320 - 1a 320 - 1b 320 - 1c 320 - 1d 321 - 1e 321 - 1f 321 - 20 323 - 21 323 - 22 323 - 23 323 - 24 324 - 25 324 - 26 324 - 27 325 - 28 325 - 29 325 - 31 325 - 32 325 - 36 325 - 3a 325 - 3b 325 - 3c 325 - 3d 325 - 3e 325 - 3f 325 - 40 328 - 41 328 - 42 328 - 43 329 - 44 329 - 45 329 - 46 329 - 47 329 - 48 329 - 49 329 - 4a 329 - 4f 331 - 50 331 - 51 331 - 52 331 - 53 331 - 54 331 - 55 331 - 56 331 - 57 332 - 58 332 - 59 332 - 5a 332 - 5b 332 - 5c 333 - 5d 333 - 5e 333 - 5f 334 - 62 337 - 63 337 - 64 337 - 65 337 - 66 337 - 67 337 - 68 337 - 69 337 - 85 323 - 86 323 - 87 323 - 88 323 - 89 323 - 8a 323 - 8b 323 - 8c 323 - 90 341 - 91 341 - 92 341 - 93 341 - 94 341 - 95 341 - 96 341 - 97 341 - 9b 344 - 9c 344 - 9d 344 - 9e 344 - 9f 344 - a0 344 - a1 344 - a2 344 - a3 345 + method 'testMismatchedOutputExit3 (III)V' { + 0 313 + 1 313 + 2 313 + 3 313 + 4 314 + 5 314 + 6 314 + e 314 + f 314 + 13 314 + 17 314 + 18 314 + 19 314 + 1a 314 + 1b 314 + 1c 314 + 1d 315 + 1e 315 + 1f 315 + 20 318 + 21 318 + 22 318 + 23 318 + 24 319 + 25 319 + 26 319 + 27 320 + 28 320 + 29 320 + 31 320 + 32 320 + 36 320 + 3a 320 + 3b 320 + 3c 320 + 3d 320 + 3e 320 + 3f 320 + 40 322 + 41 322 + 42 322 + 43 322 + 45 323 + 47 323 + 48 326 + 49 326 + 4a 326 + 4b 327 + 4c 327 + 4d 327 + 4e 327 + 4f 327 + 50 327 + 51 327 + 52 327 + 53 328 + 54 328 + 55 328 + 56 328 + 57 328 + 60 332 + 61 332 + 62 332 + 63 332 + 64 332 + 65 332 + 66 332 + 67 332 + 68 333 + 69 333 + 6a 333 + 6b 333 + 6c 333 + 6d 334 + 6e 334 + 6f 334 + 70 335 + 73 338 + 74 338 + 75 338 + 76 338 + 77 338 + 78 338 + 79 338 + 7a 338 + ba 322 + bb 322 + bc 322 + bd 322 + be 322 + bf 322 + c0 322 + c1 322 + c5 342 + c6 342 + c7 342 + c8 342 + c9 342 + ca 342 + cb 342 + cc 342 + d0 345 + d1 345 + d2 345 + d3 345 + d4 345 + d5 345 + d6 345 + d7 345 + db 348 + dc 348 + dd 348 + de 348 + df 348 + e0 348 + e1 348 + e2 348 + e3 349 } - method 'testMismatchedOutputExitReturnInner (II)V' { - 0 349 - 1 349 - 2 349 - 3 349 - 4 350 - 5 350 - 6 350 - e 350 - f 350 - 13 350 - 17 350 - 18 350 - 19 350 - 1a 350 - 1b 350 - 1c 350 - 1d 351 - 1e 351 - 1f 351 - 20 353 - 21 353 - 22 353 - 23 353 - 24 354 - 25 354 - 26 354 - 27 355 - 28 355 - 29 355 - 31 355 - 32 355 - 36 355 - 3a 355 - 3b 355 - 3c 355 - 3d 355 - 3e 355 - 3f 355 - 40 360 - 41 360 - 42 360 - 43 361 - 44 361 - 45 361 - 46 361 - 47 361 - 48 361 - 49 361 - 4a 361 + method 'testMismatchedOutputExitReturn (II)V' { + 0 353 + 1 353 + 2 353 + 3 353 + 4 354 + 5 354 + 6 354 + e 354 + f 354 + 13 354 + 17 354 + 18 354 + 19 354 + 1a 354 + 1b 354 + 1c 354 + 1d 355 + 1e 355 + 1f 355 + 20 357 + 21 357 + 22 357 + 23 357 + 24 358 + 25 358 + 26 358 + 27 359 + 28 359 + 29 359 + 31 359 + 32 359 + 36 359 + 3a 359 + 3b 359 + 3c 359 + 3d 359 + 3e 359 + 3f 359 + 40 362 + 41 362 + 42 362 + 43 363 + 44 363 + 45 363 + 46 363 + 47 363 + 48 363 + 49 363 + 4a 363 4f 365 50 365 51 365 @@ -1434,63 +1482,165 @@ class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { 5d 367 5e 367 5f 368 - 60 371 - 61 371 62 371 63 371 64 371 65 371 66 371 67 371 - 6a 375 - 6b 375 - 6c 375 - 6d 375 - 6e 375 - 6f 375 - 70 375 - 71 375 - 72 376 - 73 376 - 74 376 - 75 376 - 76 376 - 77 377 - 78 377 - 79 377 - 7d 379 - 7e 379 - 7f 379 - 80 379 - 81 379 - 82 379 - 83 379 - 84 379 - 85 380 - 86 380 - 87 380 - 88 380 - 89 380 - 8a 380 - 8b 380 - 8c 380 - 90 384 - 91 384 - 92 384 - 93 384 - 94 384 - 95 384 - 96 384 - 97 384 - 9b 387 - 9c 387 - 9d 387 - 9e 387 - 9f 387 - a0 387 - a1 387 - a2 387 - a3 388 + 68 371 + 69 371 + 85 357 + 86 357 + 87 357 + 88 357 + 89 357 + 8a 357 + 8b 357 + 8c 357 + 90 375 + 91 375 + 92 375 + 93 375 + 94 375 + 95 375 + 96 375 + 97 375 + 9b 378 + 9c 378 + 9d 378 + 9e 378 + 9f 378 + a0 378 + a1 378 + a2 378 + a3 379 + } + + method 'testMismatchedOutputExitReturnInner (II)V' { + 0 383 + 1 383 + 2 383 + 3 383 + 4 384 + 5 384 + 6 384 + e 384 + f 384 + 13 384 + 17 384 + 18 384 + 19 384 + 1a 384 + 1b 384 + 1c 384 + 1d 385 + 1e 385 + 1f 385 + 20 387 + 21 387 + 22 387 + 23 387 + 24 388 + 25 388 + 26 388 + 27 389 + 28 389 + 29 389 + 31 389 + 32 389 + 36 389 + 3a 389 + 3b 389 + 3c 389 + 3d 389 + 3e 389 + 3f 389 + 40 394 + 41 394 + 42 394 + 43 395 + 44 395 + 45 395 + 46 395 + 47 395 + 48 395 + 49 395 + 4a 395 + 4f 399 + 50 399 + 51 399 + 52 399 + 53 399 + 54 399 + 55 399 + 56 399 + 57 400 + 58 400 + 59 400 + 5a 400 + 5b 400 + 5c 401 + 5d 401 + 5e 401 + 5f 402 + 60 405 + 61 405 + 62 405 + 63 405 + 64 405 + 65 405 + 66 405 + 67 405 + 6a 409 + 6b 409 + 6c 409 + 6d 409 + 6e 409 + 6f 409 + 70 409 + 71 409 + 72 410 + 73 410 + 74 410 + 75 410 + 76 410 + 77 411 + 78 411 + 79 411 + 7d 413 + 7e 413 + 7f 413 + 80 413 + 81 413 + 82 413 + 83 413 + 84 413 + 85 414 + 86 414 + 87 414 + 88 414 + 89 414 + 8a 414 + 8b 414 + 8c 414 + 90 418 + 91 418 + 92 418 + 93 418 + 94 418 + 95 418 + 96 418 + 97 418 + 9b 421 + 9c 421 + 9d 421 + 9e 421 + 9f 421 + a0 421 + a1 421 + a2 421 + a3 422 } } @@ -1545,123 +1695,140 @@ Lines mapping: 138 <-> 165 141 <-> 166 142 <-> 167 -146 <-> 171 -148 <-> 173 -149 <-> 174 -150 <-> 175 -152 <-> 176 -153 <-> 177 -156 <-> 179 -167 <-> 183 -173 <-> 184 -177 <-> 188 -179 <-> 190 -180 <-> 191 -187 <-> 194 -188 <-> 195 -193 <-> 199 -195 <-> 201 -196 <-> 202 -197 <-> 203 -198 <-> 204 -199 <-> 205 -200 <-> 206 -201 <-> 207 -202 <-> 208 -215 <-> 211 -216 <-> 212 -221 <-> 216 -223 <-> 218 -224 <-> 219 -226 <-> 221 -228 <-> 223 -230 <-> 225 -232 <-> 227 -234 <-> 229 -236 <-> 231 -238 <-> 233 -240 <-> 235 -242 <-> 237 -244 <-> 239 -246 <-> 241 -277 <-> 245 -278 <-> 246 -282 <-> 250 -283 <-> 251 -284 <-> 252 -286 <-> 254 -287 <-> 255 -288 <-> 256 -291 <-> 259 -292 <-> 260 -294 <-> 262 -295 <-> 263 -296 <-> 264 -297 <-> 265 -299 <-> 268 -310 <-> 254 -312 <-> 272 -314 <-> 275 -315 <-> 276 -320 <-> 280 -321 <-> 281 -322 <-> 282 -324 <-> 285 -325 <-> 286 -326 <-> 287 -329 <-> 289 -330 <-> 290 -337 <-> 293 -338 <-> 294 -339 <-> 295 -343 <-> 299 -344 <-> 300 -345 <-> 301 -346 <-> 302 -348 <-> 305 -371 <-> 289 -373 <-> 309 -375 <-> 312 -377 <-> 315 -378 <-> 316 -383 <-> 320 -384 <-> 321 -385 <-> 322 -387 <-> 324 -388 <-> 325 -389 <-> 326 -392 <-> 329 -393 <-> 330 -395 <-> 332 -396 <-> 333 -397 <-> 334 -398 <-> 335 -400 <-> 338 -411 <-> 324 -413 <-> 342 -415 <-> 345 -416 <-> 346 -420 <-> 350 -421 <-> 351 -422 <-> 352 -424 <-> 354 -425 <-> 355 -426 <-> 356 -429 <-> 361 -430 <-> 362 -432 <-> 366 -433 <-> 367 -434 <-> 368 -435 <-> 369 -437 <-> 372 -441 <-> 376 -442 <-> 377 -443 <-> 378 +146 <-> 175 +148 <-> 179 +149 <-> 180 +150 <-> 181 +152 <-> 182 +153 <-> 183 +156 <-> 185 +161 <-> 190 +162 <-> 191 +163 <-> 192 +164 <-> 193 +165 <-> 194 +166 <-> 195 +167 <-> 196 +169 <-> 198 +170 <-> 199 +173 <-> 201 +178 <-> 205 +180 <-> 207 +181 <-> 208 +182 <-> 209 +184 <-> 210 +185 <-> 211 +188 <-> 213 +202 <-> 217 +203 <-> 218 +207 <-> 222 +209 <-> 224 +210 <-> 225 +217 <-> 228 +218 <-> 229 +223 <-> 233 +225 <-> 235 +226 <-> 236 +227 <-> 237 +228 <-> 238 +229 <-> 239 +230 <-> 240 +231 <-> 241 +232 <-> 242 +245 <-> 245 +246 <-> 246 +251 <-> 250 +253 <-> 252 +254 <-> 253 +256 <-> 255 +258 <-> 257 +260 <-> 259 +262 <-> 261 +264 <-> 263 +266 <-> 265 +268 <-> 267 +270 <-> 269 +272 <-> 271 +274 <-> 273 +276 <-> 275 +307 <-> 279 +308 <-> 280 +312 <-> 284 +313 <-> 285 +314 <-> 286 +316 <-> 288 +317 <-> 289 +318 <-> 290 +321 <-> 293 +322 <-> 294 +324 <-> 296 +325 <-> 297 +326 <-> 298 +327 <-> 299 +329 <-> 302 +340 <-> 288 +342 <-> 306 +344 <-> 309 +345 <-> 310 +350 <-> 314 +351 <-> 315 +352 <-> 316 +354 <-> 319 +355 <-> 320 +356 <-> 321 +359 <-> 323 +360 <-> 324 +367 <-> 327 +368 <-> 328 +369 <-> 329 +373 <-> 333 +374 <-> 334 +375 <-> 335 +376 <-> 336 +378 <-> 339 +401 <-> 323 +403 <-> 343 +405 <-> 346 +407 <-> 349 +408 <-> 350 +413 <-> 354 +414 <-> 355 +415 <-> 356 +417 <-> 358 +418 <-> 359 +419 <-> 360 +422 <-> 363 +423 <-> 364 +425 <-> 366 +426 <-> 367 +427 <-> 368 +428 <-> 369 +430 <-> 372 +441 <-> 358 +443 <-> 376 +445 <-> 379 446 <-> 380 -448 <-> 381 -450 <-> 385 -452 <-> 388 -453 <-> 389 +450 <-> 384 +451 <-> 385 +452 <-> 386 +454 <-> 388 +455 <-> 389 +456 <-> 390 +459 <-> 395 +460 <-> 396 +462 <-> 400 +463 <-> 401 +464 <-> 402 +465 <-> 403 +467 <-> 406 +471 <-> 410 +472 <-> 411 +473 <-> 412 +476 <-> 414 +478 <-> 415 +480 <-> 419 +482 <-> 422 +483 <-> 423 Not mapped: 9 12 @@ -1685,79 +1852,82 @@ Not mapped: 154 157 159 -161 -162 -163 -164 -165 -166 -169 -170 -178 -181 -182 -184 -185 +179 +183 +186 +189 +191 +193 194 -203 -204 -206 -207 +195 +196 +197 +199 208 -209 -210 211 212 -213 -222 -248 -249 -251 +214 +215 +224 +233 +234 +236 +237 +238 +239 +240 +241 +242 +243 252 -254 -256 -258 -260 -262 -264 -266 -268 -270 -272 -274 -293 +278 +279 +281 +282 +284 +286 +288 +290 +292 +294 +296 +298 300 -301 -303 +302 304 -305 -306 -308 -340 -342 -349 -350 -352 -353 -354 -355 -357 -359 -362 -363 -364 -365 -367 -368 +323 +330 +331 +333 +334 +335 +336 +338 +370 +372 +379 +380 +382 +383 +384 +385 +387 +389 +392 +393 394 -401 -402 -404 -405 -406 -407 -409 +395 +397 +398 +424 431 -438 +432 +434 +435 +436 +437 439 -444 +461 +468 +469 +474 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec deleted file mode 100644 index dcdab4677f..0000000000 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_1.dec +++ /dev/null @@ -1,1763 +0,0 @@ -package pkg; - -import org.vineflower.marker.CatchAllException; - -public class TestTryFinallyMarkerExceptionsInvalid { - // $VF: Could not inline inconsistent finally blocks - public Object testReturn() { - try { - System.out.println("Hello");// 8 - } catch (Throwable var3) { - System.out.println("Finally");// 10 - return e;// 11 - } - - System.out.println("Finally");// 14 - System.out.println("Bye");// 17 - return null;// 18 - } - - // $VF: Could not inline inconsistent finally blocks - public void testLogged(int i) { - try { - System.out.println("Hello");// 24 - } catch (Throwable var4) { - System.out.println(e.getMessage());// 27 - System.out.println("Finally");// 29 - throw e;// 30 - } - - System.out.println("Finally");// 33 - System.out.println("Bye");// 36 - }// 37 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testWeirdCatch(int i) { - boolean var5 = false /* VF: Semaphore variable */; - - label26: { - try { - var5 = true; - System.out.println("Hello");// 44 - var5 = false; - break label26; - } catch (NullPointerException npe) {// 45 - var5 = false; - } finally { - if (var5) { - System.out.println("Finally");// 48 - } - } - - System.out.println("NPE");// 46 - } - - System.out.println("Finally");// 52 - System.out.println("Bye");// 55 - }// 56 - - public void testWeirdCatch2(int param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: getstatic java/lang/System.out Ljava/io/PrintStream; - // 03: ldc "Hello" - // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 08: goto 22 - // 0b: astore 2 - // 0c: getstatic java/lang/System.out Ljava/io/PrintStream; - // 0f: ldc "Finally" - // 11: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 14: goto 22 - // 17: astore 2 - // 18: getstatic java/lang/System.out Ljava/io/PrintStream; - // 1b: ldc "Finally" - // 1d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 20: aload 2 - // 21: athrow - // 22: getstatic java/lang/System.out Ljava/io/PrintStream; - // 25: ldc "Finally" - // 27: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 2a: getstatic java/lang/System.out Ljava/io/PrintStream; - // 2d: ldc "Bye" - // 2f: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 32: return - // try (0 -> 3): 4 java/lang/NullPointerException - // try (0 -> 3): 9 null - } - - public void testWeirdCatch3(int i) { - label26: { - NullPointerException npe; - try { - System.out.println("Hello");// 81 - break label26; - } catch (NullPointerException var5) {// 82 - npe = var5; - } finally { - System.out.println("Finally");// 86 - } - - System.out.println("NPE: " + npe.getMessage());// 84 - } - - System.out.println("Bye");// 93 - }// 94 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testBlockReuse(int i) { - boolean var4 = false /* VF: Semaphore variable */; - - try { - var4 = true; - System.out.println("Hello");// 101 - var4 = false; - } finally { - if (var4) { - System.out.println("Finally");// 103 - if (i > 0) {// 104 - System.out.println("Cool 1");// 105 - } else { - System.out.println("Cool 2");// 107 - } - - if (i < 0) {// 109 - } - } - } - - System.out.println("Finally");// 113 - if (i > 0) {// 114 - } - - System.out.println("Cool 1");// 115 - if (i < 0) {// 116 - } - - System.out.println("Bye");// 119 - }// 120 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testInjectWrongException(boolean b) { - boolean var4 = false /* VF: Semaphore variable */; - - try { - var4 = true; - System.out.println("Hello");// 124 - var4 = false; - } finally { - if (var4) { - System.out.println("Finally start");// 126 - CatchAllException e; - if (b) {// 127 - e = new CatchAllException("yo");// 128 - } - - System.out.println("Finally end");// 130 - throw e;// 131 - } - } - - System.out.println("Finally start");// 134 - if (b) {// 135 - new CatchAllException("yo");// 136 - } - - System.out.println("Finally end");// 138 - System.out.println("Bye");// 141 - }// 142 - - public void testMultiImplicitExits(int i) { - try { - System.out.println("Hello");// 146 - } finally { - System.out.println("Finally");// 148 - if (i > 0) {// 149 - System.out.println("Positive!");// 150 - } else if (i == 0) {// 152 - System.out.println("ZERO");// 153 - } else { - System.out.println("Negative!");// 156 - } - } - - System.out.println("Bye 1");// 164 - }// 173 - - public void testConfusion1(String a, String b) { - try { - System.out.println("Hello");// 177 - } finally { - System.out.println("Finally");// 179 - System.out.println(a);// 180 - } - - System.out.println("Bye");// 187 - }// 188 - - public void testConfusion2() { - try { - System.out.println("Hello");// 193 - } finally { - System.out.println("Finally");// 195 - String x = "X";// 196 - String y = "Y";// 197 - String z = "Z";// 198 - x = x + z;// 199 - y = y + x;// 200 - z = z + y;// 201 - System.out.println(z);// 202 - } - - System.out.println("Bye");// 215 - }// 216 - - public void testMismatchedSwitch(int i) { - try { - System.out.println("Hello");// 221 - } finally { - System.out.println("Finally");// 223 - switch (i) {// 224 - case 10: - System.out.println("10");// 226 - case 9: - System.out.println("9");// 228 - case 8: - System.out.println("8");// 230 - case 7: - System.out.println("7");// 232 - case 6: - System.out.println("6");// 234 - case 5: - System.out.println("5");// 236 - case 4: - System.out.println("4");// 238 - case 3: - System.out.println("3");// 240 - case 2: - System.out.println("2");// 242 - case 1: - System.out.println("1");// 244 - case 0: - System.out.println("Lift off!");// 246 - } - } - - System.out.println("Bye");// 277 - }// 278 - - public void testMismatchedOutputExit(int a, int b) { - label53: - while (a > 0) {// 282 - System.out.println("A: " + a);// 283 - a--;// 284 - - for (; b > 0; System.out.println("Beep")) {// 286 310 - a++;// 287 - System.out.println("B: " + b);// 288 - - try { - b--;// 291 - System.out.println("Hello");// 292 - } finally { - System.out.println("Finally");// 294 - if (a > b) {// 295 - a--;// 296 - continue label53;// 297 - } - - System.out.println("Boop");// 299 - } - } - - System.out.println("BLORB");// 312 - } - - System.out.println("Bye");// 314 - }// 315 - - public void testMismatchedOutputExit3(int a, int b, int c) { - label84: - while (a > 0) {// 320 - System.out.println("A: " + a);// 321 - a--;// 322 - - label82: - while (b > 0) {// 324 - a++;// 325 - System.out.println("B: " + b);// 326 - - for (; c > 0; System.out.println("Lost")) {// 329 371 - c -= b;// 330 - - try { - b--;// 337 - System.out.println("Hello");// 338 - if (c < a) {// 339 - continue label82; - } - } finally { - System.out.println("Finally");// 343 - if (a > b) {// 344 - a--;// 345 - continue label84;// 346 - } - - System.out.println("Boop");// 348 - } - } - - System.out.println("Beep");// 373 - } - - System.out.println("BLORB");// 375 - } - - System.out.println("Bye");// 377 - }// 378 - - public void testMismatchedOutputExitReturn(int a, int b) { - label54: - while (a > 0) {// 383 - System.out.println("A: " + a);// 384 - a--;// 385 - - for (; b > 0; System.out.println("Beep")) {// 387 411 - a++;// 388 - System.out.println("B: " + b);// 389 - - try { - b--;// 392 - System.out.println("Hello");// 393 - } finally { - System.out.println("Finally");// 395 - if (a > b) {// 396 - a--;// 397 - continue label54;// 398 - } - - System.out.println("Boop");// 400 - } - } - - System.out.println("BLORB");// 413 - } - - System.out.println("Bye");// 415 - }// 416 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testMismatchedOutputExitReturnInner(int a, int b) { - while (a > 0) {// 420 - System.out.println("A: " + a);// 421 - a--;// 422 - - while (b > 0) {// 424 - a++;// 425 - System.out.println("B: " + b);// 426 - boolean var5 = false /* VF: Semaphore variable */; - - try { - var5 = true; - b--;// 429 - System.out.println("Hello");// 430 - var5 = false; - } finally { - if (var5) { - System.out.println("Finally");// 432 - if (a > b) {// 433 - a--;// 434 - return;// 435 - } - - System.out.println("Boop");// 437 - } - } - - System.out.println("Finally");// 441 - if (a > b) {// 442 - a--;// 443 - } else { - System.out.println("Boop");// 446 - System.out.println("Beep");// 448 - } - } - - System.out.println("BLORB");// 450 - } - - System.out.println("Bye");// 452 - }// 453 -} - -class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { - method 'testReturn ()Ljava/lang/Object;' { - 0 8 - 1 8 - 2 8 - 3 8 - 4 8 - 5 8 - 6 8 - 7 8 - c 10 - d 10 - e 10 - f 10 - 10 10 - 11 10 - 12 10 - 13 10 - 14 11 - 15 11 - 16 14 - 17 14 - 18 14 - 19 14 - 1a 14 - 1b 14 - 1c 14 - 1d 14 - 1e 15 - 1f 15 - 20 15 - 21 15 - 22 15 - 23 15 - 24 15 - 25 15 - 26 16 - 27 16 - } - - method 'testLogged (I)V' { - 0 22 - 1 22 - 2 22 - 3 22 - 4 22 - 5 22 - 6 22 - 7 22 - c 24 - d 24 - e 24 - f 24 - 10 24 - 11 24 - 12 24 - 13 24 - 14 24 - 15 24 - 16 25 - 17 25 - 18 25 - 19 25 - 1a 25 - 1b 25 - 1c 25 - 1d 25 - 1e 26 - 1f 26 - 20 29 - 21 29 - 22 29 - 23 29 - 24 29 - 25 29 - 26 29 - 27 29 - 28 30 - 29 30 - 2a 30 - 2b 30 - 2c 30 - 2d 30 - 2e 30 - 2f 30 - 30 31 - } - - method 'testWeirdCatch (I)V' { - 0 40 - 1 40 - 2 40 - 3 40 - 4 40 - 5 40 - 6 40 - 7 40 - b 43 - c 51 - d 51 - e 51 - f 51 - 10 51 - 11 51 - 12 51 - 13 51 - 18 47 - 19 47 - 1a 47 - 1b 47 - 1c 47 - 1d 47 - 1e 47 - 1f 47 - 22 54 - 23 54 - 24 54 - 25 54 - 26 54 - 27 54 - 28 54 - 29 54 - 2a 55 - 2b 55 - 2c 55 - 2d 55 - 2e 55 - 2f 55 - 30 55 - 31 55 - 32 56 - } - - method 'testWeirdCatch3 (I)V' { - 0 91 - 1 91 - 2 91 - 3 91 - 4 91 - 5 91 - 6 91 - 7 91 - b 93 - 14 99 - 15 99 - 16 99 - 1e 99 - 1f 99 - 23 99 - 24 99 - 25 99 - 26 99 - 2a 99 - 2b 99 - 2c 99 - 2d 99 - 2e 99 - 2f 99 - 34 96 - 35 96 - 36 96 - 37 96 - 38 96 - 39 96 - 3a 96 - 3b 96 - 46 102 - 47 102 - 48 102 - 49 102 - 4a 102 - 4b 102 - 4c 102 - 4d 102 - 4e 103 - } - - method 'testBlockReuse (I)V' { - 0 111 - 1 111 - 2 111 - 3 111 - 4 111 - 5 111 - 6 111 - 7 111 - c 115 - d 115 - e 115 - f 115 - 10 115 - 11 115 - 12 115 - 13 115 - 14 116 - 15 116 - 16 116 - 17 116 - 18 117 - 19 117 - 1a 117 - 1b 117 - 1c 117 - 1d 117 - 1e 117 - 1f 117 - 23 119 - 24 119 - 25 119 - 26 119 - 27 119 - 28 119 - 29 119 - 2a 119 - 2b 122 - 2c 122 - 2d 122 - 2e 122 - 31 127 - 32 127 - 33 127 - 34 127 - 35 127 - 36 127 - 37 127 - 38 127 - 39 128 - 3a 128 - 3b 128 - 3c 128 - 3d 131 - 3e 131 - 3f 131 - 40 131 - 41 131 - 42 131 - 43 131 - 44 131 - 45 132 - 46 132 - 47 132 - 48 132 - 49 135 - 4a 135 - 4b 135 - 4c 135 - 4d 135 - 4e 135 - 4f 135 - 50 135 - 51 136 - } - - method 'testInjectWrongException (Z)V' { - 0 144 - 1 144 - 2 144 - 3 144 - 4 144 - 5 144 - 6 144 - 7 144 - c 148 - d 148 - e 148 - f 148 - 10 148 - 11 148 - 12 148 - 13 148 - 14 150 - 15 150 - 16 150 - 17 150 - 1c 151 - 1d 151 - 21 151 - 22 154 - 23 154 - 24 154 - 25 154 - 26 154 - 27 154 - 28 154 - 29 154 - 2a 155 - 2b 155 - 2c 159 - 2d 159 - 2e 159 - 2f 159 - 30 159 - 31 159 - 32 159 - 33 159 - 34 160 - 35 160 - 36 160 - 37 160 - 3c 161 - 3d 161 - 42 164 - 43 164 - 44 164 - 45 164 - 46 164 - 47 164 - 48 164 - 49 164 - 4a 165 - 4b 165 - 4c 165 - 4d 165 - 4e 165 - 4f 165 - 50 165 - 51 165 - 52 166 - } - - method 'testMultiImplicitExits (I)V' { - 0 170 - 1 170 - 2 170 - 3 170 - 4 170 - 5 170 - 6 170 - 7 170 - c 172 - d 172 - e 172 - f 172 - 10 172 - 11 172 - 12 172 - 13 172 - 14 173 - 15 173 - 16 173 - 17 173 - 18 174 - 19 174 - 1a 174 - 1b 174 - 1c 174 - 1d 174 - 1e 174 - 1f 174 - 22 175 - 23 175 - 24 175 - 25 175 - 26 176 - 27 176 - 28 176 - 29 176 - 2a 176 - 2b 176 - 2c 176 - 2d 176 - 30 178 - 31 178 - 32 178 - 33 178 - 34 178 - 35 178 - 36 178 - 37 178 - 4e 182 - 4f 182 - 50 182 - 51 182 - 52 182 - 53 182 - 54 182 - 55 182 - 80 183 - } - - method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { - 0 187 - 1 187 - 2 187 - 3 187 - 4 187 - 5 187 - 6 187 - 7 187 - c 189 - d 189 - e 189 - f 189 - 10 189 - 11 189 - 12 189 - 13 189 - 14 190 - 15 190 - 16 190 - 17 190 - 18 190 - 19 190 - 1a 190 - 2c 193 - 2d 193 - 2e 193 - 2f 193 - 30 193 - 31 193 - 32 193 - 33 193 - 34 194 - } - - method 'testConfusion2 ()V' { - 0 198 - 1 198 - 2 198 - 3 198 - 4 198 - 5 198 - 6 198 - 7 198 - d 200 - e 200 - f 200 - 10 200 - 11 200 - 12 200 - 13 200 - 14 200 - 15 201 - 16 201 - 17 201 - 18 202 - 19 202 - 1a 202 - 1b 203 - 1c 203 - 1d 203 - 25 204 - 29 204 - 2d 204 - 2e 204 - 2f 204 - 30 204 - 38 205 - 3c 205 - 40 205 - 41 205 - 42 205 - 43 205 - 4b 206 - 4f 206 - 53 206 - 54 206 - 55 206 - 56 206 - 57 207 - 58 207 - 59 207 - 5a 207 - 5b 207 - 5c 207 - 5d 207 - b2 210 - b3 210 - b4 210 - b5 210 - b6 210 - b7 210 - b8 210 - b9 210 - ba 211 - } - - method 'testMismatchedSwitch (I)V' { - 0 215 - 1 215 - 2 215 - 3 215 - 4 215 - 5 215 - 6 215 - 7 215 - c 217 - d 217 - e 217 - f 217 - 10 217 - 11 217 - 12 217 - 13 217 - 14 218 - 15 218 - 16 218 - 17 218 - 18 218 - 19 218 - 1a 218 - 1b 218 - 1c 218 - 1d 218 - 1e 218 - 1f 218 - 20 218 - 21 218 - 22 218 - 23 218 - 24 218 - 25 218 - 26 218 - 27 218 - 28 218 - 29 218 - 2a 218 - 2b 218 - 2c 218 - 2d 218 - 2e 218 - 2f 218 - 30 218 - 31 218 - 32 218 - 33 218 - 34 218 - 35 218 - 36 218 - 37 218 - 38 218 - 39 218 - 3a 218 - 3b 218 - 3c 218 - 3d 218 - 3e 218 - 3f 218 - 40 218 - 41 218 - 42 218 - 43 218 - 44 218 - 45 218 - 46 218 - 47 218 - 48 218 - 49 218 - 4a 218 - 4b 218 - 4c 218 - 4d 218 - 4e 218 - 4f 218 - 50 220 - 51 220 - 52 220 - 53 220 - 54 220 - 55 220 - 56 220 - 57 220 - 58 222 - 59 222 - 5a 222 - 5b 222 - 5c 222 - 5d 222 - 5e 222 - 5f 222 - 60 224 - 61 224 - 62 224 - 63 224 - 64 224 - 65 224 - 66 224 - 67 224 - 68 226 - 69 226 - 6a 226 - 6b 226 - 6c 226 - 6d 226 - 6e 226 - 6f 226 - 70 228 - 71 228 - 72 228 - 73 228 - 74 228 - 75 228 - 76 228 - 77 228 - 78 230 - 79 230 - 7a 230 - 7b 230 - 7c 230 - 7d 230 - 7e 230 - 7f 230 - 80 232 - 81 232 - 82 232 - 83 232 - 84 232 - 85 232 - 86 232 - 87 232 - 88 234 - 89 234 - 8a 234 - 8b 234 - 8c 234 - 8d 234 - 8e 234 - 8f 234 - 90 236 - 91 236 - 92 236 - 93 236 - 94 236 - 95 236 - 96 236 - 97 236 - 98 238 - 99 238 - 9a 238 - 9b 238 - 9c 238 - 9d 238 - 9e 238 - 9f 238 - a0 240 - a1 240 - a2 240 - a3 240 - a4 240 - a5 240 - a6 240 - a7 240 - 144 244 - 145 244 - 146 244 - 147 244 - 148 244 - 149 244 - 14a 244 - 14b 244 - 14c 245 - } - - method 'testMismatchedOutputExit (II)V' { - 0 249 - 1 249 - 2 249 - 3 249 - 4 250 - 5 250 - 6 250 - e 250 - f 250 - 13 250 - 17 250 - 18 250 - 19 250 - 1a 250 - 1b 250 - 1c 250 - 1d 251 - 1e 251 - 1f 251 - 20 253 - 21 253 - 22 253 - 23 253 - 24 254 - 25 254 - 26 254 - 27 255 - 28 255 - 29 255 - 31 255 - 32 255 - 36 255 - 3a 255 - 3b 255 - 3c 255 - 3d 255 - 3e 255 - 3f 255 - 40 258 - 41 258 - 42 258 - 43 259 - 44 259 - 45 259 - 46 259 - 47 259 - 48 259 - 49 259 - 4a 259 - 4f 261 - 50 261 - 51 261 - 52 261 - 53 261 - 54 261 - 55 261 - 56 261 - 57 262 - 58 262 - 59 262 - 5a 262 - 5b 262 - 5c 263 - 5d 263 - 5e 263 - 5f 264 - 62 267 - 63 267 - 64 267 - 65 267 - 66 267 - 67 267 - 68 267 - 69 267 - 87 253 - 88 253 - 89 253 - 8a 253 - 8b 253 - 8c 253 - 8d 253 - 8e 253 - 92 271 - 93 271 - 94 271 - 95 271 - 96 271 - 97 271 - 98 271 - 99 271 - 9d 274 - 9e 274 - 9f 274 - a0 274 - a1 274 - a2 274 - a3 274 - a4 274 - a5 275 - } - - method 'testMismatchedOutputExit3 (III)V' { - 0 279 - 1 279 - 2 279 - 3 279 - 4 280 - 5 280 - 6 280 - e 280 - f 280 - 13 280 - 17 280 - 18 280 - 19 280 - 1a 280 - 1b 280 - 1c 280 - 1d 281 - 1e 281 - 1f 281 - 20 284 - 21 284 - 22 284 - 23 284 - 24 285 - 25 285 - 26 285 - 27 286 - 28 286 - 29 286 - 31 286 - 32 286 - 36 286 - 3a 286 - 3b 286 - 3c 286 - 3d 286 - 3e 286 - 3f 286 - 40 288 - 41 288 - 42 288 - 43 288 - 45 289 - 47 289 - 48 292 - 49 292 - 4a 292 - 4b 293 - 4c 293 - 4d 293 - 4e 293 - 4f 293 - 50 293 - 51 293 - 52 293 - 53 294 - 54 294 - 55 294 - 56 294 - 57 294 - 60 298 - 61 298 - 62 298 - 63 298 - 64 298 - 65 298 - 66 298 - 67 298 - 68 299 - 69 299 - 6a 299 - 6b 299 - 6c 299 - 6d 300 - 6e 300 - 6f 300 - 70 301 - 73 304 - 74 304 - 75 304 - 76 304 - 77 304 - 78 304 - 79 304 - 7a 304 - ba 288 - bb 288 - bc 288 - bd 288 - be 288 - bf 288 - c0 288 - c1 288 - c5 308 - c6 308 - c7 308 - c8 308 - c9 308 - ca 308 - cb 308 - cc 308 - d0 311 - d1 311 - d2 311 - d3 311 - d4 311 - d5 311 - d6 311 - d7 311 - db 314 - dc 314 - dd 314 - de 314 - df 314 - e0 314 - e1 314 - e2 314 - e3 315 - } - - method 'testMismatchedOutputExitReturn (II)V' { - 0 319 - 1 319 - 2 319 - 3 319 - 4 320 - 5 320 - 6 320 - e 320 - f 320 - 13 320 - 17 320 - 18 320 - 19 320 - 1a 320 - 1b 320 - 1c 320 - 1d 321 - 1e 321 - 1f 321 - 20 323 - 21 323 - 22 323 - 23 323 - 24 324 - 25 324 - 26 324 - 27 325 - 28 325 - 29 325 - 31 325 - 32 325 - 36 325 - 3a 325 - 3b 325 - 3c 325 - 3d 325 - 3e 325 - 3f 325 - 40 328 - 41 328 - 42 328 - 43 329 - 44 329 - 45 329 - 46 329 - 47 329 - 48 329 - 49 329 - 4a 329 - 4f 331 - 50 331 - 51 331 - 52 331 - 53 331 - 54 331 - 55 331 - 56 331 - 57 332 - 58 332 - 59 332 - 5a 332 - 5b 332 - 5c 333 - 5d 333 - 5e 333 - 5f 334 - 62 337 - 63 337 - 64 337 - 65 337 - 66 337 - 67 337 - 68 337 - 69 337 - 85 323 - 86 323 - 87 323 - 88 323 - 89 323 - 8a 323 - 8b 323 - 8c 323 - 90 341 - 91 341 - 92 341 - 93 341 - 94 341 - 95 341 - 96 341 - 97 341 - 9b 344 - 9c 344 - 9d 344 - 9e 344 - 9f 344 - a0 344 - a1 344 - a2 344 - a3 345 - } - - method 'testMismatchedOutputExitReturnInner (II)V' { - 0 349 - 1 349 - 2 349 - 3 349 - 4 350 - 5 350 - 6 350 - e 350 - f 350 - 13 350 - 17 350 - 18 350 - 19 350 - 1a 350 - 1b 350 - 1c 350 - 1d 351 - 1e 351 - 1f 351 - 20 353 - 21 353 - 22 353 - 23 353 - 24 354 - 25 354 - 26 354 - 27 355 - 28 355 - 29 355 - 31 355 - 32 355 - 36 355 - 3a 355 - 3b 355 - 3c 355 - 3d 355 - 3e 355 - 3f 355 - 40 360 - 41 360 - 42 360 - 43 361 - 44 361 - 45 361 - 46 361 - 47 361 - 48 361 - 49 361 - 4a 361 - 4f 365 - 50 365 - 51 365 - 52 365 - 53 365 - 54 365 - 55 365 - 56 365 - 57 366 - 58 366 - 59 366 - 5a 366 - 5b 366 - 5c 367 - 5d 367 - 5e 367 - 5f 368 - 60 371 - 61 371 - 62 371 - 63 371 - 64 371 - 65 371 - 66 371 - 67 371 - 6a 375 - 6b 375 - 6c 375 - 6d 375 - 6e 375 - 6f 375 - 70 375 - 71 375 - 72 376 - 73 376 - 74 376 - 75 376 - 76 376 - 77 377 - 78 377 - 79 377 - 7d 379 - 7e 379 - 7f 379 - 80 379 - 81 379 - 82 379 - 83 379 - 84 379 - 85 380 - 86 380 - 87 380 - 88 380 - 89 380 - 8a 380 - 8b 380 - 8c 380 - 90 384 - 91 384 - 92 384 - 93 384 - 94 384 - 95 384 - 96 384 - 97 384 - 9b 387 - 9c 387 - 9d 387 - 9e 387 - 9f 387 - a0 387 - a1 387 - a2 387 - a3 388 - } -} - -Lines mapping: -8 <-> 9 -10 <-> 11 -11 <-> 12 -14 <-> 15 -17 <-> 16 -18 <-> 17 -24 <-> 23 -27 <-> 25 -29 <-> 26 -30 <-> 27 -33 <-> 30 -36 <-> 31 -37 <-> 32 -44 <-> 41 -45 <-> 44 -46 <-> 52 -48 <-> 48 -52 <-> 55 -55 <-> 56 -56 <-> 57 -81 <-> 92 -82 <-> 94 -84 <-> 100 -86 <-> 97 -93 <-> 103 -94 <-> 104 -101 <-> 112 -103 <-> 116 -104 <-> 117 -105 <-> 118 -107 <-> 120 -109 <-> 123 -113 <-> 128 -114 <-> 129 -115 <-> 132 -116 <-> 133 -119 <-> 136 -120 <-> 137 -124 <-> 145 -126 <-> 149 -127 <-> 151 -128 <-> 152 -130 <-> 155 -131 <-> 156 -134 <-> 160 -135 <-> 161 -136 <-> 162 -138 <-> 165 -141 <-> 166 -142 <-> 167 -146 <-> 171 -148 <-> 173 -149 <-> 174 -150 <-> 175 -152 <-> 176 -153 <-> 177 -156 <-> 179 -164 <-> 183 -173 <-> 184 -177 <-> 188 -179 <-> 190 -180 <-> 191 -187 <-> 194 -188 <-> 195 -193 <-> 199 -195 <-> 201 -196 <-> 202 -197 <-> 203 -198 <-> 204 -199 <-> 205 -200 <-> 206 -201 <-> 207 -202 <-> 208 -215 <-> 211 -216 <-> 212 -221 <-> 216 -223 <-> 218 -224 <-> 219 -226 <-> 221 -228 <-> 223 -230 <-> 225 -232 <-> 227 -234 <-> 229 -236 <-> 231 -238 <-> 233 -240 <-> 235 -242 <-> 237 -244 <-> 239 -246 <-> 241 -277 <-> 245 -278 <-> 246 -282 <-> 250 -283 <-> 251 -284 <-> 252 -286 <-> 254 -287 <-> 255 -288 <-> 256 -291 <-> 259 -292 <-> 260 -294 <-> 262 -295 <-> 263 -296 <-> 264 -297 <-> 265 -299 <-> 268 -310 <-> 254 -312 <-> 272 -314 <-> 275 -315 <-> 276 -320 <-> 280 -321 <-> 281 -322 <-> 282 -324 <-> 285 -325 <-> 286 -326 <-> 287 -329 <-> 289 -330 <-> 290 -337 <-> 293 -338 <-> 294 -339 <-> 295 -343 <-> 299 -344 <-> 300 -345 <-> 301 -346 <-> 302 -348 <-> 305 -371 <-> 289 -373 <-> 309 -375 <-> 312 -377 <-> 315 -378 <-> 316 -383 <-> 320 -384 <-> 321 -385 <-> 322 -387 <-> 324 -388 <-> 325 -389 <-> 326 -392 <-> 329 -393 <-> 330 -395 <-> 332 -396 <-> 333 -397 <-> 334 -398 <-> 335 -400 <-> 338 -411 <-> 324 -413 <-> 342 -415 <-> 345 -416 <-> 346 -420 <-> 350 -421 <-> 351 -422 <-> 352 -424 <-> 354 -425 <-> 355 -426 <-> 356 -429 <-> 361 -430 <-> 362 -432 <-> 366 -433 <-> 367 -434 <-> 368 -435 <-> 369 -437 <-> 372 -441 <-> 376 -442 <-> 377 -443 <-> 378 -446 <-> 380 -448 <-> 381 -450 <-> 385 -452 <-> 388 -453 <-> 389 -Not mapped: -9 -12 -25 -31 -47 -49 -50 -83 -85 -87 -88 -90 -102 -110 -111 -125 -132 -147 -151 -154 -157 -159 -161 -162 -163 -165 -166 -167 -169 -170 -178 -181 -182 -184 -185 -194 -203 -204 -206 -207 -208 -209 -210 -211 -212 -213 -222 -248 -249 -251 -252 -254 -256 -258 -260 -262 -264 -266 -268 -270 -272 -274 -293 -300 -301 -303 -304 -305 -306 -308 -340 -342 -349 -350 -352 -353 -354 -355 -357 -359 -362 -363 -364 -365 -367 -368 -394 -401 -402 -404 -405 -406 -407 -409 -431 -438 -439 -444 diff --git a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec b/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec deleted file mode 100644 index e3af2683ea..0000000000 --- a/testData/results/pkg/TestTryFinallyMarkerExceptionsInvalid_2.dec +++ /dev/null @@ -1,1763 +0,0 @@ -package pkg; - -import org.vineflower.marker.CatchAllException; - -public class TestTryFinallyMarkerExceptionsInvalid { - // $VF: Could not inline inconsistent finally blocks - public Object testReturn() { - try { - System.out.println("Hello");// 8 - } catch (Throwable var3) { - System.out.println("Finally");// 10 - return e;// 11 - } - - System.out.println("Finally");// 14 - System.out.println("Bye");// 17 - return null;// 18 - } - - // $VF: Could not inline inconsistent finally blocks - public void testLogged(int i) { - try { - System.out.println("Hello");// 24 - } catch (Throwable var4) { - System.out.println(e.getMessage());// 27 - System.out.println("Finally");// 29 - throw e;// 30 - } - - System.out.println("Finally");// 33 - System.out.println("Bye");// 36 - }// 37 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testWeirdCatch(int i) { - boolean var5 = false /* VF: Semaphore variable */; - - label26: { - try { - var5 = true; - System.out.println("Hello");// 44 - var5 = false; - break label26; - } catch (NullPointerException npe) {// 45 - var5 = false; - } finally { - if (var5) { - System.out.println("Finally");// 48 - } - } - - System.out.println("NPE");// 46 - } - - System.out.println("Finally");// 52 - System.out.println("Bye");// 55 - }// 56 - - public void testWeirdCatch2(int param1) { - // $VF: Couldn't be decompiled - // Bytecode: - // 00: getstatic java/lang/System.out Ljava/io/PrintStream; - // 03: ldc "Hello" - // 05: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 08: goto 22 - // 0b: astore 2 - // 0c: getstatic java/lang/System.out Ljava/io/PrintStream; - // 0f: ldc "Finally" - // 11: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 14: goto 22 - // 17: astore 2 - // 18: getstatic java/lang/System.out Ljava/io/PrintStream; - // 1b: ldc "Finally" - // 1d: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 20: aload 2 - // 21: athrow - // 22: getstatic java/lang/System.out Ljava/io/PrintStream; - // 25: ldc "Finally" - // 27: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 2a: getstatic java/lang/System.out Ljava/io/PrintStream; - // 2d: ldc "Bye" - // 2f: invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V - // 32: return - // try (0 -> 3): 4 java/lang/NullPointerException - // try (0 -> 3): 9 null - } - - public void testWeirdCatch3(int i) { - label26: { - NullPointerException npe; - try { - System.out.println("Hello");// 81 - break label26; - } catch (NullPointerException var5) {// 82 - npe = var5; - } finally { - System.out.println("Finally");// 86 - } - - System.out.println("NPE: " + npe.getMessage());// 84 - } - - System.out.println("Bye");// 93 - }// 94 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testBlockReuse(int i) { - boolean var4 = false /* VF: Semaphore variable */; - - try { - var4 = true; - System.out.println("Hello");// 101 - var4 = false; - } finally { - if (var4) { - System.out.println("Finally");// 103 - if (i > 0) {// 104 - System.out.println("Cool 1");// 105 - } else { - System.out.println("Cool 2");// 107 - } - - if (i < 0) {// 109 - } - } - } - - System.out.println("Finally");// 113 - if (i > 0) {// 114 - } - - System.out.println("Cool 1");// 115 - if (i < 0) {// 116 - } - - System.out.println("Bye");// 119 - }// 120 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testInjectWrongException(boolean b) { - boolean var4 = false /* VF: Semaphore variable */; - - try { - var4 = true; - System.out.println("Hello");// 124 - var4 = false; - } finally { - if (var4) { - System.out.println("Finally start");// 126 - CatchAllException e; - if (b) {// 127 - e = new CatchAllException("yo");// 128 - } - - System.out.println("Finally end");// 130 - throw e;// 131 - } - } - - System.out.println("Finally start");// 134 - if (b) {// 135 - new CatchAllException("yo");// 136 - } - - System.out.println("Finally end");// 138 - System.out.println("Bye");// 141 - }// 142 - - public void testMultiImplicitExits(int i) { - try { - System.out.println("Hello");// 146 - } finally { - System.out.println("Finally");// 148 - if (i > 0) {// 149 - System.out.println("Positive!");// 150 - } else if (i == 0) {// 152 - System.out.println("ZERO");// 153 - } else { - System.out.println("Negative!");// 156 - } - } - - System.out.println("Bye 3");// 170 - }// 173 - - public void testConfusion1(String a, String b) { - try { - System.out.println("Hello");// 177 - } finally { - System.out.println("Finally");// 179 - System.out.println(a);// 180 - } - - System.out.println("Bye");// 187 - }// 188 - - public void testConfusion2() { - try { - System.out.println("Hello");// 193 - } finally { - System.out.println("Finally");// 195 - String x = "X";// 196 - String y = "Y";// 197 - String z = "Z";// 198 - x = x + z;// 199 - y = y + x;// 200 - z = z + y;// 201 - System.out.println(z);// 202 - } - - System.out.println("Bye");// 215 - }// 216 - - public void testMismatchedSwitch(int i) { - try { - System.out.println("Hello");// 221 - } finally { - System.out.println("Finally");// 223 - switch (i) {// 224 - case 10: - System.out.println("10");// 226 - case 9: - System.out.println("9");// 228 - case 8: - System.out.println("8");// 230 - case 7: - System.out.println("7");// 232 - case 6: - System.out.println("6");// 234 - case 5: - System.out.println("5");// 236 - case 4: - System.out.println("4");// 238 - case 3: - System.out.println("3");// 240 - case 2: - System.out.println("2");// 242 - case 1: - System.out.println("1");// 244 - case 0: - System.out.println("Lift off!");// 246 - } - } - - System.out.println("Bye");// 277 - }// 278 - - public void testMismatchedOutputExit(int a, int b) { - label53: - while (a > 0) {// 282 - System.out.println("A: " + a);// 283 - a--;// 284 - - for (; b > 0; System.out.println("Beep")) {// 286 310 - a++;// 287 - System.out.println("B: " + b);// 288 - - try { - b--;// 291 - System.out.println("Hello");// 292 - } finally { - System.out.println("Finally");// 294 - if (a > b) {// 295 - a--;// 296 - continue label53;// 297 - } - - System.out.println("Boop");// 299 - } - } - - System.out.println("BLORB");// 312 - } - - System.out.println("Bye");// 314 - }// 315 - - public void testMismatchedOutputExit3(int a, int b, int c) { - label84: - while (a > 0) {// 320 - System.out.println("A: " + a);// 321 - a--;// 322 - - label82: - while (b > 0) {// 324 - a++;// 325 - System.out.println("B: " + b);// 326 - - for (; c > 0; System.out.println("Lost")) {// 329 371 - c -= b;// 330 - - try { - b--;// 337 - System.out.println("Hello");// 338 - if (c < a) {// 339 - continue label82; - } - } finally { - System.out.println("Finally");// 343 - if (a > b) {// 344 - a--;// 345 - continue label84;// 346 - } - - System.out.println("Boop");// 348 - } - } - - System.out.println("Beep");// 373 - } - - System.out.println("BLORB");// 375 - } - - System.out.println("Bye");// 377 - }// 378 - - public void testMismatchedOutputExitReturn(int a, int b) { - label54: - while (a > 0) {// 383 - System.out.println("A: " + a);// 384 - a--;// 385 - - for (; b > 0; System.out.println("Beep")) {// 387 411 - a++;// 388 - System.out.println("B: " + b);// 389 - - try { - b--;// 392 - System.out.println("Hello");// 393 - } finally { - System.out.println("Finally");// 395 - if (a > b) {// 396 - a--;// 397 - continue label54;// 398 - } - - System.out.println("Boop");// 400 - } - } - - System.out.println("BLORB");// 413 - } - - System.out.println("Bye");// 415 - }// 416 - - // $VF: Could not verify finally blocks. A semaphore variable has been added to preserve control flow. - public void testMismatchedOutputExitReturnInner(int a, int b) { - while (a > 0) {// 420 - System.out.println("A: " + a);// 421 - a--;// 422 - - while (b > 0) {// 424 - a++;// 425 - System.out.println("B: " + b);// 426 - boolean var5 = false /* VF: Semaphore variable */; - - try { - var5 = true; - b--;// 429 - System.out.println("Hello");// 430 - var5 = false; - } finally { - if (var5) { - System.out.println("Finally");// 432 - if (a > b) {// 433 - a--;// 434 - return;// 435 - } - - System.out.println("Boop");// 437 - } - } - - System.out.println("Finally");// 441 - if (a > b) {// 442 - a--;// 443 - } else { - System.out.println("Boop");// 446 - System.out.println("Beep");// 448 - } - } - - System.out.println("BLORB");// 450 - } - - System.out.println("Bye");// 452 - }// 453 -} - -class 'pkg/TestTryFinallyMarkerExceptionsInvalid' { - method 'testReturn ()Ljava/lang/Object;' { - 0 8 - 1 8 - 2 8 - 3 8 - 4 8 - 5 8 - 6 8 - 7 8 - c 10 - d 10 - e 10 - f 10 - 10 10 - 11 10 - 12 10 - 13 10 - 14 11 - 15 11 - 16 14 - 17 14 - 18 14 - 19 14 - 1a 14 - 1b 14 - 1c 14 - 1d 14 - 1e 15 - 1f 15 - 20 15 - 21 15 - 22 15 - 23 15 - 24 15 - 25 15 - 26 16 - 27 16 - } - - method 'testLogged (I)V' { - 0 22 - 1 22 - 2 22 - 3 22 - 4 22 - 5 22 - 6 22 - 7 22 - c 24 - d 24 - e 24 - f 24 - 10 24 - 11 24 - 12 24 - 13 24 - 14 24 - 15 24 - 16 25 - 17 25 - 18 25 - 19 25 - 1a 25 - 1b 25 - 1c 25 - 1d 25 - 1e 26 - 1f 26 - 20 29 - 21 29 - 22 29 - 23 29 - 24 29 - 25 29 - 26 29 - 27 29 - 28 30 - 29 30 - 2a 30 - 2b 30 - 2c 30 - 2d 30 - 2e 30 - 2f 30 - 30 31 - } - - method 'testWeirdCatch (I)V' { - 0 40 - 1 40 - 2 40 - 3 40 - 4 40 - 5 40 - 6 40 - 7 40 - b 43 - c 51 - d 51 - e 51 - f 51 - 10 51 - 11 51 - 12 51 - 13 51 - 18 47 - 19 47 - 1a 47 - 1b 47 - 1c 47 - 1d 47 - 1e 47 - 1f 47 - 22 54 - 23 54 - 24 54 - 25 54 - 26 54 - 27 54 - 28 54 - 29 54 - 2a 55 - 2b 55 - 2c 55 - 2d 55 - 2e 55 - 2f 55 - 30 55 - 31 55 - 32 56 - } - - method 'testWeirdCatch3 (I)V' { - 0 91 - 1 91 - 2 91 - 3 91 - 4 91 - 5 91 - 6 91 - 7 91 - b 93 - 14 99 - 15 99 - 16 99 - 1e 99 - 1f 99 - 23 99 - 24 99 - 25 99 - 26 99 - 2a 99 - 2b 99 - 2c 99 - 2d 99 - 2e 99 - 2f 99 - 34 96 - 35 96 - 36 96 - 37 96 - 38 96 - 39 96 - 3a 96 - 3b 96 - 46 102 - 47 102 - 48 102 - 49 102 - 4a 102 - 4b 102 - 4c 102 - 4d 102 - 4e 103 - } - - method 'testBlockReuse (I)V' { - 0 111 - 1 111 - 2 111 - 3 111 - 4 111 - 5 111 - 6 111 - 7 111 - c 115 - d 115 - e 115 - f 115 - 10 115 - 11 115 - 12 115 - 13 115 - 14 116 - 15 116 - 16 116 - 17 116 - 18 117 - 19 117 - 1a 117 - 1b 117 - 1c 117 - 1d 117 - 1e 117 - 1f 117 - 23 119 - 24 119 - 25 119 - 26 119 - 27 119 - 28 119 - 29 119 - 2a 119 - 2b 122 - 2c 122 - 2d 122 - 2e 122 - 31 127 - 32 127 - 33 127 - 34 127 - 35 127 - 36 127 - 37 127 - 38 127 - 39 128 - 3a 128 - 3b 128 - 3c 128 - 3d 131 - 3e 131 - 3f 131 - 40 131 - 41 131 - 42 131 - 43 131 - 44 131 - 45 132 - 46 132 - 47 132 - 48 132 - 49 135 - 4a 135 - 4b 135 - 4c 135 - 4d 135 - 4e 135 - 4f 135 - 50 135 - 51 136 - } - - method 'testInjectWrongException (Z)V' { - 0 144 - 1 144 - 2 144 - 3 144 - 4 144 - 5 144 - 6 144 - 7 144 - c 148 - d 148 - e 148 - f 148 - 10 148 - 11 148 - 12 148 - 13 148 - 14 150 - 15 150 - 16 150 - 17 150 - 1c 151 - 1d 151 - 21 151 - 22 154 - 23 154 - 24 154 - 25 154 - 26 154 - 27 154 - 28 154 - 29 154 - 2a 155 - 2b 155 - 2c 159 - 2d 159 - 2e 159 - 2f 159 - 30 159 - 31 159 - 32 159 - 33 159 - 34 160 - 35 160 - 36 160 - 37 160 - 3c 161 - 3d 161 - 42 164 - 43 164 - 44 164 - 45 164 - 46 164 - 47 164 - 48 164 - 49 164 - 4a 165 - 4b 165 - 4c 165 - 4d 165 - 4e 165 - 4f 165 - 50 165 - 51 165 - 52 166 - } - - method 'testMultiImplicitExits (I)V' { - 0 170 - 1 170 - 2 170 - 3 170 - 4 170 - 5 170 - 6 170 - 7 170 - c 172 - d 172 - e 172 - f 172 - 10 172 - 11 172 - 12 172 - 13 172 - 14 173 - 15 173 - 16 173 - 17 173 - 18 174 - 19 174 - 1a 174 - 1b 174 - 1c 174 - 1d 174 - 1e 174 - 1f 174 - 22 175 - 23 175 - 24 175 - 25 175 - 26 176 - 27 176 - 28 176 - 29 176 - 2a 176 - 2b 176 - 2c 176 - 2d 176 - 30 178 - 31 178 - 32 178 - 33 178 - 34 178 - 35 178 - 36 178 - 37 178 - 78 182 - 79 182 - 7a 182 - 7b 182 - 7c 182 - 7d 182 - 7e 182 - 7f 182 - 80 183 - } - - method 'testConfusion1 (Ljava/lang/String;Ljava/lang/String;)V' { - 0 187 - 1 187 - 2 187 - 3 187 - 4 187 - 5 187 - 6 187 - 7 187 - c 189 - d 189 - e 189 - f 189 - 10 189 - 11 189 - 12 189 - 13 189 - 14 190 - 15 190 - 16 190 - 17 190 - 18 190 - 19 190 - 1a 190 - 2c 193 - 2d 193 - 2e 193 - 2f 193 - 30 193 - 31 193 - 32 193 - 33 193 - 34 194 - } - - method 'testConfusion2 ()V' { - 0 198 - 1 198 - 2 198 - 3 198 - 4 198 - 5 198 - 6 198 - 7 198 - d 200 - e 200 - f 200 - 10 200 - 11 200 - 12 200 - 13 200 - 14 200 - 15 201 - 16 201 - 17 201 - 18 202 - 19 202 - 1a 202 - 1b 203 - 1c 203 - 1d 203 - 25 204 - 29 204 - 2d 204 - 2e 204 - 2f 204 - 30 204 - 38 205 - 3c 205 - 40 205 - 41 205 - 42 205 - 43 205 - 4b 206 - 4f 206 - 53 206 - 54 206 - 55 206 - 56 206 - 57 207 - 58 207 - 59 207 - 5a 207 - 5b 207 - 5c 207 - 5d 207 - b2 210 - b3 210 - b4 210 - b5 210 - b6 210 - b7 210 - b8 210 - b9 210 - ba 211 - } - - method 'testMismatchedSwitch (I)V' { - 0 215 - 1 215 - 2 215 - 3 215 - 4 215 - 5 215 - 6 215 - 7 215 - c 217 - d 217 - e 217 - f 217 - 10 217 - 11 217 - 12 217 - 13 217 - 14 218 - 15 218 - 16 218 - 17 218 - 18 218 - 19 218 - 1a 218 - 1b 218 - 1c 218 - 1d 218 - 1e 218 - 1f 218 - 20 218 - 21 218 - 22 218 - 23 218 - 24 218 - 25 218 - 26 218 - 27 218 - 28 218 - 29 218 - 2a 218 - 2b 218 - 2c 218 - 2d 218 - 2e 218 - 2f 218 - 30 218 - 31 218 - 32 218 - 33 218 - 34 218 - 35 218 - 36 218 - 37 218 - 38 218 - 39 218 - 3a 218 - 3b 218 - 3c 218 - 3d 218 - 3e 218 - 3f 218 - 40 218 - 41 218 - 42 218 - 43 218 - 44 218 - 45 218 - 46 218 - 47 218 - 48 218 - 49 218 - 4a 218 - 4b 218 - 4c 218 - 4d 218 - 4e 218 - 4f 218 - 50 220 - 51 220 - 52 220 - 53 220 - 54 220 - 55 220 - 56 220 - 57 220 - 58 222 - 59 222 - 5a 222 - 5b 222 - 5c 222 - 5d 222 - 5e 222 - 5f 222 - 60 224 - 61 224 - 62 224 - 63 224 - 64 224 - 65 224 - 66 224 - 67 224 - 68 226 - 69 226 - 6a 226 - 6b 226 - 6c 226 - 6d 226 - 6e 226 - 6f 226 - 70 228 - 71 228 - 72 228 - 73 228 - 74 228 - 75 228 - 76 228 - 77 228 - 78 230 - 79 230 - 7a 230 - 7b 230 - 7c 230 - 7d 230 - 7e 230 - 7f 230 - 80 232 - 81 232 - 82 232 - 83 232 - 84 232 - 85 232 - 86 232 - 87 232 - 88 234 - 89 234 - 8a 234 - 8b 234 - 8c 234 - 8d 234 - 8e 234 - 8f 234 - 90 236 - 91 236 - 92 236 - 93 236 - 94 236 - 95 236 - 96 236 - 97 236 - 98 238 - 99 238 - 9a 238 - 9b 238 - 9c 238 - 9d 238 - 9e 238 - 9f 238 - a0 240 - a1 240 - a2 240 - a3 240 - a4 240 - a5 240 - a6 240 - a7 240 - 144 244 - 145 244 - 146 244 - 147 244 - 148 244 - 149 244 - 14a 244 - 14b 244 - 14c 245 - } - - method 'testMismatchedOutputExit (II)V' { - 0 249 - 1 249 - 2 249 - 3 249 - 4 250 - 5 250 - 6 250 - e 250 - f 250 - 13 250 - 17 250 - 18 250 - 19 250 - 1a 250 - 1b 250 - 1c 250 - 1d 251 - 1e 251 - 1f 251 - 20 253 - 21 253 - 22 253 - 23 253 - 24 254 - 25 254 - 26 254 - 27 255 - 28 255 - 29 255 - 31 255 - 32 255 - 36 255 - 3a 255 - 3b 255 - 3c 255 - 3d 255 - 3e 255 - 3f 255 - 40 258 - 41 258 - 42 258 - 43 259 - 44 259 - 45 259 - 46 259 - 47 259 - 48 259 - 49 259 - 4a 259 - 4f 261 - 50 261 - 51 261 - 52 261 - 53 261 - 54 261 - 55 261 - 56 261 - 57 262 - 58 262 - 59 262 - 5a 262 - 5b 262 - 5c 263 - 5d 263 - 5e 263 - 5f 264 - 62 267 - 63 267 - 64 267 - 65 267 - 66 267 - 67 267 - 68 267 - 69 267 - 87 253 - 88 253 - 89 253 - 8a 253 - 8b 253 - 8c 253 - 8d 253 - 8e 253 - 92 271 - 93 271 - 94 271 - 95 271 - 96 271 - 97 271 - 98 271 - 99 271 - 9d 274 - 9e 274 - 9f 274 - a0 274 - a1 274 - a2 274 - a3 274 - a4 274 - a5 275 - } - - method 'testMismatchedOutputExit3 (III)V' { - 0 279 - 1 279 - 2 279 - 3 279 - 4 280 - 5 280 - 6 280 - e 280 - f 280 - 13 280 - 17 280 - 18 280 - 19 280 - 1a 280 - 1b 280 - 1c 280 - 1d 281 - 1e 281 - 1f 281 - 20 284 - 21 284 - 22 284 - 23 284 - 24 285 - 25 285 - 26 285 - 27 286 - 28 286 - 29 286 - 31 286 - 32 286 - 36 286 - 3a 286 - 3b 286 - 3c 286 - 3d 286 - 3e 286 - 3f 286 - 40 288 - 41 288 - 42 288 - 43 288 - 45 289 - 47 289 - 48 292 - 49 292 - 4a 292 - 4b 293 - 4c 293 - 4d 293 - 4e 293 - 4f 293 - 50 293 - 51 293 - 52 293 - 53 294 - 54 294 - 55 294 - 56 294 - 57 294 - 60 298 - 61 298 - 62 298 - 63 298 - 64 298 - 65 298 - 66 298 - 67 298 - 68 299 - 69 299 - 6a 299 - 6b 299 - 6c 299 - 6d 300 - 6e 300 - 6f 300 - 70 301 - 73 304 - 74 304 - 75 304 - 76 304 - 77 304 - 78 304 - 79 304 - 7a 304 - ba 288 - bb 288 - bc 288 - bd 288 - be 288 - bf 288 - c0 288 - c1 288 - c5 308 - c6 308 - c7 308 - c8 308 - c9 308 - ca 308 - cb 308 - cc 308 - d0 311 - d1 311 - d2 311 - d3 311 - d4 311 - d5 311 - d6 311 - d7 311 - db 314 - dc 314 - dd 314 - de 314 - df 314 - e0 314 - e1 314 - e2 314 - e3 315 - } - - method 'testMismatchedOutputExitReturn (II)V' { - 0 319 - 1 319 - 2 319 - 3 319 - 4 320 - 5 320 - 6 320 - e 320 - f 320 - 13 320 - 17 320 - 18 320 - 19 320 - 1a 320 - 1b 320 - 1c 320 - 1d 321 - 1e 321 - 1f 321 - 20 323 - 21 323 - 22 323 - 23 323 - 24 324 - 25 324 - 26 324 - 27 325 - 28 325 - 29 325 - 31 325 - 32 325 - 36 325 - 3a 325 - 3b 325 - 3c 325 - 3d 325 - 3e 325 - 3f 325 - 40 328 - 41 328 - 42 328 - 43 329 - 44 329 - 45 329 - 46 329 - 47 329 - 48 329 - 49 329 - 4a 329 - 4f 331 - 50 331 - 51 331 - 52 331 - 53 331 - 54 331 - 55 331 - 56 331 - 57 332 - 58 332 - 59 332 - 5a 332 - 5b 332 - 5c 333 - 5d 333 - 5e 333 - 5f 334 - 62 337 - 63 337 - 64 337 - 65 337 - 66 337 - 67 337 - 68 337 - 69 337 - 85 323 - 86 323 - 87 323 - 88 323 - 89 323 - 8a 323 - 8b 323 - 8c 323 - 90 341 - 91 341 - 92 341 - 93 341 - 94 341 - 95 341 - 96 341 - 97 341 - 9b 344 - 9c 344 - 9d 344 - 9e 344 - 9f 344 - a0 344 - a1 344 - a2 344 - a3 345 - } - - method 'testMismatchedOutputExitReturnInner (II)V' { - 0 349 - 1 349 - 2 349 - 3 349 - 4 350 - 5 350 - 6 350 - e 350 - f 350 - 13 350 - 17 350 - 18 350 - 19 350 - 1a 350 - 1b 350 - 1c 350 - 1d 351 - 1e 351 - 1f 351 - 20 353 - 21 353 - 22 353 - 23 353 - 24 354 - 25 354 - 26 354 - 27 355 - 28 355 - 29 355 - 31 355 - 32 355 - 36 355 - 3a 355 - 3b 355 - 3c 355 - 3d 355 - 3e 355 - 3f 355 - 40 360 - 41 360 - 42 360 - 43 361 - 44 361 - 45 361 - 46 361 - 47 361 - 48 361 - 49 361 - 4a 361 - 4f 365 - 50 365 - 51 365 - 52 365 - 53 365 - 54 365 - 55 365 - 56 365 - 57 366 - 58 366 - 59 366 - 5a 366 - 5b 366 - 5c 367 - 5d 367 - 5e 367 - 5f 368 - 60 371 - 61 371 - 62 371 - 63 371 - 64 371 - 65 371 - 66 371 - 67 371 - 6a 375 - 6b 375 - 6c 375 - 6d 375 - 6e 375 - 6f 375 - 70 375 - 71 375 - 72 376 - 73 376 - 74 376 - 75 376 - 76 376 - 77 377 - 78 377 - 79 377 - 7d 379 - 7e 379 - 7f 379 - 80 379 - 81 379 - 82 379 - 83 379 - 84 379 - 85 380 - 86 380 - 87 380 - 88 380 - 89 380 - 8a 380 - 8b 380 - 8c 380 - 90 384 - 91 384 - 92 384 - 93 384 - 94 384 - 95 384 - 96 384 - 97 384 - 9b 387 - 9c 387 - 9d 387 - 9e 387 - 9f 387 - a0 387 - a1 387 - a2 387 - a3 388 - } -} - -Lines mapping: -8 <-> 9 -10 <-> 11 -11 <-> 12 -14 <-> 15 -17 <-> 16 -18 <-> 17 -24 <-> 23 -27 <-> 25 -29 <-> 26 -30 <-> 27 -33 <-> 30 -36 <-> 31 -37 <-> 32 -44 <-> 41 -45 <-> 44 -46 <-> 52 -48 <-> 48 -52 <-> 55 -55 <-> 56 -56 <-> 57 -81 <-> 92 -82 <-> 94 -84 <-> 100 -86 <-> 97 -93 <-> 103 -94 <-> 104 -101 <-> 112 -103 <-> 116 -104 <-> 117 -105 <-> 118 -107 <-> 120 -109 <-> 123 -113 <-> 128 -114 <-> 129 -115 <-> 132 -116 <-> 133 -119 <-> 136 -120 <-> 137 -124 <-> 145 -126 <-> 149 -127 <-> 151 -128 <-> 152 -130 <-> 155 -131 <-> 156 -134 <-> 160 -135 <-> 161 -136 <-> 162 -138 <-> 165 -141 <-> 166 -142 <-> 167 -146 <-> 171 -148 <-> 173 -149 <-> 174 -150 <-> 175 -152 <-> 176 -153 <-> 177 -156 <-> 179 -170 <-> 183 -173 <-> 184 -177 <-> 188 -179 <-> 190 -180 <-> 191 -187 <-> 194 -188 <-> 195 -193 <-> 199 -195 <-> 201 -196 <-> 202 -197 <-> 203 -198 <-> 204 -199 <-> 205 -200 <-> 206 -201 <-> 207 -202 <-> 208 -215 <-> 211 -216 <-> 212 -221 <-> 216 -223 <-> 218 -224 <-> 219 -226 <-> 221 -228 <-> 223 -230 <-> 225 -232 <-> 227 -234 <-> 229 -236 <-> 231 -238 <-> 233 -240 <-> 235 -242 <-> 237 -244 <-> 239 -246 <-> 241 -277 <-> 245 -278 <-> 246 -282 <-> 250 -283 <-> 251 -284 <-> 252 -286 <-> 254 -287 <-> 255 -288 <-> 256 -291 <-> 259 -292 <-> 260 -294 <-> 262 -295 <-> 263 -296 <-> 264 -297 <-> 265 -299 <-> 268 -310 <-> 254 -312 <-> 272 -314 <-> 275 -315 <-> 276 -320 <-> 280 -321 <-> 281 -322 <-> 282 -324 <-> 285 -325 <-> 286 -326 <-> 287 -329 <-> 289 -330 <-> 290 -337 <-> 293 -338 <-> 294 -339 <-> 295 -343 <-> 299 -344 <-> 300 -345 <-> 301 -346 <-> 302 -348 <-> 305 -371 <-> 289 -373 <-> 309 -375 <-> 312 -377 <-> 315 -378 <-> 316 -383 <-> 320 -384 <-> 321 -385 <-> 322 -387 <-> 324 -388 <-> 325 -389 <-> 326 -392 <-> 329 -393 <-> 330 -395 <-> 332 -396 <-> 333 -397 <-> 334 -398 <-> 335 -400 <-> 338 -411 <-> 324 -413 <-> 342 -415 <-> 345 -416 <-> 346 -420 <-> 350 -421 <-> 351 -422 <-> 352 -424 <-> 354 -425 <-> 355 -426 <-> 356 -429 <-> 361 -430 <-> 362 -432 <-> 366 -433 <-> 367 -434 <-> 368 -435 <-> 369 -437 <-> 372 -441 <-> 376 -442 <-> 377 -443 <-> 378 -446 <-> 380 -448 <-> 381 -450 <-> 385 -452 <-> 388 -453 <-> 389 -Not mapped: -9 -12 -25 -31 -47 -49 -50 -83 -85 -87 -88 -90 -102 -110 -111 -125 -132 -147 -151 -154 -157 -159 -161 -162 -163 -164 -165 -166 -167 -169 -178 -181 -182 -184 -185 -194 -203 -204 -206 -207 -208 -209 -210 -211 -212 -213 -222 -248 -249 -251 -252 -254 -256 -258 -260 -262 -264 -266 -268 -270 -272 -274 -293 -300 -301 -303 -304 -305 -306 -308 -340 -342 -349 -350 -352 -353 -354 -355 -357 -359 -362 -363 -364 -365 -367 -368 -394 -401 -402 -404 -405 -406 -407 -409 -431 -438 -439 -444 \ No newline at end of file diff --git a/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java index 04bbe8408d..23dcece0b1 100644 --- a/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java +++ b/testData/src/java8/pkg/TestTryFinallyMarkerExceptionsInvalid.java @@ -141,7 +141,7 @@ public void testInjectWrongException(boolean b) { System.out.println("Bye"); } - public void testMultiImplicitExits(int i) { + public void testMultiImplicitExitsBad(int i) { try { System.out.println("Hello"); } catch (CatchAllException e) { @@ -172,6 +172,36 @@ public void testMultiImplicitExits(int i) { } } + + public void testMultiImplicitExitsGood(int i) { + try { + System.out.println("Hello"); + } catch (CatchAllException e) { + System.out.println("Finally"); + if (i > 0) { + System.out.println("Positive!"); + throw e; + } else if (i == 0) { + System.out.println("ZERO"); + throw e; + } else { + System.out.println("Negative!"); + throw e; + } + } + { + System.out.println("Finally"); + if (i > 0) { + System.out.println("Positive!"); + } else if (i == 0) { + System.out.println("ZERO"); + } else { + System.out.println("Negative!"); + } + } + System.out.println("Bye"); + } + public void testConfusion1(String a, String b) { try { System.out.println("Hello"); From d5306ab79caeeb028c1f322b09c43e5453e7adbd Mon Sep 17 00:00:00 2001 From: Robbe Pincket <7889478+Kroppeb@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:57:19 +0200 Subject: [PATCH 22/29] Fix stats desync issue and add validation checks (#603) --- .../modules/decompiler/ValidationHelper.java | 24 ++++++++++++++++--- .../decompiler/stats/SwitchStatement.java | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ValidationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ValidationHelper.java index c848a3b679..dcb116b932 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ValidationHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ValidationHelper.java @@ -38,21 +38,36 @@ public static void validateStatement(RootStatement statement) { while (!stack.isEmpty()) { Statement stat = stack.pop(); - statements.putWithKey(stat, stat.id); - - stack.addAll(stat.getStats()); + if (statements.containsKey(stat.id)) { + if (statements.getWithKey(stat.id) != stat){ + throw new IllegalStateException("2 stats with the same id: " + stat + " vs " + statements.getWithKey(stat.id)); + } + // The else case means multiple parent. A later check will produce better error than we could do here. + } else { + statements.putWithKey(stat, stat.id); + stack.addAll(stat.getStats()); + } } for (Statement stat : statements) { for (StatEdge edge : stat.getAllSuccessorEdges()) { + if (edge.getSource() != stat) { + throw new IllegalStateException("Stat " + stat + " has successor edge for which it isn't the source: " + edge); + } validateEdgeContext(statements, stat, edge); } for (StatEdge edge : stat.getAllPredecessorEdges()) { + if (edge.getDestination() != stat) { + throw new IllegalStateException("Stat " + stat + " has predecessor edge for which it isn't the destination: " + edge); + } validateEdgeContext(statements, stat, edge); } for (StatEdge edge : stat.getLabelEdges()) { + if (edge.closure != stat) { + throw new IllegalStateException("Stat " + stat + " has a labelled edge for which it isn't the closure: " + edge); + } validateEdgeContext(statements, stat, edge); } @@ -74,6 +89,9 @@ public static void validateStatement(RootStatement statement) { if (statStat.getParent() != stat) { throw new IllegalStateException("Statement parent is not set correctly [" + statStat + "]: Expected " + stat + " but was " + statStat.getParent()); } + if (!stat.getStats().containsKey(statStat.id)){ + throw new IllegalStateException("Statement " + stat + " contains non stat without id lookup: " + statStat); + } } validateSingleStatement(stat); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java index 6daa5eeb8d..478e9b9fbf 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -578,7 +578,7 @@ public void addCase(int index, List values, Statement stat) { private void addCaseInternal(int index, List<@Nullable Exprent> values, Statement stat) { // Basichead is always the first stat - this.getStats().add(1 + index, stat); + this.getStats().addWithKeyAndIndex(1 + index, stat, stat.id); this.getCaseStatements().add(index, stat); this.getCaseValues().add(index, values); From ceb1d13561bd8ef41b03dda1d3d78f62befdbc3c Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:18:16 -0500 Subject: [PATCH 23/29] Optimize sparse set int[] alloc --- .../modules/decompiler/flow/DirectNode.java | 7 +- .../java/decompiler/util/TextBuffer.java | 6 +- .../collections/FastSparseSetFactory.java | 323 +++++++++++++----- 3 files changed, 253 insertions(+), 83 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/flow/DirectNode.java b/src/org/jetbrains/java/decompiler/modules/decompiler/flow/DirectNode.java index c3ffd64159..9c0fd4675d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/flow/DirectNode.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/flow/DirectNode.java @@ -80,7 +80,12 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(type, id); + int res = 1; + + res = 31 * res + type.hashCode(); + res = 31 * res + id.hashCode(); + + return res; } @Override diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index 6f4d1100b2..bc21c40815 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -841,7 +841,11 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(myBytecodeOffset, myClass, myMethod); + int res = 1; + res = 31 * res + Integer.hashCode(myBytecodeOffset); + res = 31 * res + (myClass == null ? 0 : myClass.hashCode()); + res = 31 * res + (myMethod == null ? 0 : myMethod.hashCode()); + return res; } @Override diff --git a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java index 77461de2b9..27d46ee252 100644 --- a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java +++ b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java @@ -1,6 +1,9 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.util.collections; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.decompiler.modules.decompiler.ValidationHelper; + import java.util.*; public class FastSparseSetFactory { @@ -67,8 +70,10 @@ public static final class FastSparseSet implements Iterable { private final PackedMap colValuesInternal; - private int[] data; - private int[] next; + @NotNull + private final FastSparseSetFactory.ArrayHolder data; + @NotNull + private final FastSparseSetFactory.ArrayHolder next; private FastSparseSet(FastSparseSetFactory factory) { this.factory = factory; @@ -79,11 +84,11 @@ private FastSparseSet(FastSparseSetFactory factory) { // don't produce -1 lengths. // TODO: the array init of size 1 can be elided, and the array can be lazy initialized when sized above 1 int length = Math.max(factory.getLastBlock(), 1); - this.data = new int[length]; - this.next = null; + this.data = new ArrayHolder(length); + this.next = new ArrayHolder(length); } - private FastSparseSet(FastSparseSetFactory factory, int[] data, int[] next) { + private FastSparseSet(FastSparseSetFactory factory, ArrayHolder data, ArrayHolder next) { this.factory = factory; this.colValuesInternal = factory.getInternalValuesCollection(); @@ -92,15 +97,15 @@ private FastSparseSet(FastSparseSetFactory factory, int[] data, int[] next) { } public FastSparseSet getCopy() { - int[] newData = this.data.clone(); - int[] newNext = this.next == null ? null : this.next.clone(); + ArrayHolder newData = this.data.copy(); + ArrayHolder newNext = this.next.copy(); return new FastSparseSet<>(factory, newData, newNext); } - private int[] ensureCapacity(int index) { + private void ensureCapacity(int index) { - int newlength = data.length; + int newlength = data.length(); if (newlength == 0) { newlength = 1; } @@ -109,12 +114,8 @@ private int[] ensureCapacity(int index) { newlength *= 2; } - data = Arrays.copyOf(data, newlength); - if (next != null) { - next = Arrays.copyOf(next, newlength); - } - - return data; + data.resize(newlength); + next.resize(newlength); } public void add(E element) { @@ -126,25 +127,17 @@ public void add(E element) { } int block = PackedMap.unpackLow(index); - if (block >= data.length) { + if (block >= data.length()) { ensureCapacity(block); } - data[block] |= PackedMap.unpackHigh(index); + data.set(block, data.get(block) | PackedMap.unpackHigh(index)); changeNext(block, getNextIdx(block), block); } private int getNextIdx(int block) { - return next == null ? 0 : next[block]; - } - - private int[] allocNext() { - if (next == null) { - next = new int[data.length]; - } - - return next; + return next.get(block); } public void remove(E element) { @@ -157,10 +150,10 @@ public void remove(E element) { } int block = PackedMap.unpackLow(index); - if (block < data.length) { - data[block] &= ~PackedMap.unpackHigh(index); + if (block < data.length()) { + data.set(block, data.get(block) & ~PackedMap.unpackHigh(index)); - if (data[block] == 0) { + if (data.get(block) == 0) { changeNext(block, block, getNextIdx(block)); } } @@ -176,19 +169,18 @@ public boolean contains(E element) { } int block = PackedMap.unpackLow(index); - return block < data.length && ((data[block] & PackedMap.unpackHigh(index)) != 0); + return block < data.length() && ((data.get(block) & PackedMap.unpackHigh(index)) != 0); } private void setNext() { int link = 0; - for (int i = data.length - 1; i >= 0; i--) { - if (link != 0 && next == null) { - allocNext(); - next[i] = link; + for (int i = data.length() - 1; i >= 0; i--) { + if (link != 0) { + next.set(i, link); } - if (data[i] != 0) { + if (data.get(i) != 0) { link = i; } } @@ -197,8 +189,7 @@ private void setNext() { private void changeNext(int key, int oldnext, int newnext) { for (int i = key - 1; i >= 0; i--) { if (getNextIdx(i) == oldnext) { - allocNext(); - next[i] = newnext; + next.set(i, newnext); } else { break; } @@ -207,18 +198,18 @@ private void changeNext(int key, int oldnext, int newnext) { public void union(FastSparseSet set) { - int[] extdata = set.getData(); - int[] intdata = data; - int intlength = intdata.length; + ArrayHolder extdata = set.getData(); + ArrayHolder intdata = data; + int intlength = intdata.length(); int pointer = 0; do { if (pointer >= intlength) { - intdata = ensureCapacity(extdata.length - 1); + ensureCapacity(extdata.length() - 1); } - boolean nextrec = (intdata[pointer] == 0); - intdata[pointer] |= extdata[pointer]; + boolean nextrec = (intdata.get(pointer) == 0); + intdata.set(pointer, intdata.get(pointer) | extdata.get(pointer)); if (nextrec) { changeNext(pointer, getNextIdx(pointer), pointer); @@ -230,17 +221,17 @@ public void union(FastSparseSet set) { } public void intersection(FastSparseSet set) { - int[] extdata = set.getData(); - int[] intdata = data; + ArrayHolder extdata = set.getData(); + ArrayHolder intdata = data; - int minlength = Math.min(extdata.length, intdata.length); + int minlength = Math.min(extdata.length(), intdata.length()); for (int i = minlength - 1; i >= 0; i--) { - intdata[i] &= extdata[i]; + intdata.set(i, intdata.get(i) & extdata.get(i)); } - for (int i = intdata.length - 1; i >= minlength; i--) { - intdata[i] = 0; + for (int i = intdata.length() - 1; i >= minlength; i--) { + intdata.set(i, 0); } setNext(); @@ -248,9 +239,9 @@ public void intersection(FastSparseSet set) { public void complement(FastSparseSet set) { - int[] extdata = set.getData(); - int[] intdata = data; - int extlength = extdata.length; + ArrayHolder extdata = set.getData(); + ArrayHolder intdata = data; + int extlength = extdata.length(); int pointer = 0; do { @@ -258,8 +249,8 @@ public void complement(FastSparseSet set) { break; } - intdata[pointer] &= ~extdata[pointer]; - if (intdata[pointer] == 0) { + intdata.set(pointer, intdata.get(pointer) & ~extdata.get(pointer)); + if (intdata.get(pointer) == 0) { changeNext(pointer, pointer, getNextIdx(pointer)); } @@ -277,22 +268,22 @@ public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof FastSparseSet)) return false; - int[] longdata = ((FastSparseSet)o).getData(); - int[] shortdata = data; + ArrayHolder longdata = ((FastSparseSet)o).getData(); + ArrayHolder shortdata = data; - if (data.length > longdata.length) { + if (data.length() > longdata.length()) { shortdata = longdata; longdata = data; } - for (int i = shortdata.length - 1; i >= 0; i--) { - if (shortdata[i] != longdata[i]) { + for (int i = shortdata.length() - 1; i >= 0; i--) { + if (shortdata.get(i) != longdata.get(i)) { return false; } } - for (int i = longdata.length - 1; i >= shortdata.length; i--) { - if (longdata[i] != 0) { + for (int i = longdata.length() - 1; i >= shortdata.length(); i--) { + if (longdata.get(i) != 0) { return false; } } @@ -303,19 +294,17 @@ public boolean equals(Object o) { public int getCardinality() { boolean found = false; - int[] intdata = data; + ArrayHolder intdata = data; - for (int i = intdata.length - 1; i >= 0; i--) { - int block = intdata[i]; + for (int i = intdata.length() - 1; i >= 0; i--) { + int block = intdata.get(i); if (block != 0) { if (found) { return 2; - } - else { + } else { if ((block & (block - 1)) == 0) { found = true; - } - else { + } else { return 2; } } @@ -326,7 +315,7 @@ public int getCardinality() { } public boolean isEmpty() { - return data.length == 0 || (getNextIdx( 0) == 0 && data[0] == 0); + return data.length() == 0 || (getNextIdx( 0) == 0 && data.get(0) == 0); } @Override @@ -337,9 +326,9 @@ public Iterator iterator() { public Set toPlainSet() { HashSet set = new HashSet<>(); - int[] intdata = data; + ArrayHolder intdata = data; - int size = data.length * 32; + int size = data.length() * 32; if (size > colValuesInternal.size()) { size = colValuesInternal.size(); } @@ -347,7 +336,8 @@ public Set toPlainSet() { for (int i = size - 1; i >= 0; i--) { long index = colValuesInternal.get(i); - if ((intdata[PackedMap.unpackLow(index)] & PackedMap.unpackHigh(index)) != 0) { + int lo = PackedMap.unpackLow(index); + if ((intdata.get(lo) & PackedMap.unpackHigh(index)) != 0) { set.add(colValuesInternal.getKey(i)); } } @@ -359,24 +349,23 @@ public String toString() { return toPlainSet().toString(); } - private int[] getData() { + private ArrayHolder getData() { return data; } - private int[] getNext() { + private ArrayHolder getNext() { return next; } private FastSparseSetFactory getFactory() { return factory; } - } public static final class FastSparseSetIterator implements Iterator { private final PackedMap colValuesInternal; - private final int[] data; - private final int[] next; + private final ArrayHolder data; + private final ArrayHolder next; private final int size; private int pointer = -1; @@ -395,8 +384,8 @@ private int getNextIndex(int index) { int bindex = index >>> 5; int dindex = index & 0x1F; - while (bindex < data.length) { - int block = data[bindex]; + while (bindex < data.length()) { + int block = data.get(bindex); if (block != 0) { block >>>= dindex; @@ -410,7 +399,7 @@ private int getNextIndex(int index) { } dindex = 0; - bindex = next == null ? 0 : next[bindex]; + bindex = next.get(bindex); if (bindex == 0) { break; @@ -445,7 +434,179 @@ public E next() { @Override public void remove() { long index = colValuesInternal.get(pointer); - data[PackedMap.unpackLow(index)] &= ~PackedMap.unpackHigh(index); + int lo = PackedMap.unpackLow(index); + data.set(lo, data.get(lo) & ~PackedMap.unpackHigh(index)); + } + } + + } + + private static class ArrayHolder { + private ArrayTower tower = ArrayTower.None.INSTANCE; + private int size; + + public ArrayHolder(int size) { + this.size = size; + } + + public int get(int index) { + return tower.get(index); + } + + public void set(int index, int value) { + if (!tower.canSet(index, value)) { + ArrayTower last = tower; + if (tower instanceof ArrayTower.None) { + tower = new ArrayTower.Single(index, value); + } else if (tower instanceof ArrayTower.Single single) { + if (single.value == value) { + // Same value with multiple indices, use bitset + BitSet bits = new BitSet(); + bits.set(single.index); + tower = new ArrayTower.Bits(value, bits); + } else { + // Different values, fall all the way down to array + int[] ints = new int[size]; + ints[single.index] = single.value; + tower = new ArrayTower.Array(ints); + } + } else if (tower instanceof ArrayTower.Bits bits) { + int[] ints = new int[size]; + bits.promote(ints); + tower = new ArrayTower.Array(ints); + } + + ValidationHelper.validateTrue(last != tower, "must have changed"); + } + + tower.set(index, value); + } + + public void resize(int newSize) { + if (newSize > size) { + size = newSize; + + if (tower instanceof ArrayTower.Array ary) { + tower = new ArrayTower.Array(Arrays.copyOf(ary.ary, newSize)); + } + } + } + + public ArrayHolder copy() { + ArrayHolder next = new ArrayHolder(size); + next.tower = tower.copy(); + + return next; + } + + public int length() { + return size; + } + } + + private sealed interface ArrayTower { + int get(int i); + + default void set(int i, int v) { + if (canSet(i, v)) { + return; + } + + throw new IllegalStateException("Can't set " + i + " " + v); + } + + boolean canSet(int i, int v); + + ArrayTower copy(); + + record None() implements ArrayTower { + public static final None INSTANCE = new None(); + + @Override + public int get(int i) { + return 0; + } + + @Override + public boolean canSet(int i, int v) { + return v == 0; + } + + @Override + public ArrayTower copy() { + return INSTANCE; + } + } + + record Single(int index, int value) implements ArrayTower { + + @Override + public int get(int i) { + return i == index ? value : 0; + } + + @Override + public boolean canSet(int i, int v) { + return (i == index && v == value) || (i != index && v == 0); + } + + @Override + public ArrayTower copy() { + return new Single(index, value); + } + } + + record Bits(int value, BitSet index) implements ArrayTower { + + @Override + public int get(int i) { + return index.get(i) ? value : 0; + } + + @Override + public void set(int i, int v) { + ValidationHelper.assertTrue(v == value || v == 0, "must be"); + index.set(i, v == value); + } + + @Override + public boolean canSet(int i, int v) { + return value == v || v == 0; + } + + @Override + public ArrayTower copy() { + return new ArrayTower.Bits(value, (BitSet) index.clone()); + } + + public void promote(int[] ary) { + for (int i = 0; i < ary.length; i++) { + ary[i] = get(i); + } + } + } + + record Array(int[] ary) implements ArrayTower { + + @Override + public int get(int i) { + return ary[i]; + } + + @Override + public void set(int i, int v) { + ary[i] = v; + } + + @Override + public boolean canSet(int i, int v) { + return true; + } + + @Override + public ArrayTower copy() { + return new ArrayTower.Array(Arrays.copyOf(ary, ary.length)); + } } } } From 7937d31390d89f82955f7bcc85844c604a548e9d Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 8 Nov 2025 14:52:13 -0500 Subject: [PATCH 24/29] More aggressive optimizations for memory usage --- .../decompiler/main/rels/MethodProcessor.java | 8 +- .../modules/decompiler/ExprProcessor.java | 17 + .../java/decompiler/struct/gen/VarType.java | 4 +- .../collections/FastSparseSetFactory.java | 279 +++++++++++-- .../util/collections/SFormsFastMapDirect.java | 381 +++++++++++++----- 5 files changed, 532 insertions(+), 157 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java index ccee225600..d7c108a1ce 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java @@ -87,9 +87,9 @@ public void run() { public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDescriptor md, VarProcessor varProc, LanguageSpec spec) throws IOException { CancelationManager.checkCanceled(); - debugCurrentlyDecompiling.set(null); - debugCurrentCFG.set(null); - debugCurrentDecompileRecord.set(null); + debugCurrentlyDecompiling.remove(); + debugCurrentCFG.remove(); + debugCurrentDecompileRecord.remove(); boolean isInitializer = CodeConstants.CLINIT_NAME.equals(mt.getName()); // for now static initializer only PluginContext pluginContext = PluginContext.getCurrentContext(); @@ -497,6 +497,8 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe // Debug print the decompile record DotExporter.toDotFile(decompileRecord, mt, "decompileRecord", false); + // Delete unneeded data now that processing is complete + ExprProcessor.releaseResources(root, varProc); mt.releaseResources(); return root; diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index fa11313f6a..f392856ace 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -764,6 +764,23 @@ private static void markExprOddity(RootStatement root, Exprent ex, boolean block } } + public static void releaseResources(RootStatement stat, VarProcessor varProc) { + releaseResources(stat); + + varProc.getVarVersions().getTypeProcessor().getUpperBounds().clear(); + } + + private static void releaseResources(Statement stat) { + for (Statement st : stat.getStats()) { + releaseResources(st); + } + + if (stat instanceof BasicBlockStatement block) { + ((ArrayList)block.getBlock().getInstrOldOffsets()).trimToSize(); + ((ArrayList) block.getExprents()).trimToSize(); + } + } + public static String getTypeName(VarType type) { return getTypeName(type, true); } diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java index 5eef9761a5..b0caa2bcdc 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java @@ -80,7 +80,7 @@ protected VarType(CodeType type, int arrayDim, String value, TypeFamily typeFami ValidationHelper.assertTrue(type == CodeType.NULL || value != null, "Must not be null for non null type"); this.type = type; this.arrayDim = arrayDim; - this.value = value; + this.value = value == null ? null : value.intern(); this.typeFamily = typeFamily; this.stackSize = stackSize; } @@ -122,7 +122,7 @@ public VarType(String signature, boolean clType) { this.type = type; this.arrayDim = arrayDim; - this.value = value; + this.value = value == null ? null : value.intern(); this.typeFamily = getFamily(type, arrayDim); this.stackSize = getStackSize(type, arrayDim); } diff --git a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java index 27d46ee252..bf53969496 100644 --- a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java +++ b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java @@ -71,9 +71,9 @@ public static final class FastSparseSet implements Iterable { private final PackedMap colValuesInternal; @NotNull - private final FastSparseSetFactory.ArrayHolder data; + private final FastSparseSetFactory.IntArray data; @NotNull - private final FastSparseSetFactory.ArrayHolder next; + private final FastSparseSetFactory.IntArray next; private FastSparseSet(FastSparseSetFactory factory) { this.factory = factory; @@ -82,13 +82,12 @@ private FastSparseSet(FastSparseSetFactory factory) { // Originally, this returned factory.getLastBlock() + 1. However, in the most common case, only 1 element is added. // This means that the array is unnecessarily large. Instead, max(lastBlock, 1) is used to ensure empty factories // don't produce -1 lengths. - // TODO: the array init of size 1 can be elided, and the array can be lazy initialized when sized above 1 int length = Math.max(factory.getLastBlock(), 1); - this.data = new ArrayHolder(length); - this.next = new ArrayHolder(length); + this.data = new IntArray(length); + this.next = new IntArray(length); } - private FastSparseSet(FastSparseSetFactory factory, ArrayHolder data, ArrayHolder next) { + private FastSparseSet(FastSparseSetFactory factory, IntArray data, IntArray next) { this.factory = factory; this.colValuesInternal = factory.getInternalValuesCollection(); @@ -97,8 +96,8 @@ private FastSparseSet(FastSparseSetFactory factory, ArrayHolder data, ArrayHo } public FastSparseSet getCopy() { - ArrayHolder newData = this.data.copy(); - ArrayHolder newNext = this.next.copy(); + IntArray newData = this.data.copy(); + IntArray newNext = this.next.copy(); return new FastSparseSet<>(factory, newData, newNext); } @@ -187,6 +186,10 @@ private void setNext() { } private void changeNext(int key, int oldnext, int newnext) { + if (oldnext == newnext) { + return; + } + for (int i = key - 1; i >= 0; i--) { if (getNextIdx(i) == oldnext) { next.set(i, newnext); @@ -198,8 +201,8 @@ private void changeNext(int key, int oldnext, int newnext) { public void union(FastSparseSet set) { - ArrayHolder extdata = set.getData(); - ArrayHolder intdata = data; + IntArray extdata = set.getData(); + IntArray intdata = data; int intlength = intdata.length(); int pointer = 0; @@ -221,8 +224,8 @@ public void union(FastSparseSet set) { } public void intersection(FastSparseSet set) { - ArrayHolder extdata = set.getData(); - ArrayHolder intdata = data; + IntArray extdata = set.getData(); + IntArray intdata = data; int minlength = Math.min(extdata.length(), intdata.length()); @@ -239,8 +242,8 @@ public void intersection(FastSparseSet set) { public void complement(FastSparseSet set) { - ArrayHolder extdata = set.getData(); - ArrayHolder intdata = data; + IntArray extdata = set.getData(); + IntArray intdata = data; int extlength = extdata.length(); int pointer = 0; @@ -268,8 +271,8 @@ public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof FastSparseSet)) return false; - ArrayHolder longdata = ((FastSparseSet)o).getData(); - ArrayHolder shortdata = data; + IntArray longdata = ((FastSparseSet)o).getData(); + IntArray shortdata = data; if (data.length() > longdata.length()) { shortdata = longdata; @@ -294,7 +297,7 @@ public boolean equals(Object o) { public int getCardinality() { boolean found = false; - ArrayHolder intdata = data; + IntArray intdata = data; for (int i = intdata.length() - 1; i >= 0; i--) { int block = intdata.get(i); @@ -326,7 +329,7 @@ public Iterator iterator() { public Set toPlainSet() { HashSet set = new HashSet<>(); - ArrayHolder intdata = data; + IntArray intdata = data; int size = data.length() * 32; if (size > colValuesInternal.size()) { @@ -349,11 +352,11 @@ public String toString() { return toPlainSet().toString(); } - private ArrayHolder getData() { + private IntArray getData() { return data; } - private ArrayHolder getNext() { + private IntArray getNext() { return next; } @@ -364,8 +367,8 @@ private FastSparseSetFactory getFactory() { public static final class FastSparseSetIterator implements Iterator { private final PackedMap colValuesInternal; - private final ArrayHolder data; - private final ArrayHolder next; + private final IntArray data; + private final IntArray next; private final int size; private int pointer = -1; @@ -441,14 +444,22 @@ public void remove() { } - private static class ArrayHolder { + public static final class IntArray { private ArrayTower tower = ArrayTower.None.INSTANCE; private int size; - public ArrayHolder(int size) { + public IntArray(int size) { this.size = size; } + public void setNone() { + tower = ArrayTower.None.INSTANCE; + } + + public String str() { + return tower.toString(); + } + public int get(int index) { return tower.get(index); } @@ -457,29 +468,60 @@ public void set(int index, int value) { if (!tower.canSet(index, value)) { ArrayTower last = tower; if (tower instanceof ArrayTower.None) { - tower = new ArrayTower.Single(index, value); + if (index == 0 && value == 1) { + tower = new ArrayTower.Ladder(); + } else { + tower = new ArrayTower.Single(index, value); + } } else if (tower instanceof ArrayTower.Single single) { if (single.value == value) { // Same value with multiple indices, use bitset - BitSet bits = new BitSet(); - bits.set(single.index); - tower = new ArrayTower.Bits(value, bits); +// BitSet bits = new BitSet(); +// bits.set(single.index); +// tower = new ArrayTower.Bits(value, bits); + + // range + tower = new ArrayTower.Range(value, single.index, single.index); } else { // Different values, fall all the way down to array - int[] ints = new int[size]; - ints[single.index] = single.value; - tower = new ArrayTower.Array(ints); + if (index == single.index || single.value == 0) { + // Size is one, just replace the value in single + tower = new ArrayTower.Single(index, value); + } else { + int[] ints = new int[size]; + ints[single.index] = single.value; + tower = new ArrayTower.Array(ints, 1); + } } - } else if (tower instanceof ArrayTower.Bits bits) { + } +// else if (tower instanceof ArrayTower.Bits bits) { +// int[] ints = new int[size]; +// bits.promote(ints); +// tower = new ArrayTower.Array(ints, bits.set); +// } + else if (tower instanceof ArrayTower.Ladder ladder) { + int[] ints = new int[size]; + ladder.promote(ints); + tower = new ArrayTower.Array(ints, ladder.size + 1); + } else if (tower instanceof ArrayTower.Range range) { int[] ints = new int[size]; - bits.promote(ints); - tower = new ArrayTower.Array(ints); + range.promote(ints); + tower = new ArrayTower.Array(ints, (range.end - range.start) + 1); } ValidationHelper.validateTrue(last != tower, "must have changed"); } tower.set(index, value); + +// if (this.tower instanceof ArrayTower.Bits bits && bits.set == 0) { +// this.tower = ArrayTower.None.INSTANCE; +// } else + if (this.tower instanceof ArrayTower.Array ary) { + if (ary.set == 0) { + this.tower = ArrayTower.None.INSTANCE; + } + } } public void resize(int newSize) { @@ -487,13 +529,29 @@ public void resize(int newSize) { size = newSize; if (tower instanceof ArrayTower.Array ary) { - tower = new ArrayTower.Array(Arrays.copyOf(ary.ary, newSize)); + tower = new ArrayTower.Array(Arrays.copyOf(ary.ary, newSize), ary.set); } } } - public ArrayHolder copy() { - ArrayHolder next = new ArrayHolder(size); + public int cardApprox() { + if (this.tower instanceof ArrayTower.None) { + return 0; + } else if (this.tower instanceof ArrayTower.Single) { + return 1; + } else if (this.tower instanceof ArrayTower.Bits bits) { + return Math.min(bits.set, 2); + } else if (this.tower instanceof ArrayTower.Ladder ladder) { + return Math.min(ladder.size + 1, 2); + } else if (this.tower instanceof ArrayTower.Array array) { + return Math.min(array.set, 2); + } + + throw new IllegalStateException("Illegal state!"); + } + + public IntArray copy() { + IntArray next = new IntArray(size); next.tower = tower.copy(); return next; @@ -519,6 +577,12 @@ default void set(int i, int v) { ArrayTower copy(); + default void promote(int[] ary) { + for (int i = 0; i < ary.length; i++) { + ary[i] = get(i); + } + } + record None() implements ArrayTower { public static final None INSTANCE = new None(); @@ -556,7 +620,53 @@ public ArrayTower copy() { } } - record Bits(int value, BitSet index) implements ArrayTower { + final class Ladder implements ArrayTower { + private int size = -1; + + @Override + public int get(int i) { + return i <= size ? i + 1 : 0; + } + + @Override + public void set(int i, int v) { + // Increase ladder size + if (i == size + 1) { + if (v == size + 2) { + size++; + } else if (v == 0) { + size--; + } else { + ValidationHelper.assertTrue(false, "impossible case"); + } + } + // else already in ladder, no change + } + + @Override + public boolean canSet(int i, int v) { + return i == size + 1 && (v == size + 2 || v == 0) // new in ladder + || i <= size && i + 1 == v // already in ladder + ; + } + + @Override + public ArrayTower copy() { + Ladder ladder = new Ladder(); + ladder.size = size; + return ladder; + } + } + + final class Bits implements ArrayTower { + private final int value; + private final BitSet index; + private int set = 0; + + private Bits(int value, BitSet index) { + this.value = value; + this.index = index; + } @Override public int get(int i) { @@ -566,7 +676,15 @@ public int get(int i) { @Override public void set(int i, int v) { ValidationHelper.assertTrue(v == value || v == 0, "must be"); + int old = index.get(i) ? value : 0; + index.set(i, v == value); + + if (old == 0 && v != 0) { + set++; + } else if (old != 0 && v == 0) { + set--; + } } @Override @@ -576,17 +694,83 @@ public boolean canSet(int i, int v) { @Override public ArrayTower copy() { - return new ArrayTower.Bits(value, (BitSet) index.clone()); + Bits bits = new Bits(value, (BitSet) index.clone()); + bits.set = set; + return bits; } + } - public void promote(int[] ary) { - for (int i = 0; i < ary.length; i++) { - ary[i] = get(i); + final class Range implements ArrayTower { + private final int value; + private int start; + private int end; + + public Range(int value, int start, int end) { + this.value = value; + this.start = start; + this.end = end; + } + + @Override + public int get(int i) { + return i >= start && i <= end ? value : 0; + } + + @Override + public void set(int i, int v) { + if (v == 0) { + // contract range + if (i == start) { + start++; + } else { + end--; + } + } else { + // expand range + if (i == start - 1) { + start--; + } else { + end++; + } + } + } + + @Override + public boolean canSet(int i, int v) { + // TODO: extract common behavior? + if (v == value) { + // expand range + if (i == start - 1) { + return true; + } else if (i == end + 1) { + return true; + } + } else if (v == 0) { + // contract range + if (i == start) { + return true; + } else if (i == end) { + return true; + } } + + return false; + } + + @Override + public ArrayTower copy() { + return new Range(value, start, end); } } - record Array(int[] ary) implements ArrayTower { + final class Array implements ArrayTower { + private final int[] ary; + private int set; + + private Array(int[] ary, int set) { + this.ary = ary; + this.set = set; + } @Override public int get(int i) { @@ -595,7 +779,14 @@ public int get(int i) { @Override public void set(int i, int v) { + int old = ary[i]; ary[i] = v; + + if (old == 0 && v != 0) { + set++; + } else if (old != 0 && v == 0) { + set--; + } } @Override @@ -605,7 +796,7 @@ public boolean canSet(int i, int v) { @Override public ArrayTower copy() { - return new ArrayTower.Array(Arrays.copyOf(ary, ary.length)); + return new ArrayTower.Array(Arrays.copyOf(ary, ary.length), set); } } } diff --git a/src/org/jetbrains/java/decompiler/util/collections/SFormsFastMapDirect.java b/src/org/jetbrains/java/decompiler/util/collections/SFormsFastMapDirect.java index 1136873e49..6b28e5bd3a 100644 --- a/src/org/jetbrains/java/decompiler/util/collections/SFormsFastMapDirect.java +++ b/src/org/jetbrains/java/decompiler/util/collections/SFormsFastMapDirect.java @@ -1,11 +1,13 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.util.collections; +import org.jetbrains.java.decompiler.modules.decompiler.ValidationHelper; import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.collections.FastSparseSetFactory.FastSparseSet; +import org.jetbrains.java.decompiler.util.collections.FastSparseSetFactory.IntArray; import java.util.ArrayList; import java.util.Arrays; @@ -20,9 +22,9 @@ public class SFormsFastMapDirect { private int size; private final FastSparseSetFactory factory; - @SuppressWarnings("unchecked") private final FastSparseSet[][] elements = new FastSparseSet[3][]; + private final FastSparseSetArray[] elements = new FastSparseSetArray[3]; - private final int[][] next = new int[3][]; + private final IntArray[] next = new IntArray[3]; public SFormsFastMapDirect(FastSparseSetFactory factory) { this(true, factory); @@ -32,9 +34,8 @@ private SFormsFastMapDirect(boolean initialize, FastSparseSetFactory fa this.factory = factory; if (initialize) { for (int i = 2; i >= 0; i--) { - @SuppressWarnings("unchecked") FastSparseSet[] empty = FastSparseSet.EMPTY_ARRAY; - elements[i] = empty; - next[i] = InterpreterUtil.EMPTY_INT_ARRAY; + elements[i] = new FastSparseSetArray(0); + next[i] = new FastSparseSetFactory.IntArray(0); } } } @@ -44,35 +45,22 @@ public SFormsFastMapDirect getCopy() { SFormsFastMapDirect map = new SFormsFastMapDirect(false, factory); map.size = size; - FastSparseSet[][] mapelements = map.elements; - int[][] mapnext = map.next; + FastSparseSetArray[] mapelements = map.elements; + IntArray[] mapnext = map.next; for (int i = 2; i >= 0; i--) { - FastSparseSet[] arr = elements[i]; - int length = arr.length; + FastSparseSetArray arr = elements[i]; + int length = arr.length(); if (length > 0) { - int[] arrnext = next[i]; + IntArray arrnext = next[i]; - @SuppressWarnings("unchecked") FastSparseSet[] arrnew = new FastSparseSet[length]; - int[] arrnextnew = Arrays.copyOf(arrnext, length); + mapelements[i] = arr.copy(); + mapnext[i] = arrnext.copy(); - mapelements[i] = arrnew; - mapnext[i] = arrnextnew; - - int pointer = 0; - do { - FastSparseSet set = arr[pointer]; - if (set != null) { - arrnew[pointer] = set.getCopy(); - } - - pointer = arrnext[pointer]; - } - while (pointer != 0); } else { - mapelements[i] = FastSparseSet.EMPTY_ARRAY; - mapnext[i] = InterpreterUtil.EMPTY_INT_ARRAY; + mapelements[i] = new FastSparseSetArray(0); + mapnext[i] = new IntArray(0); } } @@ -96,31 +84,23 @@ public void remove(int key) { } public void removeAllFields() { - FastSparseSet[] arr = elements[2]; - int[] arrnext = next[2]; + FastSparseSetArray arr = elements[2]; + IntArray arrnext = next[2]; - for (int i = arr.length - 1; i >= 0; i--) { - FastSparseSet val = arr[i]; - if (val != null) { - arr[i] = null; - size--; - } - arrnext[i] = 0; - } + size -= arr.cardinality(); + + arrnext.setNone(); + arr.setNone(); } public void removeAllStacks() { - FastSparseSet[] arr = elements[1]; - int[] arrnext = next[1]; + FastSparseSetArray arr = elements[1]; + IntArray arrnext = next[1]; - for (int i = arr.length - 1; i >= 0; i--) { - FastSparseSet val = arr[i]; - if (val != null) { - arr[i] = null; - size--; - } - arrnext[i] = 0; - } + size -= arr.cardinality(); + + arrnext.setNone(); + arr.setNone(); } private void putInternal(final int key, final FastSparseSet value, boolean remove) { @@ -134,33 +114,36 @@ private void putInternal(final int key, final FastSparseSet value, bool ikey -= VarExprent.STACK_BASE; } - FastSparseSet[] arr = elements[index]; - if (ikey >= arr.length) { + FastSparseSetArray arr = elements[index]; + if (ikey >= arr.length()) { if (remove) { return; } else { - arr = ensureCapacity(index, ikey + 1, false); + ensureCapacity(index, ikey + 1, false); } } - FastSparseSet oldval = arr[ikey]; - arr[ikey] = value; + FastSparseSet oldval = arr.get(ikey); + arr.set(ikey, value); - int[] arrnext = next[index]; + IntArray arrnext = next[index]; if (oldval == null && value != null) { size++; - changeNext(arrnext, ikey, arrnext[ikey], ikey); + changeNext(arrnext, ikey, arrnext.get(ikey), ikey); } else if (oldval != null && value == null) { size--; - changeNext(arrnext, ikey, ikey, arrnext[ikey]); + changeNext(arrnext, ikey, ikey, arrnext.get(ikey)); } } - private static void changeNext(int[] arrnext, int key, int oldnext, int newnext) { + private static void changeNext(IntArray arrnext, int key, int oldnext, int newnext) { + if (oldnext == newnext) { + return; + } for (int i = key - 1; i >= 0; i--) { - if (arrnext[i] == oldnext) { - arrnext[i] = newnext; + if (arrnext.get(i) == oldnext) { + arrnext.set(i, newnext); } else { break; } @@ -182,10 +165,10 @@ public FastSparseSet get(int key) { key -= VarExprent.STACK_BASE; } - FastSparseSet[] arr = elements[index]; + FastSparseSetArray arr = elements[index]; - if (key < arr.length) { - return arr[key]; + if (key < arr.length()) { + return arr.get(key); } return null; @@ -194,36 +177,36 @@ public FastSparseSet get(int key) { public void complement(SFormsFastMapDirect map) { for (int i = 2; i >= 0; i--) { - FastSparseSet[] lstOwn = elements[i]; + FastSparseSetArray lstOwn = elements[i]; - if (lstOwn.length == 0) { + if (lstOwn.length() == 0) { continue; } - FastSparseSet[] lstExtern = map.elements[i]; - int[] arrnext = next[i]; + FastSparseSetArray lstExtern = map.elements[i]; + IntArray arrnext = next[i]; int pointer = 0; do { - FastSparseSet first = lstOwn[pointer]; + FastSparseSet first = lstOwn.get(pointer); if (first != null) { - if (pointer >= lstExtern.length) { + if (pointer >= lstExtern.length()) { break; } - FastSparseSet second = lstExtern[pointer]; + FastSparseSet second = lstExtern.get(pointer); if (second != null) { first.complement(second); if (first.isEmpty()) { - lstOwn[pointer] = null; + lstOwn.set(pointer, null); size--; - changeNext(arrnext, pointer, pointer, arrnext[pointer]); + changeNext(arrnext, pointer, pointer, arrnext.get(pointer)); } } } - pointer = arrnext[pointer]; + pointer = arrnext.get(pointer); } while (pointer != 0); } @@ -232,23 +215,23 @@ public void complement(SFormsFastMapDirect map) { public void intersection(SFormsFastMapDirect map) { for (int i = 2; i >= 0; i--) { - FastSparseSet[] lstOwn = elements[i]; + FastSparseSetArray lstOwn = elements[i]; - if (lstOwn.length == 0) { + if (lstOwn.length() == 0) { continue; } - FastSparseSet[] lstExtern = map.elements[i]; - int[] arrnext = next[i]; + FastSparseSetArray lstExtern = map.elements[i]; + IntArray arrnext = next[i]; int pointer = 0; do { - FastSparseSet first = lstOwn[pointer]; + FastSparseSet first = lstOwn.get(pointer); if (first != null) { FastSparseSet second = null; - if (pointer < lstExtern.length) { - second = lstExtern[pointer]; + if (pointer < lstExtern.length()) { + second = lstExtern.get(pointer); } if (second != null) { @@ -256,13 +239,13 @@ public void intersection(SFormsFastMapDirect map) { } if (second == null || first.isEmpty()) { - lstOwn[pointer] = null; + lstOwn.set(pointer, null); size--; - changeNext(arrnext, pointer, pointer, arrnext[pointer]); + changeNext(arrnext, pointer, pointer, arrnext.get(pointer)); } } - pointer = arrnext[pointer]; + pointer = arrnext.get(pointer); } while (pointer != 0); } @@ -271,39 +254,40 @@ public void intersection(SFormsFastMapDirect map) { public void union(SFormsFastMapDirect map) { for (int i = 2; i >= 0; i--) { - FastSparseSet[] lstExtern = map.elements[i]; + FastSparseSetArray lstExtern = map.elements[i]; - if (lstExtern.length == 0) { + if (lstExtern.length() == 0) { continue; } - FastSparseSet[] lstOwn = elements[i]; - int[] arrnext = next[i]; - int[] arrnextExtern = map.next[i]; + FastSparseSetArray lstOwn = elements[i]; + + IntArray arrnext = next[i]; + IntArray arrnextExtern = map.next[i]; int pointer = 0; do { - if (pointer >= lstOwn.length) { - lstOwn = ensureCapacity(i, lstExtern.length, true); + if (pointer >= lstOwn.length()) { + ensureCapacity(i, lstExtern.length(), true); arrnext = next[i]; } - FastSparseSet second = lstExtern[pointer]; + FastSparseSet second = lstExtern.get(pointer); if (second != null) { - FastSparseSet first = lstOwn[pointer]; + FastSparseSet first = lstOwn.get(pointer); if (first == null) { - lstOwn[pointer] = second.getCopy(); + lstOwn.set(pointer, second.getCopy()); size++; - changeNext(arrnext, pointer, arrnext[pointer], pointer); + changeNext(arrnext, pointer, arrnext.get(pointer), pointer); } else { first.union(second); } } - pointer = arrnextExtern[pointer]; + pointer = arrnextExtern.get(pointer); } while (pointer != 0); } @@ -338,7 +322,8 @@ public List>> entryList() { for (int i = 2; i >= 0; i--) { int ikey = 0; - for (final FastSparseSet ent : elements[i]) { + for (int j = 0; j < elements[i].length(); j++) { + final FastSparseSet ent = elements[i].get(j); if (ent != null) { final int key = i == 0 ? ikey : (i == 1 ? ikey + VarExprent.STACK_BASE : -ikey); @@ -368,29 +353,21 @@ public FastSparseSet setValue(FastSparseSet newvalue) { return list; } - private FastSparseSet[] ensureCapacity(int index, int size, boolean exact) { + private void ensureCapacity(int index, int size, boolean exact) { - FastSparseSet[] arr = elements[index]; - int[] arrnext = next[index]; + FastSparseSetArray arr = elements[index]; + IntArray arrnext = next[index]; int minsize = size; if (!exact) { - minsize = 2 * arr.length / 3 + 1; + minsize = 2 * arr.length() / 3 + 1; if (size > minsize) { minsize = size; } } - @SuppressWarnings("unchecked") FastSparseSet[] arrnew = new FastSparseSet[minsize]; - System.arraycopy(arr, 0, arrnew, 0, arr.length); - - int[] arrnextnew = new int[minsize]; - System.arraycopy(arrnext, 0, arrnextnew, 0, arrnext.length); - - elements[index] = arrnew; - next[index] = arrnextnew; - - return arrnew; + arr.resize(minsize); + arrnext.resize(minsize); } public void setCurrentVar(int var, int version) { @@ -414,4 +391,192 @@ public void setCurrentVar(VarVersionPair varExprent) { public FastSparseSet get(VarExprent varExprent) { return this.get(varExprent.getIndex()); } + + private static class FastSparseSetArray { + private ArrayTower tower = ArrayTower.None.INSTANCE; + private int size; + + public FastSparseSetArray(int size) { + this.size = size; + } + + public FastSparseSet get(int index) { + return tower.get(index); + } + + public void setNone() { + tower = ArrayTower.None.INSTANCE; + } + + public void set(int index, FastSparseSet value) { + if (!tower.canSet(index, value)) { + ArrayTower last = tower; + if (tower instanceof ArrayTower.None) { + tower = new ArrayTower.Single(index, value); + } else if (tower instanceof ArrayTower.Single single) { + // Different values, fall all the way down to array + if (index == single.index || single.value == null) { + // Size is one, just replace the value in single + tower = new ArrayTower.Single(index, value); + } else { + FastSparseSet[] ints = new FastSparseSet[size]; + ints[single.index] = single.value; + tower = new ArrayTower.Array(ints, 1); + } + } + + ValidationHelper.validateTrue(last != tower, "must have changed"); + } + + tower.set(index, value); + + if (tower instanceof ArrayTower.Array ary && ary.set == 0) { + tower = ArrayTower.None.INSTANCE; + } + } + + public void resize(int newSize) { + if (newSize > size) { + size = newSize; + + if (tower instanceof ArrayTower.Array ary) { + tower = new ArrayTower.Array(Arrays.copyOf(ary.ary, newSize), ary.set); + } + } + } + + public int cardinality() { + if (this.tower instanceof ArrayTower.None) { + return 0; + } else if (this.tower instanceof ArrayTower.Single) { + return 1; + } else if (this.tower instanceof ArrayTower.Array ary) { + return ary.set; + } + + throw new IllegalStateException("illegal state!"); + } + + public FastSparseSetArray copy() { + FastSparseSetArray next = new FastSparseSetArray(size); + next.tower = tower.copy(); + + return next; + } + + public int length() { + return size; + } + } + + private sealed interface ArrayTower { + FastSparseSet get(int i); + + default void set(int i, FastSparseSet v) { + if (canSet(i, v)) { + return; + } + + throw new IllegalStateException("Can't set " + i + " " + v); + } + + boolean canSet(int i, FastSparseSet v); + + ArrayTower copy(); + + record None() implements ArrayTower { + public static final None INSTANCE = new None(); + + @Override + public FastSparseSet get(int i) { + return null; + } + + @Override + public boolean canSet(int i, FastSparseSet v) { + return v == null; + } + + @Override + public ArrayTower copy() { + return INSTANCE; + } + + @Override + public String toString() { + return "Nil"; + } + } + + record Single(int index, FastSparseSet value) implements ArrayTower { + + @Override + public FastSparseSet get(int i) { + return i == index ? value : null; + } + + @Override + public boolean canSet(int i, FastSparseSet v) { + return (i == index && v == value) || (i != index && v == null); + } + + @Override + public ArrayTower copy() { + return new Single(index, value.getCopy()); + } + + @Override + public String toString() { + return value + "@" + index; + } + } + + final class Array implements ArrayTower { + private final FastSparseSet[] ary; + private int set; + + Array(FastSparseSet[] ary, int set) { + this.ary = ary; + this.set = set; + } + + @Override + public FastSparseSet get(int i) { + return ary[i]; + } + + @Override + public void set(int i, FastSparseSet v) { + FastSparseSet old = ary[i]; + ary[i] = v; + + if (old == null && v != null) { + set++; + } else if (old != null && v == null) { + set--; + } + } + + @Override + public boolean canSet(int i, FastSparseSet v) { + return true; + } + + @Override + public ArrayTower copy() { + FastSparseSet[] cpy = Arrays.copyOf(ary, ary.length); + for (int i = 0; i < cpy.length; i++) { + FastSparseSet v = cpy[i]; + cpy[i] = v == null ? null : v.getCopy(); + } + + return new ArrayTower.Array(cpy, set); + } + + @Override + public String toString() { + return Arrays.toString(ary); + } + } + } } \ No newline at end of file From e1713ffd70e8aab5590f28a7cc54c0b312f7d3f5 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 8 Nov 2025 16:08:19 -0500 Subject: [PATCH 25/29] Fix improper promotion to range --- .../collections/FastSparseSetFactory.java | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java index bf53969496..edfdfd0961 100644 --- a/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java +++ b/src/org/jetbrains/java/decompiler/util/collections/FastSparseSetFactory.java @@ -474,7 +474,7 @@ public void set(int index, int value) { tower = new ArrayTower.Single(index, value); } } else if (tower instanceof ArrayTower.Single single) { - if (single.value == value) { + if (single.value == value && (single.index == index + 1 || single.index == index - 1)) { // Same value with multiple indices, use bitset // BitSet bits = new BitSet(); // bits.set(single.index); @@ -517,10 +517,16 @@ else if (tower instanceof ArrayTower.Ladder ladder) { // if (this.tower instanceof ArrayTower.Bits bits && bits.set == 0) { // this.tower = ArrayTower.None.INSTANCE; // } else - if (this.tower instanceof ArrayTower.Array ary) { + if (this.tower instanceof ArrayTower.Array ary) { if (ary.set == 0) { this.tower = ArrayTower.None.INSTANCE; } + } else if (this.tower instanceof ArrayTower.Range range) { + if (range.end < range.start) { + this.tower = ArrayTower.None.INSTANCE; + } else if (range.end == range.start) { + this.tower = new ArrayTower.Single(range.start, range.value); + } } } @@ -600,6 +606,11 @@ public boolean canSet(int i, int v) { public ArrayTower copy() { return INSTANCE; } + + @Override + public String toString() { + return "Nil"; + } } record Single(int index, int value) implements ArrayTower { @@ -618,6 +629,11 @@ public boolean canSet(int i, int v) { public ArrayTower copy() { return new Single(index, value); } + + @Override + public String toString() { + return value + "@" + index; + } } final class Ladder implements ArrayTower { @@ -656,6 +672,18 @@ public ArrayTower copy() { ladder.size = size; return ladder; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < size; i++) { + if (i > 0) { + sb.append(","); + } + sb.append(i + 1); + } + return "Ladder:" + sb.toString(); + } } final class Bits implements ArrayTower { @@ -698,6 +726,11 @@ public ArrayTower copy() { bits.set = set; return bits; } + + @Override + public String toString() { + return value + "@" + index; + } } final class Range implements ArrayTower { @@ -761,6 +794,11 @@ public boolean canSet(int i, int v) { public ArrayTower copy() { return new Range(value, start, end); } + + @Override + public String toString() { + return value + "@[" + start + "-" + end + "]"; + } } final class Array implements ArrayTower { @@ -798,6 +836,11 @@ public boolean canSet(int i, int v) { public ArrayTower copy() { return new ArrayTower.Array(Arrays.copyOf(ary, ary.length), set); } + + @Override + public String toString() { + return Arrays.toString(ary); + } } } } From 6dd58538097a4725d78ab2d8cd1687e3c86b6699 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 8 Nov 2025 17:17:25 -0500 Subject: [PATCH 26/29] Use more compact memory representation for bytecode offset --- .../kotlin/expr/KFunctionExprent.java | 4 +- .../vineflower/kotlin/expr/KVarExprent.java | 2 +- .../main/decompiler/ConsoleDecompiler.java | 3 +- .../decompiler/ConcatenationHelper.java | 2 +- .../modules/decompiler/ExprProcessor.java | 8 +- .../decompiler/SimplifyExprentsHelper.java | 2 +- .../decompiler/exps/AnnotationExprent.java | 2 +- .../modules/decompiler/exps/ArrayExprent.java | 4 +- .../decompiler/exps/AssertExprent.java | 3 +- .../decompiler/exps/AssignmentExprent.java | 6 +- .../modules/decompiler/exps/ConstExprent.java | 20 +-- .../modules/decompiler/exps/ExitExprent.java | 4 +- .../modules/decompiler/exps/Exprent.java | 143 +++++++++++++++++- .../modules/decompiler/exps/FieldExprent.java | 8 +- .../decompiler/exps/FunctionExprent.java | 8 +- .../modules/decompiler/exps/IfExprent.java | 6 +- .../decompiler/exps/InvocationExprent.java | 4 +- .../decompiler/exps/MonitorExprent.java | 4 +- .../modules/decompiler/exps/NewExprent.java | 6 +- .../decompiler/exps/PatternExprent.java | 2 +- .../decompiler/exps/SwitchExprent.java | 2 +- .../decompiler/exps/SwitchHeadExprent.java | 4 +- .../modules/decompiler/exps/VarExprent.java | 4 +- .../modules/decompiler/exps/YieldExprent.java | 2 +- .../decompiler/stats/CatchStatement.java | 2 +- .../decompiler/stats/DummyExitStatement.java | 10 +- .../modules/decompiler/stats/Statement.java | 6 +- .../decompiler/vars/VarTypeProcessor.java | 3 + .../StructLocalVariableTableAttribute.java | 5 +- .../java/decompiler/struct/gen/VarType.java | 4 +- .../java/decompiler/util/TextBuffer.java | 15 +- 31 files changed, 219 insertions(+), 79 deletions(-) diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java index 063b2f73e6..7bf371609d 100644 --- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java +++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KFunctionExprent.java @@ -30,13 +30,13 @@ public enum KFunctionType implements Typed { STR_TEMPLATE } - public KFunctionExprent(KFunctionType funcType, List operands, BitSet bytecodeOffsets) { + public KFunctionExprent(KFunctionType funcType, List operands, BytecodeRange bytecodeOffsets) { this(FunctionType.OTHER, operands, bytecodeOffsets); this.kType = funcType; } - public KFunctionExprent(FunctionType funcType, List operands, BitSet bytecodeOffsets) { + public KFunctionExprent(FunctionType funcType, List operands, BytecodeRange bytecodeOffsets) { super(funcType, new ArrayList<>(KUtils.replaceExprents(operands)), bytecodeOffsets); } diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KVarExprent.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KVarExprent.java index fd507b6815..34670529e6 100644 --- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KVarExprent.java +++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/expr/KVarExprent.java @@ -21,7 +21,7 @@ public enum DeclarationType { private DeclarationType declarationType; - public KVarExprent(int index, VarType varType, VarProcessor processor, BitSet bytecode) { + public KVarExprent(int index, VarType varType, VarProcessor processor, BytecodeRange bytecode) { super(index, varType, processor, bytecode); } diff --git a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java index 3af2a704d3..920100fb14 100644 --- a/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java +++ b/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java @@ -57,8 +57,7 @@ else if (args.length > x+1) { System.out.println("error: Failed to read config file '" + path + "'"); throw new RuntimeException(e); } - } - else { + } else { params.add(args[x]); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java index 15021b3d93..036c99008f 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java @@ -180,7 +180,7 @@ else if (found == 2) { return createConcatExprent(lstOperands, expr.bytecode); } - private static Exprent createConcatExprent(List lstOperands, BitSet bytecode) { + private static Exprent createConcatExprent(List lstOperands, Exprent.BytecodeRange bytecode) { // build exprent to return Exprent func = lstOperands.get(0); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index f392856ace..491758ecbb 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -216,10 +216,10 @@ public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, Stru Instruction instr = seq.getInstr(i); int bytecode_offset = instr.startOffset; - BitSet bytecode_offsets = null; + Exprent.BytecodeRange bytecode_offsets = null; if (bytecode_offset >= 0) { - bytecode_offsets = new BitSet(); - bytecode_offsets.set(bytecode_offset, bytecode_offset + instr.length); + bytecode_offsets = new Exprent.BytecodeRange(new Exprent.BytecodeSet.Range(bytecode_offset, bytecode_offset + instr.length - 1)); +// bytecode_offsets.set(); } switch (instr.opcode) { @@ -312,7 +312,7 @@ else if (cn instanceof LinkConstant) { Exprent expr = stack.pop(); int varindex = instr.operand(0); if (bytecode_offsets != null) { //TODO: Figure out why this nulls in some cases - bytecode_offsets.set(bytecode_offset, bytecode_offset + instr.length); + bytecode_offsets.or(new Exprent.BytecodeRange(new Exprent.BytecodeSet.Range(bytecode_offset, bytecode_offset + instr.length - 1))); } varExprent = new VarExprent(varindex, varTypes[instr.opcode - opc_istore], varProcessor, bytecode_offsets); varExprent.setBackingInstr(instr); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java index c414ccbd96..67ea14e46c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java @@ -995,7 +995,7 @@ private static Exprent isSimpleConstructorInvocation(Exprent exprent) { private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) { if (stat instanceof IfStatement statement && stat.getExprents() == null) { Exprent ifHeadExpr = statement.getHeadexprent(); - BitSet ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode); + Exprent.BytecodeRange ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode); if (statement.iftype == IfStatement.IFTYPE_IFELSE) { Statement ifStatement = statement.getIfstat(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java index 15797f5475..d3b34ac4b1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java @@ -152,7 +152,7 @@ public void setDidWriteAlready(boolean didWriteAlready) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, parValues); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java index 5126342b25..e10d1be63c 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java @@ -15,7 +15,7 @@ public class ArrayExprent extends Exprent { private Exprent index; private final VarType hardType; - public ArrayExprent(Exprent array, Exprent index, VarType hardType, BitSet bytecodeOffsets) { + public ArrayExprent(Exprent array, Exprent index, VarType hardType, BytecodeRange bytecodeOffsets) { super(Type.ARRAY); this.array = array; this.index = index; @@ -130,7 +130,7 @@ public Exprent getIndex() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, array); measureBytecode(values, index); measureBytecode(values); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java index 13755bd3ef..cd3bf9eb76 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java @@ -71,8 +71,7 @@ public CheckTypesResult checkExprTypeBounds() { return super.checkExprTypeBounds(); } - @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, parameters); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java index c454010c85..808efe8b54 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java @@ -33,7 +33,7 @@ public class AssignmentExprent extends Exprent { private Exprent right; private FunctionExprent.FunctionType condType = null; - public AssignmentExprent(Exprent left, Exprent right, BitSet bytecodeOffsets) { + public AssignmentExprent(Exprent left, Exprent right, BytecodeRange bytecodeOffsets) { super(Type.ASSIGNMENT); this.left = left; this.right = right; @@ -41,7 +41,7 @@ public AssignmentExprent(Exprent left, Exprent right, BitSet bytecodeOffsets) { addBytecodeOffsets(bytecodeOffsets); } - public AssignmentExprent(Exprent left, Exprent right, FunctionExprent.FunctionType condType, BitSet bytecodeOffsets) { + public AssignmentExprent(Exprent left, Exprent right, FunctionExprent.FunctionType condType, BytecodeRange bytecodeOffsets) { this(left, right, bytecodeOffsets); this.condType = condType; } @@ -286,7 +286,7 @@ public boolean equals(Object o) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, left); measureBytecode(values, right); measureBytecode(values); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java index e2e050793e..e2269bd1c0 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java @@ -21,8 +21,8 @@ public class ConstExprent extends Exprent { private static final Map CHAR_ESCAPES = new HashMap<>(); - private static final Map> UNINLINED_DOUBLES = new HashMap<>(); - private static final Map> UNINLINED_FLOATS = new HashMap<>(); + private static final Map> UNINLINED_DOUBLES = new HashMap<>(); + private static final Map> UNINLINED_FLOATS = new HashMap<>(); private static final Set NO_PAREN_VALUES = new HashSet<>(); static { @@ -135,20 +135,20 @@ public class ConstExprent extends Exprent { private final boolean boolPermitted; private boolean wasCondy = false; - public ConstExprent(int val, boolean boolPermitted, BitSet bytecodeOffsets) { + public ConstExprent(int val, boolean boolPermitted, BytecodeRange bytecodeOffsets) { this(guessType(val, boolPermitted), val, boolPermitted, bytecodeOffsets); } - public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets) { + public ConstExprent(VarType constType, Object value, BytecodeRange bytecodeOffsets) { this(constType, value, false, bytecodeOffsets); } - public ConstExprent(VarType constType, Object value, BitSet bytecodeOffsets, boolean wasCondy) { + public ConstExprent(VarType constType, Object value, BytecodeRange bytecodeOffsets, boolean wasCondy) { this(constType, value, false, bytecodeOffsets); this.wasCondy = wasCondy; } - protected ConstExprent(VarType constType, Object value, boolean boolPermitted, BitSet bytecodeOffsets) { + protected ConstExprent(VarType constType, Object value, boolean boolPermitted, BytecodeRange bytecodeOffsets) { super(Type.CONST); this.constType = constType; this.value = value; @@ -394,15 +394,15 @@ public int getPrecedence() { return super.getPrecedence(); } - private static TextBuffer getPiDouble(BitSet bytecode) { + private static TextBuffer getPiDouble(BytecodeRange bytecode) { return getDouble(bytecode, "PI", "java/lang/Math"); } - private static TextBuffer getDouble(BitSet bytecode, String name, String className) { + private static TextBuffer getDouble(BytecodeRange bytecode, String name, String className) { return new FieldExprent(name, className, true, null, FieldDescriptor.DOUBLE_DESCRIPTOR, bytecode).toJava(0); } - private static TextBuffer getFloat(BitSet bytecode, String name, String className) { + private static TextBuffer getFloat(BytecodeRange bytecode, String name, String className) { return new FieldExprent(name, className, true, null, FieldDescriptor.FLOAT_DESCRIPTOR, bytecode).toJava(0); } @@ -651,7 +651,7 @@ public boolean isBoolPermitted() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java index 23701a4f71..548c5615a7 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java @@ -30,7 +30,7 @@ public enum Type { private final VarType retType; private final MethodDescriptor methodDescriptor; - public ExitExprent(Type exitType, Exprent value, VarType retType, BitSet bytecodeOffsets, MethodDescriptor methodDescriptor) { + public ExitExprent(Type exitType, Exprent value, VarType retType, BytecodeRange bytecodeOffsets, MethodDescriptor methodDescriptor) { super(Exprent.Type.EXIT); this.exitType = exitType; this.value = value; @@ -155,7 +155,7 @@ public MethodDescriptor getMethodDescriptor() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, value); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java index 6b9ff4190c..0256ce9bb2 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java @@ -57,7 +57,7 @@ public enum Type { public final Type type; public final int id; - public BitSet bytecode = null; // offsets of bytecode instructions decompiled to this exprent + public BytecodeRange bytecode = null; // offsets of bytecode instructions decompiled to this exprent protected Exprent(Type type) { this.type = type; @@ -175,29 +175,29 @@ public TextBuffer toJava() { public void replaceExprent(Exprent oldExpr, Exprent newExpr) { } - public void addBytecodeOffsets(BitSet bytecodeOffsets) { + public void addBytecodeOffsets(BytecodeRange bytecodeOffsets) { if (bytecodeOffsets != null) { if (bytecode == null) { - bytecode = new BitSet(); + bytecode = new BytecodeRange(); } bytecode.or(bytecodeOffsets); } } - public abstract void getBytecodeRange(BitSet values); + public abstract void getBytecodeRange(BytecodeRange values); - protected void measureBytecode(BitSet values) { + protected void measureBytecode(BytecodeRange values) { if (bytecode != null && values != null) { values.or(bytecode); } } - protected static void measureBytecode(BitSet values, Exprent exprent) { + protected static void measureBytecode(BytecodeRange values, Exprent exprent) { if (exprent != null) exprent.getBytecodeRange(values); } - protected static void measureBytecode(BitSet values, List list) { + protected static void measureBytecode(BytecodeRange values, List list) { if (list != null && !list.isEmpty()) { for (Exprent e : list) e.getBytecodeRange(values); @@ -368,4 +368,133 @@ public String toString() { return toJava(0).convertToStringAndAllowDataDiscard(); } } + + public static class BytecodeRange { + private BytecodeSet set = new BytecodeSet.Empty(); + + public BytecodeRange() { + + } + + public BytecodeRange(BytecodeSet set) { + this.set = set; + } + + public void or(BytecodeRange range) { +// System.out.print(set + " | " + range.set + " -> "); + this.set = set.or(range.set); + +// System.out.println(set); + } + + public BitSet asBitSet() { + return set.set(); + } + + public int length() { + return asBitSet().length(); + } + } + + public interface BytecodeSet { + + BytecodeSet or(BytecodeSet other); + + BitSet set(); + + class Empty implements BytecodeSet { + + @Override + public BytecodeSet or(BytecodeSet other) { + if (other instanceof Empty) { + return this; + } else if (other instanceof Range r) { + return new Range(r.start, r.end); + } else if (other instanceof Bits b) { + Bits set = new Bits(new BitSet()); + set.or(b); + return set; + } + + throw new IllegalStateException(); + } + + @Override + public BitSet set() { + return new BitSet(); + } + + @Override + public String toString() { + return "Nil"; + } + } + + // Inclusive range + class Range implements BytecodeSet { + public final int start; + public final int end; + + public Range(int start, int end) { + this.start = start; + this.end = end; + } + + @Override + public BytecodeSet or(BytecodeSet other) { + if (other instanceof Empty) { + return this; + } else if (other instanceof Range r) { + if (r.start == start && r.end == end) { + return this; + } if (r.end > end && r.start >= start && r.start <= end + 1) { + return new Range(start, r.end); + } else if (r.start < start && r.end <= end && r.end >= start - 1) { + return new Range(start, r.end); + } + } + + BitSet set = set(); + set.or(other.set()); + + return new Bits(set); + } + + @Override + public BitSet set() { + BitSet set = new BitSet(); + set.set(start, end + 1); + return set; + } + + @Override + public String toString() { + return "[" + start + "-" + end + "]"; + } + } + + class Bits implements BytecodeSet { + private final BitSet set; + + public Bits(BitSet set) { + this.set = set; + } + + @Override + public BytecodeSet or(BytecodeSet other) { + set.or(other.set()); + return this; + } + + @Override + public BitSet set() { + return set; + } + + @Override + public String toString() { + return set.toString(); + } + } + } } \ No newline at end of file diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java index 85c7676a96..8bc1f7af10 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java @@ -40,15 +40,15 @@ public class FieldExprent extends Exprent { private boolean isQualifier = false; private boolean wasCondy = false; - public FieldExprent(LinkConstant cn, Exprent instance, BitSet bytecodeOffsets) { + public FieldExprent(LinkConstant cn, Exprent instance, BytecodeRange bytecodeOffsets) { this(cn.elementname, cn.classname, instance == null, instance, FieldDescriptor.parseDescriptor(cn.descriptor), bytecodeOffsets); } - public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BitSet bytecodeOffsets) { + public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BytecodeRange bytecodeOffsets) { this(name, classname, isStatic, instance, descriptor, bytecodeOffsets, false, false); } - public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BitSet bytecodeOffsets, boolean forceQualified, boolean wasCondy) { + public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor, BytecodeRange bytecodeOffsets, boolean forceQualified, boolean wasCondy) { super(Type.FIELD); this.name = name; this.classname = classname; @@ -284,7 +284,7 @@ public void forceQualified(boolean value) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, instance); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java index 4afbb61674..5890c41a73 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java @@ -149,7 +149,7 @@ public boolean isPostfixPPMM() { private boolean needsCast = true; private boolean disableNewlineGroupCreation = false; - public FunctionExprent(FunctionType funcType, ListStack stack, BitSet bytecodeOffsets) { + public FunctionExprent(FunctionType funcType, ListStack stack, BytecodeRange bytecodeOffsets) { this(funcType, new ArrayList<>(), bytecodeOffsets); if (funcType.arity == 1) { @@ -165,7 +165,7 @@ else if (funcType.arity == 2) { } } - public FunctionExprent(FunctionType funcType, List operands, BitSet bytecodeOffsets) { + public FunctionExprent(FunctionType funcType, List operands, BytecodeRange bytecodeOffsets) { super(Type.FUNCTION); this.funcType = funcType; this.lstOperands = operands; @@ -173,7 +173,7 @@ public FunctionExprent(FunctionType funcType, List operands, BitSet byt addBytecodeOffsets(bytecodeOffsets); } - public FunctionExprent(FunctionType funcType, Exprent operand, BitSet bytecodeOffsets) { + public FunctionExprent(FunctionType funcType, Exprent operand, BytecodeRange bytecodeOffsets) { this(funcType, new ArrayList<>(1), bytecodeOffsets); lstOperands.add(operand); } @@ -870,7 +870,7 @@ public boolean allowNewlineAfterQualifier() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, lstOperands); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java index dd8d555798..9f792d5d69 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java @@ -56,7 +56,7 @@ public Type getNegative() { private Exprent condition; - public IfExprent(Type ifType, ListStack stack, BitSet bytecodeOffsets) { + public IfExprent(Type ifType, ListStack stack, BytecodeRange bytecodeOffsets) { this(null, bytecodeOffsets); if (ifType.ordinal() <= Type.LE.ordinal()) { @@ -69,7 +69,7 @@ else if (ifType.ordinal() <= Type.NONNULL.ordinal()) { condition = ifType.functionType == null ? stack.pop() : new FunctionExprent(ifType.functionType, stack, bytecodeOffsets); } - private IfExprent(Exprent condition, BitSet bytecodeOffsets) { + private IfExprent(Exprent condition, BytecodeRange bytecodeOffsets) { super(Exprent.Type.IF); this.condition = condition; @@ -132,7 +132,7 @@ public void setCondition(Exprent condition) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, condition); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java index af5be5fe4a..adc604861d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java @@ -85,7 +85,7 @@ public InvocationExprent(int opcode, LinkConstant bootstrapMethod, List bootstrapArguments, ListStack stack, - BitSet bytecodeOffsets) { + BytecodeRange bytecodeOffsets) { this(); name = cn.elementname; @@ -1878,7 +1878,7 @@ public void setInvocationInstance() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, lstParameters); measureBytecode(values, instance); measureBytecode(values); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java index 364f809894..f899f15837 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java @@ -21,7 +21,7 @@ public enum Type { private final Type monType; private Exprent value; - public MonitorExprent(Type monType, Exprent value, BitSet bytecodeOffsets) { + public MonitorExprent(Type monType, Exprent value, BytecodeRange bytecodeOffsets) { super(Exprent.Type.MONITOR); this.monType = monType; this.value = value; @@ -91,7 +91,7 @@ public void setRemove(boolean remove) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, value); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java index 09d135c942..4375ec4e53 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -48,11 +48,11 @@ public class NewExprent extends Exprent { private List genericArgs = new ArrayList<>(); private VarType inferredLambdaType = null; - public NewExprent(VarType newType, ListStack stack, int arrayDim, BitSet bytecodeOffsets) { + public NewExprent(VarType newType, ListStack stack, int arrayDim, BytecodeRange bytecodeOffsets) { this(newType, getDimensions(arrayDim, stack), bytecodeOffsets); } - public NewExprent(VarType newType, List lstDims, BitSet bytecodeOffsets) { + public NewExprent(VarType newType, List lstDims, BytecodeRange bytecodeOffsets) { super(Type.NEW); this.newType = newType; this.lstDims = lstDims; @@ -785,7 +785,7 @@ public boolean equals(Object o) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, lstArrayElements); measureBytecode(values, lstDims); measureBytecode(values, constructor); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java index 754305102b..2d28d962a1 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java @@ -95,7 +95,7 @@ public CheckTypesResult checkExprTypeBounds() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, exprents); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java index f15a88293e..2358b92e51 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -251,7 +251,7 @@ protected List getAllExprents(List list) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values); } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java index 0a7169f0be..bcd763cabc 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchHeadExprent.java @@ -17,7 +17,7 @@ public class SwitchHeadExprent extends Exprent { private Exprent value; private List> caseValues = new ArrayList<>(); - public SwitchHeadExprent(Exprent value, BitSet bytecodeOffsets) { + public SwitchHeadExprent(Exprent value, BytecodeRange bytecodeOffsets) { super(Type.SWITCH_HEAD); this.value = value; @@ -116,7 +116,7 @@ public boolean equals(Object o) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { if (caseValues != null && !caseValues.isEmpty()) { for (List l : caseValues) { if (l != null && !l.isEmpty()) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java index 526b4a69a0..7370778226 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -66,7 +66,7 @@ public VarExprent(int index, VarType varType, VarProcessor processor) { this(index, varType, processor, null); } - public VarExprent(int index, VarType varType, VarProcessor processor, BitSet bytecode) { + public VarExprent(int index, VarType varType, VarProcessor processor, BytecodeRange bytecode) { super(Type.VAR); this.index = index; this.varType = varType; @@ -347,7 +347,7 @@ public boolean equalsVersions(Object o) { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java index e043ec9fdd..73b140e388 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/YieldExprent.java @@ -68,7 +68,7 @@ public VarType getExprType() { } @Override - public void getBytecodeRange(BitSet values) { + public void getBytecodeRange(BytecodeRange values) { measureBytecode(values, this.content); measureBytecode(values); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java index 3f7a0de242..dd55c15963 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java @@ -237,7 +237,7 @@ public Statement getSimpleCopy() { return cs; } - public void getOffset(BitSet values) { + public void getOffset(Exprent.BytecodeRange values) { super.getOffset(values); for (Exprent exp : this.getResources()) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java index 377559466c..694a9566f9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DummyExitStatement.java @@ -1,19 +1,21 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.modules.decompiler.stats; +import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; + import java.util.BitSet; public final class DummyExitStatement extends Statement { - public BitSet bytecode = null; // offsets of bytecode instructions mapped to dummy exit + public Exprent.BytecodeRange bytecode = null; // offsets of bytecode instructions mapped to dummy exit public DummyExitStatement() { super(StatementType.DUMMY_EXIT); } - public void addBytecodeOffsets(BitSet bytecodeOffsets) { - if (bytecodeOffsets != null && !bytecodeOffsets.isEmpty()) { + public void addBytecodeOffsets(Exprent.BytecodeRange bytecodeOffsets) { + if (bytecodeOffsets != null && !bytecodeOffsets.asBitSet().isEmpty()) { if (bytecode == null) { - bytecode = new BitSet(); + bytecode = new Exprent.BytecodeRange(); } bytecode.or(bytecodeOffsets); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java index 1ea15a69d0..f2cf440cdf 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -986,7 +986,7 @@ public String toString() { } //TODO: Cleanup/cache? - public void getOffset(BitSet values) { + public void getOffset(Exprent.BytecodeRange values) { if (this instanceof DummyExitStatement && ((DummyExitStatement)this).bytecode != null) values.or(((DummyExitStatement)this).bytecode); if (this.getExprents() != null) { @@ -1007,9 +1007,9 @@ public void getOffset(BitSet values) { private StartEndPair endpoints; public StartEndPair getStartEndRange() { if (endpoints == null) { - BitSet set = new BitSet(); + Exprent.BytecodeRange set = new Exprent.BytecodeRange(); getOffset(set); - endpoints = new StartEndPair(set.nextSetBit(0), set.length() - 1); + endpoints = new StartEndPair(set.asBitSet().nextSetBit(0), set.length() - 1); } return endpoints; } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java index 08fd060b60..dc2507e8b9 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java @@ -36,6 +36,9 @@ public VarTypeProcessor(StructMethod mt, MethodDescriptor md) { } public void calculateVarTypes(RootStatement root, DirectGraph graph) { + lowerBounds.clear(); + upperBounds.clear(); + setInitVars(root); resetExprentTypes(graph); diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java index 05a7c803ea..8aa38ba0ce 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java @@ -2,6 +2,7 @@ package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.code.BytecodeVersion; +import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; @@ -77,9 +78,9 @@ public Stream matchingVars(int index) { } public Stream matchingVars(Statement stat) { - BitSet values = new BitSet(); + Exprent.BytecodeRange values = new Exprent.BytecodeRange(); stat.getOffset(values); - return getRange(values.nextSetBit(0), values.length() - 1); + return getRange(values.asBitSet().nextSetBit(0), values.length() - 1); } public Stream getRange(int start, int end) { diff --git a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java index b0caa2bcdc..7aaf0e77ea 100644 --- a/src/org/jetbrains/java/decompiler/struct/gen/VarType.java +++ b/src/org/jetbrains/java/decompiler/struct/gen/VarType.java @@ -80,7 +80,7 @@ protected VarType(CodeType type, int arrayDim, String value, TypeFamily typeFami ValidationHelper.assertTrue(type == CodeType.NULL || value != null, "Must not be null for non null type"); this.type = type; this.arrayDim = arrayDim; - this.value = value == null ? null : value.intern(); + this.value = value;// == null ? null : value.intern(); this.typeFamily = typeFamily; this.stackSize = stackSize; } @@ -122,7 +122,7 @@ public VarType(String signature, boolean clType) { this.type = type; this.arrayDim = arrayDim; - this.value = value == null ? null : value.intern(); + this.value = value;// == null ? null : value.intern(); this.typeFamily = getFamily(type, arrayDim); this.stackSize = getStackSize(type, arrayDim); } diff --git a/src/org/jetbrains/java/decompiler/util/TextBuffer.java b/src/org/jetbrains/java/decompiler/util/TextBuffer.java index bc21c40815..21b3f058bc 100644 --- a/src/org/jetbrains/java/decompiler/util/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/util/TextBuffer.java @@ -11,6 +11,7 @@ import org.jetbrains.java.decompiler.main.extern.TextTokenVisitor; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.TypeAnnotation; import org.jetbrains.java.decompiler.struct.gen.CodeType; import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; @@ -350,20 +351,26 @@ public void addStartBytecodeMapping(int bytecodeOffset) { myBytecodeOffsetMapping.putIfAbsent(new BytecodeMappingKey(bytecodeOffset, null, null), 0); } - public void addBytecodeMapping(BitSet bytecodeOffsets) { + public void addBytecodeMapping(Exprent.BytecodeRange bytecodeOffsets) { if (bytecodeOffsets == null) { return; } - for (int i = bytecodeOffsets.nextSetBit(0); i >= 0; i = bytecodeOffsets.nextSetBit(i + 1)) { + + BitSet set = bytecodeOffsets.asBitSet(); + + for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(i + 1)) { addBytecodeMapping(i); } } - public void addStartBytecodeMapping(BitSet bytecodeOffsets) { + public void addStartBytecodeMapping(Exprent.BytecodeRange bytecodeOffsets) { if (bytecodeOffsets == null) { return; } - for (int i = bytecodeOffsets.nextSetBit(0); i >= 0; i = bytecodeOffsets.nextSetBit(i + 1)) { + + BitSet set = bytecodeOffsets.asBitSet(); + + for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(i + 1)) { addStartBytecodeMapping(i); } } From 64ef5d44640caa1a69acf819fbdf508c0efe7428 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Sat, 8 Nov 2025 19:21:05 -0500 Subject: [PATCH 27/29] Lazy generate ssu dominators, don't process stack again for simple methods --- .../decompiler/main/rels/MethodProcessor.java | 16 +++++++++++----- .../sforms/SSAUConstructorSparseEx.java | 2 +- .../modules/decompiler/stats/RootStatement.java | 9 +++++++++ .../decompiler/vars/VarVersionsGraph.java | 4 ++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java index d7c108a1ce..4e9750b1bc 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/MethodProcessor.java @@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.modules.code.ExceptionDeobfuscator; import org.jetbrains.java.decompiler.modules.decompiler.flow.DirectGraph; import org.jetbrains.java.decompiler.modules.decompiler.flow.FlattenStatementsHelper; +import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; import org.jetbrains.java.decompiler.struct.StructClass; @@ -261,6 +262,12 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe // Main loop while (true) { + if (root.isSimple() && root.getFirst().getExprents().size() <= 1) { + LabelHelper.identifyLabels(root); + decompileRecord.add("IdentifyLabels", root); + break; + } + decompileRecord.incrementMainLoop(); decompileRecord.add("Start", root); @@ -324,11 +331,6 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe continue; } - if (IntersectionCastProcessor.makeIntersectionCasts(root)) { - decompileRecord.add("intersectionCasts", root); - continue; - } - if (DecompilerContext.getOption(IFernflowerPreferences.PATTERN_MATCHING)) { if (cl.getVersion().hasIfPatternMatching()) { if (IfPatternMatchProcessor.matchInstanceof(root)) { @@ -463,6 +465,10 @@ public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDe decompileRecord.add("HideEmptyDefault", root); } + if (IntersectionCastProcessor.makeIntersectionCasts(root)) { + decompileRecord.add("intersectionCasts", root); + } + if (GenericsProcessor.qualifyChains(root)) { decompileRecord.add("QualifyGenericChains", root); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java index a7f38829e9..167240fb4b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java @@ -44,7 +44,7 @@ public void splitVariables(RootStatement root, StructMethod mt) { this.ssaStatements(this.dgraph, new HashSet<>(), true, mt, 999_999); - this.ssuVersions.initDominators(); +// this.ssuVersions.initDominators(); // Validation testing ValidationHelper.validateVarVersionsGraph(this.ssuVersions, root, this.varAssignmentMap); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java index fe7f33a62f..38288c0b12 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java @@ -75,6 +75,10 @@ public void addComments(ControlFlowGraph graph) { public void buildContentFlags() { buildContentFlagsStat(this); + + if (!flags.hasLoops && !flags.hasSwitch && !flags.hasTryCatch && first instanceof BasicBlockStatement) { + flags.simple = true; + } } private void buildContentFlagsStat(Statement stat) { @@ -103,6 +107,10 @@ public boolean hasSwitch() { return this.flags.hasSwitch; } + public boolean isSimple() { + return this.flags.simple; + } + @Override public StartEndPair getStartEndRange() { return StartEndPair.join(first.getStartEndRange(), dummyExit != null ? dummyExit.getStartEndRange() : null); @@ -112,5 +120,6 @@ private static class ContentFlags { private boolean hasTryCatch; private boolean hasLoops; private boolean hasSwitch; + private boolean simple; } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java index a66717fa41..695014dcb6 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java @@ -28,6 +28,10 @@ public VarVersionNode createNode(VarVersionPair ver, LocalVariable lvt) { public boolean isDominatorSet(VarVersionNode node, Set domnodes) { if (domnodes.size() == 1) { + if (this.engine == null) { + initDominators(); + } + return this.engine.isDominator(node, domnodes.iterator().next()); } else { if (domnodes.contains(node)) { From 0ff02f78071a2ff2c4e84041fca14eaf83dc0f17 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:18:02 -0500 Subject: [PATCH 28/29] Only run ssa/u in FinallyProcessor when needed --- .../modules/decompiler/FinallyProcessor.java | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java index d6a06dea8d..abb6707a82 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java @@ -50,8 +50,11 @@ public class FinallyProcessor { private final MethodDescriptor methodDescriptor; private final VarProcessor varProcessor; + + // Ephemeral variables private @Nullable VarVersionsGraph ssuversions; private @Nullable Map instrRewrites; + private RootStatement root; public FinallyProcessor(StructMethod mt, MethodDescriptor md, VarProcessor varProc) { this.methodDescriptor = md; @@ -60,6 +63,8 @@ public FinallyProcessor(StructMethod mt, MethodDescriptor md, VarProcessor varPr public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, ControlFlowGraph graph) { this.ssuversions = null; + this.instrRewrites = null; + this.root = root; BytecodeVersion bytecodeVersion = mt.getBytecodeVersion(); ListStack stack = new ListStack<>(); @@ -148,26 +153,35 @@ private record Area(BasicBlock start, Set sample, @Nullable BasicBlo private record FinallyExit(BasicBlock source, BasicBlock succ, ExitType type) { } - private @Nullable Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) { - ExprProcessor proc = new ExprProcessor(this.methodDescriptor, this.varProcessor); - proc.processStatement(root, cl); - - if (this.ssuversions == null) { - // FIXME: don't split SSAU unless needed! + private Map getInstrRewrites() { + if (this.instrRewrites == null) { SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); - ssa.splitVariables(root, mt); + ssa.splitVariables(root, root.mt); this.instrRewrites = SimpleSSAReassign.reassignSSAForm(ssa, root); StackVarsProcessor.setVersionsToNull(root); + } + + return this.instrRewrites; + } + private VarVersionsGraph getVarVersionsGraph() { + if (this.ssuversions == null) { SSAUConstructorSparseEx ssau = new SSAUConstructorSparseEx(); - ssau.splitVariables(root, mt); + ssau.splitVariables(root, root.mt); this.ssuversions = ssau.getSsuVersions(); StackVarsProcessor.setVersionsToNull(root); } + return this.ssuversions; + } + + private @Nullable Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) { + ExprProcessor proc = new ExprProcessor(this.methodDescriptor, this.varProcessor); + proc.processStatement(root, cl); + Map mapLast = new LinkedHashMap<>(); BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead(); @@ -900,8 +914,6 @@ private static void splitBasicBlock( } public boolean equalInstructions(Instruction first, Instruction second, List lstStoreVars) { - ValidationHelper.notNull(this.instrRewrites); - ValidationHelper.notNull(this.ssuversions); if (!Instruction.equals(first, second)) { return false; } @@ -930,14 +942,15 @@ public boolean equalInstructions(Instruction first, Instruction second, List rewrites = this.getInstrRewrites(); + if (rewrites.containsKey(first)) { + firstOp = rewrites.get(first); } - if (this.instrRewrites.containsKey(second)) { - secondOp = this.instrRewrites.get(second); + if (rewrites.containsKey(second)) { + secondOp = rewrites.get(second); } - if (this.ssuversions.areVarsAnalogous(firstOp, secondOp)) { + if (this.getVarVersionsGraph().areVarsAnalogous(firstOp, secondOp)) { ok = true; } From 130f1efbc80e5ce7a3c71277aca8ebeb588d4134 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan <25208576+jaskarth@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:27:41 -0400 Subject: [PATCH 29/29] fix build --- .../src/main/java/org/vineflower/kotlin/KotlinWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java index a52680f4ba..694c7129e3 100644 --- a/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java +++ b/plugins/kotlin/src/main/java/org/vineflower/kotlin/KotlinWriter.java @@ -579,7 +579,7 @@ private void writeLambda(ClassNode node, TextBuffer buffer, int indent, KFunctio buffer.appendIndent(indent).append("}"); } - public static TextBuffer stringifyReference(int indent, ClassesProcessor.ClassNode node, BitSet bytecode, Exprent receiver) { + public static TextBuffer stringifyReference(int indent, ClassesProcessor.ClassNode node, Exprent.BytecodeRange bytecode, Exprent receiver) { // Attempt to extract the real reference from MethodWrapper init = node.getWrapper().getMethodWrapper("", receiver != null ? "(Ljava/lang/Object;)V" : "()V"); if (init == null) {