fix: improve StringBuilder elimination (#2148)

This commit is contained in:
Skylot
2024-04-18 19:43:11 +01:00
parent ec9244a635
commit b356ff76e1
5 changed files with 68 additions and 14 deletions
@@ -132,6 +132,10 @@ public abstract class InsnArg extends Typed {
}
InsnArg arg = wrapInsnIntoArg(insn);
InsnArg oldArg = parent.getArg(i);
if (arg.getType() == ArgType.UNKNOWN) {
// restore arg type if wrapped insn missing result
arg.setType(oldArg.getType());
}
parent.setArg(i, arg);
InsnRemover.unbindArgUsage(mth, oldArg);
if (unbind) {
@@ -1,7 +1,5 @@
package jadx.core.dex.instructions.args;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;
import jadx.core.dex.instructions.ConstStringNode;
@@ -75,10 +73,18 @@ public final class InsnWrapArg extends InsnArg {
}
@Override
public String toString() {
if (wrappedInsn.getType() == InsnType.CONST_STR && Objects.equals(type, ArgType.STRING)) {
public String toShortString() {
if (wrappedInsn.getType() == InsnType.CONST_STR) {
return "(\"" + ((ConstStringNode) wrappedInsn).getString() + "\")";
}
return "(wrap: " + type + " : " + wrappedInsn + ')';
return "(wrap:" + type + ":" + wrappedInsn.getType() + ')';
}
@Override
public String toString() {
if (wrappedInsn.getType() == InsnType.CONST_STR) {
return "(\"" + ((ConstStringNode) wrappedInsn).getString() + "\")";
}
return "(wrap:" + type + ":" + wrappedInsn + ')';
}
}
@@ -402,7 +402,8 @@ public class SimplifyVisitor extends AbstractVisitor {
}
}
if (!stringArgFound) {
mth.addDebugComment("TODO: convert one arg to string using `String.valueOf()`, args: " + args);
String argStr = Utils.listToString(args, InsnArg::toShortString);
mth.addDebugComment("TODO: convert one arg to string using `String.valueOf()`, args: " + argStr);
return null;
}
@@ -625,7 +626,9 @@ public class SimplifyVisitor extends AbstractVisitor {
for (int i = 1; i < argsCount; i++) {
concat.addArg(wrap.getArg(i));
}
return ArithNode.oneArgOp(ArithOp.ADD, fArg, InsnArg.wrapArg(concat));
InsnArg concatArg = InsnArg.wrapArg(concat);
concatArg.setType(ArgType.STRING);
return ArithNode.oneArgOp(ArithOp.ADD, fArg, concatArg);
} catch (Exception e) {
LOG.debug("Can't convert field arith insn: {}, mth: {}", insn, mth, e);
}
@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.shrink;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.Set;
@@ -64,12 +63,9 @@ public class CodeShrinkVisitor extends AbstractVisitor {
List<WrapInfo> wrapList = new ArrayList<>();
for (ArgsInfo argsInfo : argsList) {
List<RegisterArg> args = argsInfo.getArgs();
if (!args.isEmpty()) {
ListIterator<RegisterArg> it = args.listIterator(args.size());
while (it.hasPrevious()) {
RegisterArg arg = it.previous();
checkInline(mth, block, insnList, wrapList, argsInfo, arg);
}
for (int i = args.size() - 1; i >= 0; i--) {
RegisterArg arg = args.get(i);
checkInline(mth, block, insnList, wrapList, argsInfo, arg);
}
}
if (!wrapList.isEmpty()) {
@@ -0,0 +1,45 @@
package jadx.tests.integration.others;
import org.junit.jupiter.api.Test;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestStringBuilderElimination5 extends IntegrationTest {
public static class TestCls {
@SuppressWarnings("StringConcatenationInLoop")
public static String test(long[] a) {
String s = "";
final char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
for (int i = a.length - 1; i >= 0; i--) {
s += hexChars[(int) (a[i] >>> 60) & 0x0f];
s += hexChars[(int) (a[i] >>> 56) & 0x0f];
s += hexChars[(int) (a[i] >>> 52) & 0x0f];
s += hexChars[(int) (a[i] >>> 48) & 0x0f];
s += hexChars[(int) (a[i] >>> 44) & 0x0f];
s += hexChars[(int) (a[i] >>> 40) & 0x0f];
s += hexChars[(int) (a[i] >>> 36) & 0x0f];
s += hexChars[(int) (a[i] >>> 32) & 0x0f];
s += hexChars[(int) (a[i] >>> 28) & 0x0f];
s += hexChars[(int) (a[i] >>> 24) & 0x0f];
s += hexChars[(int) (a[i] >>> 20) & 0x0f];
s += hexChars[(int) (a[i] >>> 16) & 0x0f];
s += hexChars[(int) (a[i] >>> 12) & 0x0f];
s += hexChars[(int) (a[i] >>> 8) & 0x0f];
s += hexChars[(int) (a[i] >>> 4) & 0x0f];
s += hexChars[(int) (a[i]) & 0x0f];
s += " ";
}
return s;
}
}
@Test
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain(".append(");
}
}