fix: don't duplicate result arg with instruction copy (breaks SSA variable assign)

This commit is contained in:
Skylot
2020-04-26 18:25:49 +01:00
parent e3f388af11
commit 4dc4aa122b
27 changed files with 319 additions and 97 deletions
@@ -71,6 +71,7 @@ public class Jadx {
passes.add(new DebugInfoApplyVisitor());
}
passes.add(new GenericTypesVisitor());
passes.add(new DeboxingVisitor());
passes.add(new ModVisitor());
passes.add(new CodeShrinkVisitor());
@@ -15,6 +15,7 @@ import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.GenericInfoAttr;
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
import jadx.core.dex.attributes.nodes.MethodInlineAttr;
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
@@ -603,8 +604,7 @@ public class InsnGen {
code.add('}');
}
private void makeConstructor(ConstructorInsn insn, CodeWriter code)
throws CodegenException {
private void makeConstructor(ConstructorInsn insn, CodeWriter code) throws CodegenException {
ClassNode cls = mth.dex().resolveClass(insn.getClassType());
if (cls != null && cls.isAnonymous() && !fallback) {
cls.ensureProcessed();
@@ -622,20 +622,18 @@ public class InsnGen {
} else {
code.add("new ");
useClass(code, insn.getClassType());
ArgType argType = insn.getResult().getSVar().getCodeVar().getType();
boolean genericCls = cls == null || !cls.getGenericTypeParameters().isEmpty();
if (argType != null
&& argType.getGenericTypes() != null
&& genericCls) {
GenericInfoAttr genericInfoAttr = insn.get(AType.GENERIC_INFO);
if (genericInfoAttr != null) {
code.add('<');
if (insn.contains(AFlag.EXPLICIT_GENERICS)) {
if (genericInfoAttr.isExplicit()) {
boolean first = true;
for (ArgType type : argType.getGenericTypes()) {
for (ArgType type : genericInfoAttr.getGenericTypes()) {
if (!first) {
code.add(',');
} else {
first = false;
}
mgen.getClassGen().useType(code, type);
first = false;
}
}
code.add('>');
@@ -849,7 +847,7 @@ public class InsnGen {
regs[regNums[i]] = arg;
}
// replace args
InsnNode inlCopy = inl.copy();
InsnNode inlCopy = inl.copyWithoutResult();
List<RegisterArg> inlArgs = new ArrayList<>();
inlCopy.getRegisterArgs(inlArgs);
for (RegisterArg r : inlArgs) {
@@ -60,7 +60,6 @@ public enum AFlag {
FALL_THROUGH,
EXPLICIT_GENERICS,
VARARG_CALL,
/**
@@ -12,6 +12,7 @@ import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumMapAttr;
import jadx.core.dex.attributes.nodes.FieldReplaceAttr;
import jadx.core.dex.attributes.nodes.ForceReturnAttr;
import jadx.core.dex.attributes.nodes.GenericInfoAttr;
import jadx.core.dex.attributes.nodes.IgnoreEdgeAttr;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JumpInfo;
@@ -36,6 +37,7 @@ import jadx.core.dex.trycatch.SplitterBlockAttr;
*
* @param <T> attribute class implementation
*/
@SuppressWarnings("InstantiationOfUtilityClass")
public class AType<T extends IAttribute> {
// class, method, field
@@ -81,6 +83,7 @@ public class AType<T extends IAttribute> {
public static final AType<LoopLabelAttr> LOOP_LABEL = new AType<>();
public static final AType<AttrList<JumpInfo>> JUMP = new AType<>();
public static final AType<IMethodDetails> METHOD_DETAILS = new AType<>();
public static final AType<GenericInfoAttr> GENERIC_INFO = new AType<>();
// register
public static final AType<RegDebugInfoAttr> REG_DEBUG_INFO = new AType<>();
@@ -1,6 +1,5 @@
package jadx.core.dex.attributes.nodes;
import java.util.ArrayList;
import java.util.List;
import jadx.core.dex.attributes.AType;
@@ -53,8 +52,8 @@ public class EnumClassAttr implements IAttribute {
private final List<EnumField> fields;
private MethodNode staticMethod;
public EnumClassAttr(int fieldsCount) {
this.fields = new ArrayList<>(fieldsCount);
public EnumClassAttr(List<EnumField> fields) {
this.fields = fields;
}
public List<EnumField> getFields() {
@@ -0,0 +1,31 @@
package jadx.core.dex.attributes.nodes;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.dex.instructions.args.ArgType;
public class GenericInfoAttr implements IAttribute {
private final ArgType[] genericTypes;
private boolean explicit;
public GenericInfoAttr(ArgType[] genericTypes) {
this.genericTypes = genericTypes;
}
public ArgType[] getGenericTypes() {
return genericTypes;
}
public boolean isExplicit() {
return explicit;
}
public void setExplicit(boolean explicit) {
this.explicit = explicit;
}
@Override
public AType<GenericInfoAttr> getType() {
return AType.GENERIC_INFO;
}
}
@@ -37,4 +37,9 @@ public abstract class NotificationAttrNode extends LineAttrNode implements ICode
addAttr(AType.COMMENTS, commentStr);
LOG.info("{} in {}", commentStr, this);
}
public void addDebugComment(String commentStr) {
addAttr(AType.COMMENTS, "JADX DEBUG: " + commentStr);
LOG.debug("{} in {}", commentStr, this);
}
}
@@ -51,6 +51,10 @@ public class ArithNode extends InsnNode {
addArg(b);
}
public ArithNode(ArithOp op, InsnArg a, InsnArg b) {
this(op, null, a, b);
}
/**
* Create one argument arithmetic instructions (a+=2).
* Result is not set (null).
@@ -58,7 +62,7 @@ public class ArithNode extends InsnNode {
* @param res argument to change
*/
public static ArithNode oneArgOp(ArithOp op, InsnArg res, InsnArg a) {
ArithNode insn = new ArithNode(op, null, res, a);
ArithNode insn = new ArithNode(op, res, a);
insn.add(AFlag.ARITH_ONEARG);
return insn;
}
@@ -97,10 +101,7 @@ public class ArithNode extends InsnNode {
@Override
public InsnNode copy() {
ArithNode copy = new ArithNode(op,
getResult().duplicate(),
getArg(0).duplicate(),
getArg(1).duplicate());
ArithNode copy = new ArithNode(op, getArg(0).duplicate(), getArg(1).duplicate());
return copyCommonParams(copy);
}
@@ -1,5 +1,6 @@
package jadx.core.dex.instructions.args;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -96,6 +97,11 @@ public abstract class InsnArg extends Typed {
@Nullable("if wrap failed")
public InsnArg wrapInstruction(MethodNode mth, InsnNode insn) {
return wrapInstruction(mth, insn, true);
}
@Nullable("if wrap failed")
public InsnArg wrapInstruction(MethodNode mth, InsnNode insn, boolean unbind) {
InsnNode parent = parentInsn;
if (parent == null) {
return null;
@@ -116,14 +122,24 @@ public abstract class InsnArg extends Typed {
if (arg.isRegister()) {
((RegisterArg) arg).setNameIfUnknown(name);
} else if (arg.isInsnWrap()) {
((InsnWrapArg) arg).getWrapInsn().getResult().setNameIfUnknown(name);
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
RegisterArg registerArg = wrapInsn.getResult();
if (registerArg != null) {
registerArg.setNameIfUnknown(name);
}
}
}
}
InsnArg arg = wrapInsnIntoArg(insn);
InsnArg oldArg = parent.getArg(i);
parent.setArg(i, arg);
InsnRemover.unbindArgUsage(mth, this);
InsnRemover.unbindResult(mth, insn);
InsnRemover.unbindArgUsage(mth, oldArg);
if (unbind) {
InsnRemover.unbindArgUsage(mth, this);
// result not needed in wrapped insn
InsnRemover.unbindResult(mth, insn);
insn.setResult(null);
}
return arg;
}
@@ -137,29 +153,29 @@ public abstract class InsnArg extends Typed {
return -1;
}
@NotNull
public static InsnArg wrapInsnIntoArg(InsnNode insn) {
InsnArg arg;
InsnType type = insn.getType();
if (type == InsnType.CONST || type == InsnType.MOVE) {
if (insn.contains(AFlag.FORCE_ASSIGN_INLINE)) {
RegisterArg resArg = insn.getResult();
arg = wrap(insn);
InsnArg arg = wrap(insn);
if (resArg != null) {
arg.setType(resArg.getType());
}
return arg;
} else {
arg = insn.getArg(0);
insn.add(AFlag.REMOVE);
InsnArg arg = insn.getArg(0);
insn.add(AFlag.DONT_GENERATE);
return arg;
}
} else {
arg = wrapArg(insn);
}
return arg;
return wrapArg(insn);
}
/**
* Prefer {@link InsnArg#wrapInsnIntoArg}.
* Prefer {@link InsnArg#wrapInsnIntoArg(InsnNode)}.
* <p>
* This method don't support MOVE and CONST insns!
*/
public static InsnArg wrapArg(InsnNode insn) {
@@ -36,7 +36,7 @@ public final class InsnWrapArg extends InsnArg {
@Override
public InsnArg duplicate() {
InsnWrapArg copy = new InsnWrapArg(wrappedInsn.copy());
InsnWrapArg copy = new InsnWrapArg(wrappedInsn.copyWithoutResult());
copy.setType(type);
return copyCommonParams(copy);
}
@@ -130,6 +130,10 @@ public class RegisterArg extends InsnArg implements Named {
return duplicate(getRegNum(), sVar);
}
public RegisterArg duplicate(@Nullable SSAVar ssaVar) {
return duplicate(getRegNum(), ssaVar);
}
public RegisterArg duplicate(int regNum, @Nullable SSAVar sVar) {
RegisterArg dup = new RegisterArg(regNum, getInitType());
if (sVar != null) {
@@ -270,6 +270,7 @@ public class SSAVar {
if (!types.isEmpty()) {
sb.append(", types: ").append(types);
}
sb.append(", assign insn: ").append(getAssign().getParentInsn());
return sb.toString();
}
}
@@ -51,6 +51,7 @@ public class InsnNode extends LineAttrNode {
}
public void setResult(@Nullable RegisterArg res) {
this.result = res;
if (res != null) {
res.setParentInsn(this);
SSAVar ssaVar = res.getSVar();
@@ -58,7 +59,6 @@ public class InsnNode extends LineAttrNode {
ssaVar.setAssign(res);
}
}
this.result = res;
}
public void addArg(InsnArg arg) {
@@ -326,17 +326,9 @@ public class InsnNode extends LineAttrNode {
}
protected final <T extends InsnNode> T copyCommonParams(T copy) {
if (copy.getResult() == null && result != null) {
copy.setResult(result.duplicate());
}
if (copy.getArgsCount() == 0) {
for (InsnArg arg : this.getArguments()) {
if (arg.isInsnWrap()) {
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
copy.addArg(InsnArg.wrapInsnIntoArg(wrapInsn.copy()));
} else {
copy.addArg(arg.duplicate());
}
copy.addArg(arg.duplicate());
}
}
copy.copyAttributesFrom(this);
@@ -347,6 +339,17 @@ public class InsnNode extends LineAttrNode {
/**
* Make copy of InsnNode object.
* <p>
* NOTE: can't copy instruction with result argument
* (SSA variable can't be used in two different assigns).
* <p>
* Prefer use next methods:
* <ul>
* <li>{@link #copyWithoutResult()} to explicitly state that result not needed
* <li>{@link #copy(RegisterArg)} to provide new result arg
* <li>{@link #copyWithNewSsaVar(MethodNode)} to make new SSA variable for result arg
* </ul>
* <p>
*/
public InsnNode copy() {
if (this.getClass() != InsnNode.class) {
@@ -355,6 +358,49 @@ public class InsnNode extends LineAttrNode {
return copyCommonParams(new InsnNode(insnType, getArgsCount()));
}
/**
* See {@link #copy()}
*/
@SuppressWarnings("unchecked")
public <T extends InsnNode> T copyWithoutResult() {
return (T) copy();
}
public InsnNode copyWithoutSsa() {
InsnNode copy = copyWithoutResult();
if (result != null) {
if (result.getSVar() == null) {
copy.setResult(result.duplicate());
} else {
throw new JadxRuntimeException("Can't copy if SSA var is set");
}
}
return copy;
}
/**
* See {@link #copy()}
*/
public InsnNode copy(RegisterArg newReturnArg) {
InsnNode copy = copy();
copy.setResult(newReturnArg);
return copy;
}
/**
* See {@link #copy()}
*/
public InsnNode copyWithNewSsaVar(MethodNode mth) {
RegisterArg result = getResult();
if (result == null) {
throw new JadxRuntimeException("Result in null");
}
int regNum = result.getRegNum();
RegisterArg resDupArg = result.duplicate(regNum, null);
mth.makeNewSVar(resDupArg);
return copy(resDupArg);
}
/**
* Fix SSAVar info in register arguments.
* Must be used after altering instructions.
@@ -647,7 +647,8 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
return debugInfoOffset;
}
public SSAVar makeNewSVar(int regNum, @NotNull RegisterArg assignArg) {
public SSAVar makeNewSVar(@NotNull RegisterArg assignArg) {
int regNum = assignArg.getRegNum();
return makeNewSVar(regNum, getNextSVarVersion(regNum), assignArg);
}
@@ -93,8 +93,7 @@ public class ConstInlineVisitor extends AbstractVisitor {
String s = ((ConstStringNode) insn).getString();
FieldNode f = mth.getParentClass().getConstField(s);
if (f == null) {
InsnNode copy = insn.copy();
copy.setResult(null);
InsnNode copy = insn.copyWithoutResult();
constArg = InsnArg.wrapArg(copy);
} else {
InsnNode constGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
@@ -44,6 +44,7 @@ import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.utils.BlockInsnPair;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxException;
import static jadx.core.utils.InsnUtils.checkInsnType;
@@ -152,14 +153,13 @@ public class EnumVisitor extends AbstractVisitor {
toRemove.add(valuesInitInsn);
// all checks complete, perform transform
EnumClassAttr attr = new EnumClassAttr(enumFields.size());
EnumClassAttr attr = new EnumClassAttr(enumFields);
attr.setStaticMethod(classInitMth);
attr.getFields().addAll(enumFields);
cls.addAttr(attr);
for (EnumField field : attr.getFields()) {
ConstructorInsn co = field.getConstrInsn();
FieldNode fieldNode = field.getField();
for (EnumField enumField : attr.getFields()) {
ConstructorInsn co = enumField.getConstrInsn();
FieldNode fieldNode = enumField.getField();
// use string arg from the constructor as enum field name
String name = getConstString(cls.dex(), co.getArg(0));
@@ -172,13 +172,16 @@ public class EnumVisitor extends AbstractVisitor {
if (!co.getClassType().equals(cls.getClassInfo())) {
// enum contains additional methods
for (ClassNode innerCls : cls.getInnerClasses()) {
processEnumInnerCls(co, field, innerCls);
processEnumInnerCls(co, enumField, innerCls);
}
}
fieldNode.add(AFlag.DONT_GENERATE);
}
List<InsnNode> constrInsns = Utils.collectionMap(attr.getFields(), EnumField::getConstrInsn);
InsnRemover.removeAllWithoutUnbind(staticBlock, constrInsns);
valuesField.add(AFlag.DONT_GENERATE);
enumFields.forEach(f -> f.getField().add(AFlag.DONT_GENERATE));
InsnRemover.removeAllAndUnbind(classInitMth, staticBlock, toRemove);
if (classInitMth.countInsns() == 0) {
classInitMth.add(AFlag.DONT_GENERATE);
@@ -242,7 +245,6 @@ public class EnumVisitor extends AbstractVisitor {
}
toRemove.add(sgetInsn);
toRemove.add(sputInsn);
toRemove.add(co);
return createEnumFieldByConstructor(cls, enumFieldNode, co);
}
@@ -0,0 +1,61 @@
package jadx.core.dex.visitors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.dex.attributes.nodes.GenericInfoAttr;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.mods.ConstructorInsn;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;
import jadx.core.utils.exceptions.JadxException;
@JadxVisitor(
name = "GenericTypesVisitor",
desc = "Fix and apply generic type info",
runAfter = TypeInferenceVisitor.class,
runBefore = { CodeShrinkVisitor.class, MethodInvokeVisitor.class }
)
public class GenericTypesVisitor extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(GenericTypesVisitor.class);
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
for (BlockNode block : mth.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions()) {
if (insn.getType() == InsnType.CONSTRUCTOR) {
attachGenericTypesInfo(mth, (ConstructorInsn) insn);
}
}
}
}
private void attachGenericTypesInfo(MethodNode mth, ConstructorInsn insn) {
try {
RegisterArg resultArg = insn.getResult();
if (resultArg == null) {
return;
}
ArgType argType = resultArg.getSVar().getCodeVar().getType();
if (argType == null || argType.getGenericTypes() == null) {
return;
}
ClassNode cls = mth.dex().resolveClass(insn.getClassType());
if (cls != null && cls.getGenericTypeParameters().isEmpty()) {
return;
}
insn.addAttr(new GenericInfoAttr(argType.getGenericTypes()));
} catch (Exception e) {
LOG.error("Failed to attach constructor generic info", e);
}
}
}
@@ -73,7 +73,7 @@ public class MethodInlineVisitor extends AbstractVisitor {
if (Consts.DEBUG) {
mth.addAttr(AType.COMMENTS, "Removed for inline");
} else {
InsnNode copy = insn.copy();
InsnNode copy = insn.copyWithoutResult();
// unbind SSA variables from copy instruction
List<RegisterArg> regArgs = new ArrayList<>();
copy.getRegisterArgs(regArgs);
@@ -39,6 +39,7 @@ import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.InsnList;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
public class SimplifyVisitor extends AbstractVisitor {
@@ -393,7 +394,8 @@ public class SimplifyVisitor extends AbstractVisitor {
// all check passed
removeStringBuilderInsns(mth, toStrInsn, chain);
InsnNode concatInsn = new InsnNode(InsnType.STR_CONCAT, args);
List<InsnArg> dupArgs = Utils.collectionMap(args, InsnArg::duplicate);
InsnNode concatInsn = new InsnNode(InsnType.STR_CONCAT, dupArgs);
concatInsn.setResult(toStrInsn.getResult());
concatInsn.add(AFlag.SYNTHETIC);
concatInsn.copyAttributesFrom(toStrInsn);
@@ -499,7 +501,8 @@ public class SimplifyVisitor extends AbstractVisitor {
|| !wrap.getArg(0).isInsnWrap()) {
return null;
}
InsnNode get = ((InsnWrapArg) wrap.getArg(0)).getWrapInsn();
InsnArg getWrap = wrap.getArg(0);
InsnNode get = ((InsnWrapArg) getWrap).getWrapInsn();
InsnType getType = get.getType();
if (getType != InsnType.IGET && getType != InsnType.SGET) {
return null;
@@ -517,7 +520,8 @@ public class SimplifyVisitor extends AbstractVisitor {
return null;
}
}
InsnArg fArg = InsnArg.wrapArg(get);
InsnArg fArg = getWrap.duplicate();
InsnRemover.unbindInsn(mth, get);
if (insn.getType() == InsnType.IPUT) {
InsnRemover.unbindArgUsage(mth, insn.getArg(1));
}
@@ -750,7 +750,7 @@ public class BlockProcessor extends AbstractVisitor {
first = false;
} else {
for (InsnNode oldInsn : exitBlock.getInstructions()) {
newRetBlock.getInstructions().add(oldInsn.copy());
newRetBlock.getInstructions().add(oldInsn.copyWithoutSsa());
}
}
BlockSplitter.replaceConnection(pred, exitBlock, newRetBlock);
@@ -255,27 +255,19 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
return false;
}
List<InsnNode> toSkip = new LinkedList<>();
RegisterArg iterVar = nextCall.getResult();
if (iterVar == null) {
return false;
}
if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
if (!assignOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
RegisterArg iterVar;
if (nextCall.contains(AFlag.WRAPPED)) {
InsnArg wrapArg = BlockUtils.searchWrappedInsnParent(mth, nextCall);
if (wrapArg != null && wrapArg.getParentInsn() != null) {
InsnNode parentInsn = wrapArg.getParentInsn();
if (parentInsn.getType() != InsnType.CHECK_CAST) {
if (!fixIterableType(mth, iterableArg, iterVar)) {
return false;
}
parentInsn.replaceArg(wrapArg, iterVar);
} else {
BlockNode block = BlockUtils.getBlockByInsn(mth, parentInsn);
if (block == null) {
return false;
}
if (!RegionUtils.isRegionContainsBlock(loopRegion, block)) {
return false;
}
if (parentInsn.getType() == InsnType.CHECK_CAST) {
iterVar = parentInsn.getResult();
if (iterVar == null || !fixIterableType(mth, iterableArg, iterVar)) {
return false;
@@ -287,12 +279,32 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
// cast not inlined
toSkip.add(parentInsn);
}
} else {
iterVar = nextCall.getResult();
if (iterVar == null) {
return false;
}
nextCall.add(AFlag.DONT_GENERATE);
if (!fixIterableType(mth, iterableArg, iterVar)) {
return false;
}
parentInsn.replaceArg(wrapArg, iterVar);
}
} else {
LOG.warn(" checkIterableForEach: Wrapped insn not found: {}, mth: {}", nextCall, mth);
return false;
}
} else {
iterVar = nextCall.getResult();
if (iterVar == null) {
return false;
}
if (!usedOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
if (!assignOnlyInLoop(mth, loopRegion, iterVar)) {
return false;
}
toSkip.add(nextCall);
}
@@ -25,7 +25,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
@JadxVisitor(
name = "CodeShrinkVisitor",
desc = "Inline variables for make code smaller",
desc = "Inline variables to make code smaller",
runAfter = { ModVisitor.class }
)
public class CodeShrinkVisitor extends AbstractVisitor {
@@ -125,12 +125,11 @@ public class CodeShrinkVisitor extends AbstractVisitor {
if (useInsn == null || useInsn.contains(AFlag.DONT_GENERATE)) {
return false;
}
InsnArg replaceArg = InsnArg.wrapInsnIntoArg(assignInsn.copy());
if (!InsnRemover.removeWithoutUnbind(mth, assignBlock, assignInsn)) {
return false;
}
InsnArg replaceArg = InsnArg.wrapInsnIntoArg(assignInsn);
useInsn.replaceArg(useArg, replaceArg);
assignInsn.add(AFlag.REMOVE);
assignInsn.add(AFlag.DONT_GENERATE);
InsnRemover.remove(mth, assignBlock, assignInsn);
return true;
}
@@ -142,9 +141,11 @@ public class CodeShrinkVisitor extends AbstractVisitor {
if (insn.contains(AFlag.FORCE_ASSIGN_INLINE)) {
return assignInline(mth, arg, insn, block);
}
boolean replaced = arg.wrapInstruction(mth, insn) != null;
// just move instruction into arg, don't unbind/copy/duplicate
InsnArg wrappedArg = arg.wrapInstruction(mth, insn, false);
boolean replaced = wrappedArg != null;
if (replaced) {
InsnList.remove(block, insn);
InsnRemover.removeWithoutUnbind(mth, block, insn);
}
return replaced;
}
@@ -422,7 +422,6 @@ public class SSATransform extends AbstractVisitor {
if (resArg.getRegNum() != arg.getRegNum()
&& !resArg.getSVar().isUsedInPhi()) {
markThisArgs(resArg);
parentInsn.add(AFlag.REMOVE);
parentInsn.add(AFlag.DONT_GENERATE);
}
}
@@ -404,7 +404,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
if (apply) {
int regNum = reg.getRegNum();
RegisterArg resultArg = reg.duplicate(regNum, null);
SSAVar newSsaVar = mth.makeNewSVar(regNum, resultArg);
SSAVar newSsaVar = mth.makeNewSVar(resultArg);
RegisterArg arg = reg.duplicate(regNum, var);
InsnNode moveInsn = new InsnNode(InsnType.MOVE, 1);
@@ -476,7 +476,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
castNode.addArg(bound.getArg());
castNode.setResult(InsnArg.reg(bound.getArg().getRegNum(), bound.getType()));
SSAVar newVar = mth.makeNewSVar(castNode.getResult().getRegNum(), castNode.getResult());
SSAVar newVar = mth.makeNewSVar(castNode.getResult());
CodeVar codeVar = new CodeVar();
codeVar.setType(bound.getType());
newVar.setCodeVar(codeVar);
@@ -56,8 +56,6 @@ public class InsnRemover {
public void addWithoutUnbind(InsnNode insn) {
toRemove.add(insn);
insn.add(AFlag.REMOVE);
insn.add(AFlag.DONT_GENERATE);
}
public void perform() {
@@ -69,7 +67,8 @@ public class InsnRemover {
remove(mth, remInsn);
}
} else {
removeAll(mth, instrList, toRemove);
unbindInsns(mth, toRemove);
removeAll(instrList, toRemove);
}
toRemove.clear();
}
@@ -77,10 +76,15 @@ public class InsnRemover {
public static void unbindInsn(@Nullable MethodNode mth, InsnNode insn) {
unbindAllArgs(mth, insn);
unbindResult(mth, insn);
insn.add(AFlag.REMOVE);
insn.add(AFlag.DONT_GENERATE);
}
public static void unbindInsns(@Nullable MethodNode mth, List<InsnNode> insns) {
for (InsnNode insn : insns) {
unbindInsn(mth, insn);
}
}
public static void unbindAllArgs(@Nullable MethodNode mth, InsnNode insn) {
for (InsnArg arg : insn.getArguments()) {
unbindArgUsage(mth, arg);
@@ -154,7 +158,7 @@ public class InsnRemover {
// Don't use 'instrList.removeAll(toRemove)' because it will remove instructions by content
// and here can be several instructions with same content
private static void removeAll(MethodNode mth, List<InsnNode> insns, List<InsnNode> toRemove) {
private static void removeAll(List<InsnNode> insns, List<InsnNode> toRemove) {
if (toRemove == null || toRemove.isEmpty()) {
return;
}
@@ -164,7 +168,6 @@ public class InsnRemover {
for (int i = 0; i < insnsCount; i++) {
if (insns.get(i) == rem) {
insns.remove(i);
unbindInsn(mth, rem);
found = true;
break;
}
@@ -179,32 +182,58 @@ public class InsnRemover {
}
public static void remove(MethodNode mth, InsnNode insn) {
if (insn.contains(AFlag.WRAPPED)) {
unbindInsn(mth, insn);
return;
}
BlockNode block = BlockUtils.getBlockByInsn(mth, insn);
if (block != null) {
remove(mth, block, insn);
} else {
insn.add(AFlag.DONT_GENERATE);
mth.addWarnComment("Not found block with instruction: " + insn);
}
}
public static void remove(MethodNode mth, BlockNode block, InsnNode insn) {
unbindInsn(mth, insn);
removeWithoutUnbind(mth, block, insn);
}
public static boolean removeWithoutUnbind(MethodNode mth, BlockNode block, InsnNode insn) {
// remove by pointer (don't use equals)
Iterator<InsnNode> it = block.getInstructions().iterator();
while (it.hasNext()) {
InsnNode ir = it.next();
if (ir == insn) {
it.remove();
return;
return true;
}
}
mth.addWarnComment("Failed to remove instruction: " + insn + " from block: " + block);
return false;
}
public static void removeAllAndUnbind(MethodNode mth, BlockNode block, List<InsnNode> insns) {
for (InsnNode insn : insns) {
unbindInsn(mth, insn);
unbindInsns(mth, insns);
removeAll(block.getInstructions(), insns);
}
public static void removeAllWithoutUnbind(BlockNode block, List<InsnNode> insns) {
removeAll(block.getInstructions(), insns);
}
public static void removeAllMarked(MethodNode mth) {
InsnRemover insnRemover = new InsnRemover(mth);
for (BlockNode blockNode : mth.getBasicBlocks()) {
for (InsnNode insn : blockNode.getInstructions()) {
if (insn.contains(AFlag.REMOVE)) {
insnRemover.addWithoutUnbind(insn);
}
}
insnRemover.setBlock(blockNode);
insnRemover.perform();
}
removeAll(mth, block.getInstructions(), insns);
}
public static void remove(MethodNode mth, BlockNode block, int index) {
@@ -181,7 +181,7 @@ public class InsnUtils {
}
@Nullable
public static InsnNode checkInsnType(InsnNode insn, InsnType insnType) {
public static InsnNode checkInsnType(@Nullable InsnNode insn, InsnType insnType) {
if (insn != null && insn.getType() == insnType) {
return insn;
}
@@ -1,5 +1,11 @@
package jadx.core.utils.exceptions;
import java.util.Arrays;
import jadx.core.utils.Utils;
import static jadx.core.codegen.CodeWriter.NL;
public class JadxRuntimeException extends RuntimeException {
private static final long serialVersionUID = -7410848445429898248L;
@@ -8,6 +14,10 @@ public class JadxRuntimeException extends RuntimeException {
super(message);
}
public JadxRuntimeException(String... lines) {
super(Utils.listToString(Arrays.asList(lines), NL + " "));
}
public JadxRuntimeException(String message, Throwable cause) {
super(message, cause);
}