Skip to content

Commit b3704b8

Browse files
authored
Method node builder fixes (#170)
* Wrong conversion of some condition instructions with zero comparison from IR to jvm bytecode #167 Wrong conversion of numeric constants from IR to jvm bytecode #166 * Bug with local variables creation #165
1 parent 658ab24 commit b3704b8

3 files changed

Lines changed: 127 additions & 7 deletions

File tree

jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/MethodNodeBuilder.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,26 +265,30 @@ class MethodNodeBuilder(
265265
is JcRawLtExpr -> Triple(JcRawInt(0), Opcodes.IFLT, Opcodes.IF_ICMPLT)
266266
else -> error("Unknown condition expr: $cond")
267267
}
268+
val elseBranchTarget: LabelNode
268269
currentInsnList.add(
269270
when {
270271
cond.lhv == zeroValue -> {
271272
cond.rhv.accept(this)
272-
JumpInsnNode(zeroCmpOpcode, trueTarget)
273+
elseBranchTarget = trueTarget
274+
JumpInsnNode(zeroCmpOpcode, falseTarget)
273275
}
274276

275277
cond.rhv == zeroValue -> {
276278
cond.lhv.accept(this)
279+
elseBranchTarget = falseTarget
277280
JumpInsnNode(zeroCmpOpcode, trueTarget)
278281
}
279282

280283
else -> {
281284
cond.lhv.accept(this)
282285
cond.rhv.accept(this)
286+
elseBranchTarget = falseTarget
283287
JumpInsnNode(defaultOpcode, trueTarget)
284288
}
285289
}
286290
)
287-
currentInsnList.add(JumpInsnNode(Opcodes.GOTO, falseTarget))
291+
currentInsnList.add(JumpInsnNode(Opcodes.GOTO, elseBranchTarget))
288292
updateStackInfo(-stackSize)
289293
}
290294

@@ -713,7 +717,7 @@ class MethodNodeBuilder(
713717

714718
override fun visitJcRawInt(value: JcRawInt) {
715719
currentInsnList.add(
716-
when (value.value) {
720+
when (value.value as Comparable<Int>) {
717721
in -1..5 -> InsnNode(Opcodes.ICONST_0 + value.value)
718722
in Byte.MIN_VALUE..Byte.MAX_VALUE -> IntInsnNode(Opcodes.BIPUSH, value.value)
719723
in Short.MIN_VALUE..Short.MAX_VALUE -> IntInsnNode(Opcodes.SIPUSH, value.value)
@@ -725,8 +729,8 @@ class MethodNodeBuilder(
725729

726730
override fun visitJcRawLong(value: JcRawLong) {
727731
currentInsnList.add(
728-
when (value.value) {
729-
in 0..1 -> InsnNode(Opcodes.LCONST_0 + value.value.toInt())
732+
when {
733+
(value.value as Comparable<Long>).let { it >= 0 && it <= 1 } -> InsnNode(Opcodes.LCONST_0 + value.value.toInt())
730734
else -> LdcInsnNode(value.value)
731735
}
732736
)
@@ -735,7 +739,7 @@ class MethodNodeBuilder(
735739

736740
override fun visitJcRawFloat(value: JcRawFloat) {
737741
currentInsnList.add(
738-
when (value.value) {
742+
when (value.value as Comparable<Float>) {
739743
0.0F -> InsnNode(Opcodes.FCONST_0)
740744
1.0F -> InsnNode(Opcodes.FCONST_1)
741745
2.0F -> InsnNode(Opcodes.FCONST_2)
@@ -747,7 +751,7 @@ class MethodNodeBuilder(
747751

748752
override fun visitJcRawDouble(value: JcRawDouble) {
749753
currentInsnList.add(
750-
when (value.value) {
754+
when (value.value as Comparable<Double>) {
751755
0.0 -> InsnNode(Opcodes.DCONST_0)
752756
1.0 -> InsnNode(Opcodes.DCONST_1)
753757
else -> LdcInsnNode(value.value)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2022 UnitTestBot contributors (utbot.org)
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jacodb.testing.cfg
18+
19+
import org.jacodb.api.ext.findClass
20+
import org.jacodb.testing.WithDB
21+
import org.jacodb.testing.ir.DoubleComparison
22+
import org.jacodb.testing.ir.InvokeMethodWithException
23+
import org.jacodb.testing.ir.WhenExpr
24+
import org.junit.jupiter.api.Assertions.assertEquals
25+
import org.junit.jupiter.api.Test
26+
27+
class ReverseIRTest : BaseInstructionsTest() {
28+
companion object : WithDB()
29+
30+
@Test
31+
fun comparison() {
32+
val clazz = testAndLoadClass(cp.findClass<DoubleComparison>())
33+
val m = clazz.declaredMethods.first { it.name == "box" }
34+
assertEquals("OK", m.invoke(null))
35+
}
36+
37+
@Test
38+
fun `when`() {
39+
val clazz = testAndLoadClass(cp.findClass<WhenExpr>())
40+
val m = clazz.declaredMethods.first { it.name == "box" }
41+
assertEquals("OK", m.invoke(null))
42+
}
43+
44+
@Test
45+
fun `local vars`() {
46+
val clazz = testAndLoadClass(cp.findClass<InvokeMethodWithException>())
47+
val m = clazz.declaredMethods.first { it.name == "box" }
48+
assertEquals("OK", m.invoke(null))
49+
}
50+
51+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2022 UnitTestBot contributors (utbot.org)
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jacodb.testing.ir
18+
19+
20+
object DoubleComparison {
21+
22+
@JvmStatic
23+
fun box(): String {
24+
if ((-0.0 as Comparable<Double>) >= 0.0) return "fail"
25+
return "OK"
26+
}
27+
}
28+
29+
30+
object WhenExpr {
31+
32+
val x = 1
33+
34+
@JvmStatic
35+
fun box() =
36+
when (val y = x) {
37+
in 0..2 -> "OK"
38+
else -> "Fail: $y"
39+
}
40+
41+
}
42+
43+
object InvokeMethodWithException {
44+
45+
class A {
46+
fun lol(a: Int): Int {
47+
return 888/a
48+
}
49+
}
50+
51+
@JvmStatic
52+
fun box():String {
53+
val method = A::class.java.getMethod("lol", Int::class.java)
54+
var failed = false
55+
try {
56+
method.invoke(null, 0)
57+
}
58+
catch(e: Exception) {
59+
failed = true
60+
}
61+
62+
return if (!failed) "fail" else "OK"
63+
}
64+
65+
}

0 commit comments

Comments
 (0)