提交 13c17a00 编写于 作者: S Skylot

fix: force code inline after new array creation resugar (#1048)

上级 96dea75b
...@@ -4,8 +4,6 @@ import java.util.List; ...@@ -4,8 +4,6 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
...@@ -44,8 +42,6 @@ import jadx.core.utils.exceptions.JadxException; ...@@ -44,8 +42,6 @@ import jadx.core.utils.exceptions.JadxException;
) )
public class ReSugarCode extends AbstractVisitor { public class ReSugarCode extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(ReSugarCode.class);
@Override @Override
public boolean visit(ClassNode cls) throws JadxException { public boolean visit(ClassNode cls) throws JadxException {
initClsEnumMap(cls); initClsEnumMap(cls);
...@@ -57,55 +53,57 @@ public class ReSugarCode extends AbstractVisitor { ...@@ -57,55 +53,57 @@ public class ReSugarCode extends AbstractVisitor {
if (mth.isNoCode()) { if (mth.isNoCode()) {
return; return;
} }
boolean changed = false;
InsnRemover remover = new InsnRemover(mth); InsnRemover remover = new InsnRemover(mth);
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
remover.setBlock(block); remover.setBlock(block);
List<InsnNode> instructions = block.getInstructions(); List<InsnNode> instructions = block.getInstructions();
int size = instructions.size(); int size = instructions.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
process(mth, instructions, i, remover); changed |= process(mth, instructions, i, remover);
} }
remover.perform(); remover.perform();
} }
if (changed) {
CodeShrinkVisitor.shrinkMethod(mth);
}
} }
private static void process(MethodNode mth, List<InsnNode> instructions, int i, InsnRemover remover) { private static boolean process(MethodNode mth, List<InsnNode> instructions, int i, InsnRemover remover) {
InsnNode insn = instructions.get(i); InsnNode insn = instructions.get(i);
if (insn.contains(AFlag.REMOVE)) { if (insn.contains(AFlag.REMOVE)) {
return; return false;
} }
switch (insn.getType()) { switch (insn.getType()) {
case NEW_ARRAY: case NEW_ARRAY:
processNewArray(mth, (NewArrayNode) insn, instructions, remover); return processNewArray(mth, (NewArrayNode) insn, instructions, remover);
break;
case SWITCH: case SWITCH:
processEnumSwitch(mth, (SwitchInsn) insn); return processEnumSwitch(mth, (SwitchInsn) insn);
break;
default: default:
break; return false;
} }
} }
/** /**
* Replace new-array and sequence of array-put to new filled-array instruction. * Replace new-array and sequence of array-put to new filled-array instruction.
*/ */
private static void processNewArray(MethodNode mth, NewArrayNode newArrayInsn, private static boolean processNewArray(MethodNode mth, NewArrayNode newArrayInsn,
List<InsnNode> instructions, InsnRemover remover) { List<InsnNode> instructions, InsnRemover remover) {
InsnArg arrLenArg = newArrayInsn.getArg(0); InsnArg arrLenArg = newArrayInsn.getArg(0);
if (!arrLenArg.isLiteral()) { if (!arrLenArg.isLiteral()) {
return; return false;
} }
int len = (int) ((LiteralArg) arrLenArg).getLiteral(); int len = (int) ((LiteralArg) arrLenArg).getLiteral();
if (len == 0) { if (len == 0) {
return; return false;
} }
RegisterArg arrArg = newArrayInsn.getResult(); RegisterArg arrArg = newArrayInsn.getResult();
SSAVar ssaVar = arrArg.getSVar(); SSAVar ssaVar = arrArg.getSVar();
List<RegisterArg> useList = ssaVar.getUseList(); List<RegisterArg> useList = ssaVar.getUseList();
if (useList.size() < len) { if (useList.size() < len) {
return; return false;
} }
// check sequential array put with increasing index // check sequential array put with increasing index
int putIndex = 0; int putIndex = 0;
...@@ -118,17 +116,15 @@ public class ReSugarCode extends AbstractVisitor { ...@@ -118,17 +116,15 @@ public class ReSugarCode extends AbstractVisitor {
} }
} }
if (putIndex != len) { if (putIndex != len) {
return; return false;
} }
List<InsnNode> arrPuts = useList.subList(0, len).stream().map(InsnArg::getParentInsn).collect(Collectors.toList()); List<InsnNode> arrPuts = useList.subList(0, len).stream().map(InsnArg::getParentInsn).collect(Collectors.toList());
// check that all puts in current block // check that all puts in current block
for (InsnNode arrPut : arrPuts) { for (InsnNode arrPut : arrPuts) {
int index = InsnList.getIndex(instructions, arrPut); int index = InsnList.getIndex(instructions, arrPut);
if (index == -1) { if (index == -1) {
if (LOG.isDebugEnabled()) { mth.addDebugComment("Can't convert new array creation: APUT found in different block: " + arrPut);
LOG.debug("TODO: APUT found in different block: {}, mth: {}", arrPut, mth); return false;
}
return;
} }
} }
...@@ -146,6 +142,7 @@ public class ReSugarCode extends AbstractVisitor { ...@@ -146,6 +142,7 @@ public class ReSugarCode extends AbstractVisitor {
InsnNode lastPut = Utils.last(arrPuts); InsnNode lastPut = Utils.last(arrPuts);
int replaceIndex = InsnList.getIndex(instructions, lastPut); int replaceIndex = InsnList.getIndex(instructions, lastPut);
instructions.set(replaceIndex, filledArr); instructions.set(replaceIndex, filledArr);
return true;
} }
private static boolean checkPutInsn(MethodNode mth, InsnNode insn, RegisterArg arrArg, int putIndex) { private static boolean checkPutInsn(MethodNode mth, InsnNode insn, RegisterArg arrArg, int putIndex) {
...@@ -164,43 +161,44 @@ public class ReSugarCode extends AbstractVisitor { ...@@ -164,43 +161,44 @@ public class ReSugarCode extends AbstractVisitor {
return false; return false;
} }
private static void processEnumSwitch(MethodNode mth, SwitchInsn insn) { private static boolean processEnumSwitch(MethodNode mth, SwitchInsn insn) {
InsnArg arg = insn.getArg(0); InsnArg arg = insn.getArg(0);
if (!arg.isInsnWrap()) { if (!arg.isInsnWrap()) {
return; return false;
} }
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn(); InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
if (wrapInsn.getType() != InsnType.AGET) { if (wrapInsn.getType() != InsnType.AGET) {
return; return false;
} }
EnumMapInfo enumMapInfo = checkEnumMapAccess(mth.root(), wrapInsn); EnumMapInfo enumMapInfo = checkEnumMapAccess(mth.root(), wrapInsn);
if (enumMapInfo == null) { if (enumMapInfo == null) {
return; return false;
} }
FieldNode enumMapField = enumMapInfo.getMapField(); FieldNode enumMapField = enumMapInfo.getMapField();
InsnArg invArg = enumMapInfo.getArg(); InsnArg invArg = enumMapInfo.getArg();
EnumMapAttr.KeyValueMap valueMap = getEnumMap(mth, enumMapField); EnumMapAttr.KeyValueMap valueMap = getEnumMap(mth, enumMapField);
if (valueMap == null) { if (valueMap == null) {
return; return false;
} }
int caseCount = insn.getKeys().length; int caseCount = insn.getKeys().length;
for (int i = 0; i < caseCount; i++) { for (int i = 0; i < caseCount; i++) {
Object key = insn.getKey(i); Object key = insn.getKey(i);
Object newKey = valueMap.get(key); Object newKey = valueMap.get(key);
if (newKey == null) { if (newKey == null) {
return; return false;
} }
} }
// replace confirmed // replace confirmed
if (!insn.replaceArg(arg, invArg)) { if (!insn.replaceArg(arg, invArg)) {
return; return false;
} }
for (int i = 0; i < caseCount; i++) { for (int i = 0; i < caseCount; i++) {
insn.modifyKey(i, valueMap.get(insn.getKey(i))); insn.modifyKey(i, valueMap.get(insn.getKey(i)));
} }
enumMapField.add(AFlag.DONT_GENERATE); enumMapField.add(AFlag.DONT_GENERATE);
checkAndHideClass(enumMapField.getParentClass()); checkAndHideClass(enumMapField.getParentClass());
return true;
} }
private static void initClsEnumMap(ClassNode enumCls) { private static void initClsEnumMap(ClassNode enumCls) {
......
package jadx.tests.integration.invoke;
import org.junit.jupiter.api.Test;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestVarArg2 extends IntegrationTest {
@SuppressWarnings("ConstantConditions")
public static class TestCls {
protected static boolean b1;
protected static final boolean IS_VALID = b1 && isValid("test");
private static boolean isValid(String... string) {
return false;
}
}
@Test
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.containsOne("isValid(\"test\")"); // TODO: .containsOne("b1 && isValid(\"test\")");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册