fix: keep wide upcast for arith instructions (#2730)
This commit is contained in:
@@ -231,6 +231,9 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
ArgType castToType = (ArgType) castInsn.getIndex();
|
||||
if (isArithWideUpCast(parentInsn, argType, castToType)) {
|
||||
return null;
|
||||
}
|
||||
if (!ArgType.isCastNeeded(mth.root(), argType, castToType)
|
||||
|| isCastDuplicate(castInsn)
|
||||
|| shadowedByOuterCast(mth.root(), castToType, parentInsn)) {
|
||||
@@ -243,6 +246,21 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep cast to wide types in arith instructions,
|
||||
* because arguments type determine instruction used in result bytecode.
|
||||
* Example: (long) i << 32 - without 'long' cast will be used 'int shift' instruction and result
|
||||
* will be incorrect
|
||||
*/
|
||||
private static boolean isArithWideUpCast(@Nullable InsnNode parentInsn, ArgType argType, ArgType castToType) {
|
||||
if (parentInsn != null
|
||||
&& parentInsn.getType() == InsnType.ARITH
|
||||
&& argType.isPrimitive() && castToType.isPrimitive()) {
|
||||
return castToType.getRegCount() > argType.getRegCount();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCastDuplicate(IndexInsnNode castInsn) {
|
||||
InsnArg arg = castInsn.getArg(0);
|
||||
if (arg.isRegister()) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package jadx.tests.integration.types;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestLongCast extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
public long test(char c) {
|
||||
return (long) c << 32;
|
||||
}
|
||||
|
||||
public int test2(long l) {
|
||||
return (int) l >> 2;
|
||||
}
|
||||
|
||||
public void check() {
|
||||
assertThat(test((char) 22)).isEqualTo(94489280512L);
|
||||
assertThat(test2((1L << 32) + 8)).isEqualTo(2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOneOf(
|
||||
"return (long) c << 32;",
|
||||
"return ((long) c) << 32;");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user