Commit f2aa4cd1 authored by Skylot's avatar Skylot

core: make better variables naming

parent b940b99e
......@@ -9,16 +9,14 @@ subprojects {
apply plugin: 'jacoco'
apply plugin: 'coveralls'
sourceCompatibility = 1.6
targetCompatibility = 1.6
version = jadxVersion
gradle.projectsEvaluated {
tasks.withType(Compile) {
if (!"$it".contains(':jadx-samples:')) {
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
}
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
if (!"$it".contains(':jadx-samples:')) {
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
}
}
......
......@@ -6,6 +6,7 @@ import jadx.core.dex.visitors.BlockMakerVisitor;
import jadx.core.dex.visitors.ClassModifier;
import jadx.core.dex.visitors.CodeShrinker;
import jadx.core.dex.visitors.ConstInlinerVisitor;
import jadx.core.dex.visitors.DebugInfoVisitor;
import jadx.core.dex.visitors.DotGraphVisitor;
import jadx.core.dex.visitors.EnumVisitor;
import jadx.core.dex.visitors.FallbackModeVisitor;
......@@ -54,6 +55,7 @@ public class Jadx {
} else {
passes.add(new BlockMakerVisitor());
passes.add(new SSATransform());
passes.add(new DebugInfoVisitor());
passes.add(new TypeInference());
passes.add(new ConstInlinerVisitor());
......
......@@ -88,7 +88,7 @@ public class InsnGen {
public void addArg(CodeWriter code, InsnArg arg, boolean wrap) throws CodegenException {
if (arg.isRegister()) {
code.add(mgen.makeArgName((RegisterArg) arg));
code.add(mgen.getNameGen().useArg((RegisterArg) arg));
} else if (arg.isLiteral()) {
code.add(lit((LiteralArg) arg));
} else if (arg.isInsnWrap()) {
......@@ -120,7 +120,7 @@ public class InsnGen {
public void declareVar(CodeWriter code, RegisterArg arg) {
useType(code, arg.getType());
code.add(' ');
code.add(mgen.assignArg(arg));
code.add(mgen.getNameGen().assignArg(arg));
}
private static String lit(LiteralArg arg) {
......
package jadx.core.codegen;
import jadx.core.Consts;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.annotations.MethodParameters;
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.NamedArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
......@@ -21,10 +19,8 @@ import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.DecodeException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -36,27 +32,24 @@ public class MethodGen {
private final MethodNode mth;
private final ClassGen classGen;
private final boolean fallback;
private final AnnotationGen annotationGen;
private final Set<String> varNames = new HashSet<String>();
private final NameGen nameGen;
public MethodGen(ClassGen classGen, MethodNode mth) {
this.mth = mth;
this.classGen = classGen;
this.fallback = classGen.isFallbackMode();
this.annotationGen = classGen.getAnnotationGen();
List<RegisterArg> args = mth.getArguments(true);
for (RegisterArg arg : args) {
varNames.add(makeArgName(arg));
}
this.nameGen = new NameGen(classGen.isFallbackMode());
}
public ClassGen getClassGen() {
return classGen;
}
public NameGen getNameGen() {
return nameGen;
}
public MethodNode getMethodNode() {
return mth;
}
......@@ -124,9 +117,7 @@ public class MethodGen {
}
private void addMethodArguments(CodeWriter argsCode, List<RegisterArg> args) {
MethodParameters paramsAnnotation =
mth.get(AType.ANNOTATION_MTH_PARAMETERS);
MethodParameters paramsAnnotation = mth.get(AType.ANNOTATION_MTH_PARAMETERS);
int i = 0;
for (Iterator<RegisterArg> it = args.iterator(); it.hasNext(); ) {
RegisterArg arg = it.next();
......@@ -150,7 +141,7 @@ public class MethodGen {
classGen.useType(argsCode, arg.getType());
}
argsCode.add(' ');
argsCode.add(makeArgName(arg));
argsCode.add(nameGen.assignArg(arg));
i++;
if (it.hasNext()) {
......@@ -159,74 +150,6 @@ public class MethodGen {
}
}
/**
* Make variable name for register,
* Name contains register number and
* variable type or name (if debug info available)
*/
public String makeArgName(RegisterArg arg) {
String name = arg.getName();
String base = "r" + arg.getRegNum();
if (fallback) {
if (name != null) {
return base + "_" + name;
}
return base;
} else {
if (name != null) {
if (Consts.DEBUG) {
return base + "_" + name;
}
return name;
} else {
ArgType type = arg.getType();
if (type.isPrimitive()) {
return base + type.getPrimitiveType().getShortName().toLowerCase();
} else {
// TODO: prettify variable name
return base + "_" + Utils.escape(type.toString());
}
}
}
}
/**
* Put variable declaration and return variable name (used for assignments)
*
* @param arg register variable
* @return variable name
*/
public String assignArg(RegisterArg arg) {
String name = makeArgName(arg);
if (varNames.add(name) || fallback) {
return name;
}
name = getUniqVarName(name);
arg.getSVar().setVariableName(name);
return name;
}
public String assignNamedArg(NamedArg arg) {
String name = arg.getName();
if (varNames.add(name) || fallback) {
return name;
}
name = getUniqVarName(name);
arg.setName(name);
return name;
}
private String getUniqVarName(String name) {
String r;
int i = 2;
do {
r = name + "_" + i;
i++;
} while (varNames.contains(r));
varNames.add(r);
return r;
}
public void addInstructions(CodeWriter code) throws CodegenException {
if (mth.contains(AType.JADX_ERROR)) {
code.startLine("throw new UnsupportedOperationException(\"Method not decompiled: ");
......@@ -283,20 +206,23 @@ public class MethodGen {
return;
}
}
List<InsnNode> insns = mth.getInstructions();
if (insns == null) {
InsnNode[] insnArr = mth.getInstructions();
if (insnArr == null) {
code.startLine("// Can't load method instructions.");
return;
}
if (mth.getThisArg() != null) {
code.startLine(getFallbackMethodGen(mth).makeArgName(mth.getThisArg())).add(" = this;");
code.startLine(getFallbackMethodGen(mth).nameGen.useArg(mth.getThisArg())).add(" = this;");
}
addFallbackInsns(code, mth, insns, true);
addFallbackInsns(code, mth, insnArr, true);
}
public static void addFallbackInsns(CodeWriter code, MethodNode mth, List<InsnNode> insns, boolean addLabels) {
public static void addFallbackInsns(CodeWriter code, MethodNode mth, InsnNode[] insnArr, boolean addLabels) {
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true);
for (InsnNode insn : insns) {
for (InsnNode insn : insnArr) {
if (insn == null) {
continue;
}
if (addLabels) {
if (insn.contains(AType.JUMP)
|| insn.contains(AType.EXC_HANDLER)) {
......
package jadx.core.codegen;
import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.NamedArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.utils.Utils;
import java.util.HashSet;
import java.util.Set;
public class NameGen {
private final Set<String> varNames = new HashSet<String>();
private final boolean fallback;
public NameGen(boolean fallback) {
this.fallback = fallback;
}
public String assignArg(RegisterArg arg) {
String name = makeArgName(arg);
if (fallback) {
return name;
}
name = getUniqueVarName(name);
SSAVar sVar = arg.getSVar();
if (sVar != null) {
sVar.setName(name);
}
return name;
}
public String assignNamedArg(NamedArg arg) {
String name = arg.getName();
if (fallback) {
return name;
}
name = getUniqueVarName(name);
arg.setName(name);
return name;
}
public String useArg(RegisterArg arg) {
String name = makeArgName(arg);
varNames.add(name);
return name;
}
private String getUniqueVarName(String name) {
String r = name;
int i = 2;
while (varNames.contains(r)) {
r = name + i;
i++;
}
varNames.add(r);
return r;
}
private String makeArgName(RegisterArg arg) {
String name = arg.getName();
if (fallback) {
String base = "r" + arg.getRegNum();
if (name != null) {
return base + "_" + name;
}
return base;
}
String varName;
if (name != null) {
if (name.equals("this")) {
return name;
}
varName = name;
} else {
varName = makeNameForType(arg.getType());
}
if (NameMapper.isReserved(varName)) {
return varName + "R";
}
return varName;
}
private static String makeNameForType(ArgType type) {
if (type.isPrimitive()) {
return makeNameForPrimitive(type);
} else if (type.isArray()) {
return makeNameForType(type.getArrayRootElement()) + "Arr";
} else {
return makeNameForObject(type);
}
}
private static String makeNameForPrimitive(ArgType type) {
return type.getPrimitiveType().getShortName().toLowerCase();
}
private static String makeNameForObject(ArgType type) {
if (type.isObject()) {
String obj = type.getObject();
if (obj.startsWith("java.lang.")) {
if (obj.equals(Consts.CLASS_STRING)) {
return "str";
}
if (obj.equals(Consts.CLASS_OBJECT)) {
return "obj";
}
if (obj.equals(Consts.CLASS_CLASS)) {
return "cls";
}
if (obj.equals(Consts.CLASS_THROWABLE)) {
return "th";
}
}
ClassInfo clsInfo = ClassInfo.fromType(type);
String shortName = clsInfo.getShortName();
if (shortName.toUpperCase().equals(shortName)) {
// all characters are upper case
return shortName.toLowerCase();
}
if (!shortName.isEmpty()) {
String v1 = Character.toLowerCase(shortName.charAt(0)) + shortName.substring(1);
if (!v1.equals(shortName)) {
return v1;
}
}
}
return Utils.escape(type.toString());
}
}
......@@ -277,7 +277,7 @@ public class RegionGen extends InsnGen {
useClass(code, handler.getCatchType());
}
code.add(' ');
code.add(mgen.assignNamedArg(handler.getArg()));
code.add(mgen.getNameGen().assignNamedArg(handler.getArg()));
code.add(") {");
makeRegionIndent(code, region);
}
......
......@@ -26,7 +26,7 @@ public abstract class InsnArg extends Typed {
return reg(InsnUtils.getArg(insn, argNum), type);
}
public static RegisterArg parameterReg(int regNum, ArgType type) {
public static MthParameterArg parameterReg(int regNum, ArgType type) {
return new MthParameterArg(regNum, type);
}
......@@ -113,7 +113,7 @@ public abstract class InsnArg extends Typed {
}
public boolean isThis() {
// must be implemented in RegisterArg
// must be implemented in RegisterArg and MthParameterArg
return false;
}
}
......@@ -2,6 +2,8 @@ package jadx.core.dex.instructions.args;
public class MthParameterArg extends RegisterArg {
private boolean isThis = false;
public MthParameterArg(int rn, ArgType type) {
super(rn, type);
}
......@@ -14,4 +16,29 @@ public class MthParameterArg extends RegisterArg {
@Override
public void setType(ArgType type) {
}
public void markAsThis() {
this.isThis = true;
}
@Override
public boolean isThis() {
return isThis;
}
@Override
public String getName() {
if (isThis) {
return "this";
}
return super.getName();
}
@Override
void setSVar(SSAVar sVar) {
if (isThis) {
sVar.setName("this");
}
super.setSVar(sVar);
}
}
......@@ -11,7 +11,6 @@ import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.parser.FieldValueAttr;
import jadx.core.utils.exceptions.JadxRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -21,7 +20,6 @@ public class RegisterArg extends InsnArg implements Named {
protected final int regNum;
protected SSAVar sVar;
protected String name;
public RegisterArg(int rn) {
this.regNum = rn;
......@@ -49,32 +47,41 @@ public class RegisterArg extends InsnArg implements Named {
this.sVar = sVar;
}
@Override
public void setType(ArgType type) {
if (sVar != null) {
sVar.setType(type);
} else {
throw new JadxRuntimeException("SSA variable equals null");
public String getName() {
if (sVar == null) {
return null;
}
return sVar.getName();
}
public void forceType(ArgType type) {
this.type = type;
}
public String getName() {
return name;
public void setName(String name) {
if (sVar != null) {
sVar.setName(name);
}
}
public boolean isNameEquals(InsnArg arg) {
if (name == null || !(arg instanceof Named)) {
String n = getName();
if (n == null || !(arg instanceof Named)) {
return false;
}
return name.equals(((Named) arg).getName());
return n.equals(((Named) arg).getName());
}
@Override
public void setType(ArgType type) {
if (sVar != null) {
sVar.setType(type);
}
}
public void mergeDebugInfo(ArgType type, String name) {
setType(type);
setName(name);
}
public void setName(String newName) {
this.name = newName;
public void forceType(ArgType type) {
this.type = type;
}
/**
......@@ -113,17 +120,15 @@ public class RegisterArg extends InsnArg implements Named {
@Override
public boolean isThis() {
if ("this".equals(name)) {
if ("this".equals(getName())) {
return true;
}
// maybe it was moved from 'this' register
InsnNode ai = getAssignInsn();
if (ai != null && ai.getType() == InsnType.MOVE) {
InsnArg arg = ai.getArg(0);
if (arg != this
&& arg.isRegister()
&& "this".equals(((RegisterArg) arg).getName())) {
return true;
if (arg != this) {
return arg.isThis();
}
}
return false;
......@@ -196,8 +201,8 @@ public class RegisterArg extends InsnArg implements Named {
if (sVar != null) {
sb.append("_").append(sVar.getVersion());
}
if (name != null) {
sb.append(" '").append(name).append("'");
if (getName() != null) {
sb.append(" '").append(getName()).append("'");
}
sb.append(" ");
sb.append(type);
......
......@@ -9,6 +9,7 @@ public class SSAVar {
private final int regNum;
private final int version;
private VarName varName;
private RegisterArg assign;
private final List<RegisterArg> useList = new ArrayList<RegisterArg>(2);
......@@ -22,7 +23,6 @@ public class SSAVar {
this.assign = assign;
if (assign != null) {
mergeName(assign);
assign.setSVar(this);
}
}
......@@ -52,7 +52,6 @@ public class SSAVar {
}
public void use(RegisterArg arg) {
mergeName(arg);
if (arg.getSVar() != null) {
arg.getSVar().removeUse(arg);
}
......@@ -103,35 +102,27 @@ public class SSAVar {
}
public void setName(String name) {
if (assign != null) {
assign.setName(name);
}
for (int i = 0, useListSize = useList.size(); i < useListSize; i++) {
useList.get(i).setName(name);
if (name != null) {
if (varName == null) {
varName = new VarName();
}
varName.setName(name);
}
}
public void setVariableName(String name) {
setName(name);
if (isUsedInPhi()) {
PhiInsn phi = getUsedInPhi();
phi.getResult().getSVar().setVariableName(name);
for (InsnArg arg : phi.getArguments()) {
if (arg.isRegister()) {
RegisterArg reg = (RegisterArg) arg;
SSAVar sVar = reg.getSVar();
if (sVar != this && !name.equals(reg.getName())) {
sVar.setVariableName(name);
}
}
}
public String getName() {
if (varName == null) {
return null;
}
return varName.getName();
}
public void mergeName(RegisterArg arg) {
if (arg.getName() != null) {
setName(arg.getName());
}
public VarName getVarName() {
return varName;
}
public void setVarName(VarName varName) {
this.varName = varName;
}
@Override
......
......@@ -28,12 +28,4 @@ public abstract class Typed {
public boolean merge(InsnArg arg) {
return merge(arg.getType());
}
public void mergeDebugInfo(RegisterArg arg) {
this.type = arg.getType();
if (this instanceof Named) {
Named n = (Named) this;
n.setName(arg.getName());
}
}
}
package jadx.core.dex.instructions.args;
public class VarName {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
......@@ -15,9 +15,9 @@ import jadx.core.dex.instructions.InsnDecoder;
import jadx.core.dex.instructions.SwitchNode;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.MthParameterArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.nodes.parser.DebugInfoParser;
import jadx.core.dex.nodes.parser.SignatureParser;
import jadx.core.dex.regions.Region;
import jadx.core.dex.trycatch.ExcHandlerAttr;
......@@ -51,7 +51,8 @@ public class MethodNode extends LineAttrNode implements ILoadable {
private final Method methodData;
private int regsCount;
private List<InsnNode> instructions;
private InsnNode[] instructions;
private int debugInfoOffset;
private boolean noCode;
private ArgType retType;
......@@ -92,30 +93,12 @@ public class MethodNode extends LineAttrNode implements ILoadable {
InsnDecoder decoder = new InsnDecoder(this);
decoder.decodeInsns(mthCode);
InsnNode[] insnByOffset = decoder.process();
instructions = new ArrayList<InsnNode>();
for (InsnNode insn : insnByOffset) {
if (insn != null) {
instructions.add(insn);
}
}
((ArrayList<InsnNode>) instructions).trimToSize();
instructions = decoder.process();
initTryCatches(mthCode, insnByOffset);
initJumps(insnByOffset);
initTryCatches(mthCode);
initJumps();
int debugInfoOffset = mthCode.getDebugInfoOffset();
if (debugInfoOffset > 0) {
DebugInfoParser debugInfoParser = new DebugInfoParser(this, debugInfoOffset, insnByOffset);
debugInfoParser.process();
if (instructions.size() != 0) {
int line = instructions.get(0).getSourceLine();
if (line != 0) {
this.setSourceLine(line - 1);
}
}
}
this.debugInfoOffset = mthCode.getDebugInfoOffset();
} catch (Exception e) {
if (!noCode) {
noCode = true;
......@@ -139,9 +122,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
if (noCode) {
return;
}
if (instructions != null) {
instructions.clear();
}
instructions = null;
blocks = null;
exitBlocks = null;
exceptionHandlers.clear();
......@@ -199,8 +180,9 @@ public class MethodNode extends LineAttrNode implements ILoadable {
if (accFlags.isStatic()) {
thisArg = null;
} else {
thisArg = InsnArg.parameterReg(pos - 1, parentClass.getClassInfo().getType());
thisArg.setName("this");
MthParameterArg arg = InsnArg.parameterReg(pos - 1, parentClass.getClassInfo().getType());
arg.markAsThis();
thisArg = arg;
}
if (args.isEmpty()) {
argsList = Collections.emptyList();
......@@ -241,7 +223,8 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return genericMap;
}
private void initTryCatches(Code mthCode, InsnNode[] insnByOffset) {
private void initTryCatches(Code mthCode) {
InsnNode[] insnByOffset = instructions;
CatchHandler[] catchBlocks = mthCode.getCatchHandlers();
Try[] tries = mthCode.getTries();
......@@ -311,9 +294,13 @@ public class MethodNode extends LineAttrNode implements ILoadable {
}
}
private void initJumps(InsnNode[] insnByOffset) {
for (InsnNode insn : getInstructions()) {
int offset = insn.getOffset();
private void initJumps() {
InsnNode[] insnByOffset = instructions;
for (int offset = 0; offset < insnByOffset.length; offset++) {
InsnNode insn = insnByOffset[offset];
if (insn == null) {
continue;
}
switch (insn.getType()) {
case SWITCH: {
SwitchNode sw = (SwitchNode) insn;
......@@ -367,20 +354,20 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return noCode;
}
public List<InsnNode> getInstructions() {
public InsnNode[] getInstructions() {
return instructions;
}
public void unloadInsnArr() {
this.instructions = null;
}
public void initBasicBlocks() {
blocks = new ArrayList<BlockNode>();
exitBlocks = new ArrayList<BlockNode>(1);
}
public void finishBasicBlocks() {
// after filling basic blocks we don't need instructions list anymore
instructions.clear();
instructions = null;
((ArrayList<BlockNode>) blocks).trimToSize();
((ArrayList<BlockNode>) exitBlocks).trimToSize();
......@@ -479,6 +466,10 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return regsCount;
}
public int getDebugInfoOffset() {
return debugInfoOffset;
}
public SSAVar makeNewSVar(int regNum, int[] versions, RegisterArg arg) {
SSAVar var = new SSAVar(regNum, versions[regNum], arg);
versions[regNum]++;
......
......@@ -226,19 +226,18 @@ public class DebugInfoParser {
}
private static void fillLocals(InsnNode insn, LocalVar var) {
if (insn.getResult() != null) {
merge(insn.getResult(), var);
}
merge(insn.getResult(), var);
for (InsnArg arg : insn.getArguments()) {
merge(arg, var);
}
}
private static void merge(InsnArg arg, LocalVar var) {
if (arg != null
&& arg.isRegister()
&& var.getRegNum() == ((RegisterArg) arg).getRegNum()) {
arg.mergeDebugInfo(var);
if (arg != null && arg.isRegister()) {
RegisterArg reg = (RegisterArg) arg;
if (var.getRegNum() == reg.getRegNum()) {
reg.mergeDebugInfo(var.getType(), var.getName());
}
}
}
}
......@@ -8,17 +8,19 @@ import jadx.core.utils.InsnUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class LocalVar extends RegisterArg {
final class LocalVar {
private static final Logger LOG = LoggerFactory.getLogger(LocalVar.class);
private boolean isEnd;
private int regNum;
private String name;
private ArgType type;
private boolean isEnd;
private int startAddr;
private int endAddr;
public LocalVar(DexNode dex, int rn, int nameId, int typeId, int signId) {
super(rn, ArgType.UNKNOWN);
this.regNum = rn;
String name = (nameId == DexNode.NO_INDEX ? null : dex.getString(nameId));
ArgType type = (typeId == DexNode.NO_INDEX ? null : dex.getType(typeId));
String sign = (signId == DexNode.NO_INDEX ? null : dex.getString(signId));
......@@ -27,7 +29,7 @@ final class LocalVar extends RegisterArg {
}
public LocalVar(RegisterArg arg) {
super(arg.getRegNum(), arg.getType());
this.regNum = arg.getRegNum();
init(arg.getName(), arg.getType(), null);
}
......@@ -42,8 +44,8 @@ final class LocalVar extends RegisterArg {
LOG.error("Can't parse signature for local variable: " + sign, e);
}
}
setName(name);
forceType(type);
this.name = name;
this.type = type;
}
private boolean checkSignature(ArgType type, String sign, ArgType gType) {
......@@ -72,6 +74,18 @@ final class LocalVar extends RegisterArg {
this.endAddr = addr;
}
public int getRegNum() {
return regNum;
}
public String getName() {
return name;
}
public ArgType getType() {
return type;
}
public boolean isEnd() {
return isEnd;
}
......
......@@ -60,6 +60,9 @@ public class BlockMakerVisitor extends AbstractVisitor {
// split into blocks
for (InsnNode insn : mth.getInstructions()) {
if (insn == null) {
continue;
}
boolean startNew = false;
if (prevInsn != null) {
InsnType type = prevInsn.getType();
......@@ -443,10 +446,18 @@ public class BlockMakerVisitor extends AbstractVisitor {
if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) {
return false;
}
boolean first = true;
for (BlockNode pred : preds) {
BlockNode newRetBlock = startNewBlock(mth, exitBlock.getStartOffset());
newRetBlock.add(AFlag.SYNTHETIC);
newRetBlock.getInstructions().add(duplicateReturnInsn(returnInsn));
InsnNode newRetInsn;
if (first) {
newRetInsn = returnInsn;
first = false;
} else {
newRetInsn = duplicateReturnInsn(returnInsn);
}
newRetBlock.getInstructions().add(newRetInsn);
removeConnection(pred, exitBlock);
connect(pred, newRetBlock);
}
......
package jadx.core.dex.visitors;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.parser.DebugInfoParser;
import jadx.core.utils.exceptions.JadxException;
public class DebugInfoVisitor extends AbstractVisitor {
@Override
public void visit(MethodNode mth) throws JadxException {
int debugOffset = mth.getDebugInfoOffset();
if (debugOffset > 0) {
InsnNode[] insnArr = mth.getInstructions();
DebugInfoParser debugInfoParser = new DebugInfoParser(mth, debugOffset, insnArr);
debugInfoParser.process();
if (insnArr.length != 0) {
int line = insnArr[0].getSourceLine();
if (line != 0) {
mth.setSourceLine(line - 1);
}
}
if (!mth.getReturnType().equals(ArgType.VOID)
&& mth.getExitBlocks().size() > 1) {
// fix debug for splitter 'return' instructions
for (BlockNode exit : mth.getExitBlocks()) {
InsnNode ret = exit.getInstructions().get(0);
InsnNode oldRet = insnArr[ret.getOffset()];
if (oldRet != ret) {
RegisterArg oldArg = (RegisterArg) oldRet.getArg(0);
RegisterArg newArg = (RegisterArg) ret.getArg(0);
newArg.mergeDebugInfo(oldArg.getType(), oldArg.getName());
ret.setSourceLine(oldRet.getSourceLine());
}
}
}
}
mth.unloadInsnArr();
}
}
......@@ -211,7 +211,9 @@ public class DotGraphVisitor extends AbstractVisitor {
return str.toString();
} else {
CodeWriter code = new CodeWriter();
MethodGen.addFallbackInsns(code, mth, block.getInstructions(), false);
List<InsnNode> instructions = block.getInstructions();
MethodGen.addFallbackInsns(code, mth,
instructions.toArray(new InsnNode[instructions.size()]), false);
String str = escape(code.newLine().toString());
if (str.startsWith(NL)) {
str = str.substring(NL.length());
......
......@@ -14,6 +14,9 @@ public class FallbackModeVisitor extends AbstractVisitor {
return;
}
for (InsnNode insn : mth.getInstructions()) {
if (insn == null) {
continue;
}
// remove 'exception catch' for instruction which don't throw any exceptions
CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK);
if (catchAttr != null) {
......
......@@ -5,6 +5,7 @@ import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.DeclareVariablesAttr;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.VarName;
import jadx.core.dex.nodes.IBlock;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
......@@ -66,6 +67,7 @@ public class ProcessVariables extends AbstractVisitor {
private static class Usage {
private RegisterArg arg;
private VarName varName;
private IRegion argRegion;
private final Set<IRegion> usage = new HashSet<IRegion>(2);
private final Set<IRegion> assigns = new HashSet<IRegion>(2);
......@@ -78,6 +80,14 @@ public class ProcessVariables extends AbstractVisitor {
return arg;
}
public VarName getVarName() {
return varName;
}
public void setVarName(VarName varName) {
this.varName = varName;
}
public void setArgRegion(IRegion argRegion) {
this.argRegion = argRegion;
}
......@@ -102,7 +112,14 @@ public class ProcessVariables extends AbstractVisitor {
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>();
for (RegisterArg arg : mth.getArguments(true)) {
addToUsageMap(arg, usageMap);
}
// collect all variables usage
IRegionVisitor collect = new TracedRegionVisitor() {
......@@ -210,6 +227,17 @@ public class ProcessVariables extends AbstractVisitor {
usage = new Usage();
usageMap.put(varId, usage);
}
// merge variables names
if (usage.getVarName() == null) {
VarName argVN = arg.getSVar().getVarName();
if (argVN == null) {
argVN = new VarName();
arg.getSVar().setVarName(argVN);
}
usage.setVarName(argVN);
} else {
arg.getSVar().setVarName(usage.getVarName());
}
return usage;
}
......
......@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.ssa;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.PhiListAttr;
import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
......@@ -19,56 +18,9 @@ public class EliminatePhiNodes extends AbstractVisitor {
if (mth.isNoCode()) {
return;
}
enumerateSVars(mth);
removePhiInstructions(mth);
}
public static void enumerateSVars(MethodNode mth) {
for (SSAVar sVar : mth.getSVars()) {
if (sVar.isUsedInPhi()) {
sVar.mergeName(sVar.getUsedInPhi().getResult());
}
}
}
// public static void enumerateSVars(MethodNode mth) {
// List<SSAVar> vars = mth.getSVars();
// int varsSize = vars.size();
// Deque<SSAVar> workList = new LinkedList<SSAVar>();
// for (int i = 0; i < varsSize; i++) {
// SSAVar ssaVar = vars.get(i);
// ssaVar.setVarId(i);
// if (ssaVar.isUsedInPhi()) {
// workList.add(ssaVar);
// }
// }
//
// int k = 0;
// while (!workList.isEmpty()) {
// SSAVar var = workList.pop();
// RegisterArg assignVar = var.getUsedInPhi().getResult();
// // set same name and variable ID
// var.mergeName(assignVar);
// SSAVar assignSVar = assignVar.getSVar();
// int varId = assignSVar.getVarId();
// var.setVarId(varId);
//
// if (assignSVar.isUsedInPhi()) {
// PhiInsn assignPhi = assignSVar.getUsedInPhi();
// SSAVar asVar = assignPhi.getResult().getSVar();
// if (asVar.getVarId() != varId) {
// asVar.setVarId(varId);
// for (int i = 0; i < assignPhi.getArgsCount(); i++) {
// workList.push(assignPhi.getArg(i).getSVar());
// }
// }
// }
// if (k++ > 1000) {
// throw new JadxRuntimeException("Can't calculate variable id");
// }
// }
// }
private static void removePhiInstructions(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
PhiListAttr phiList = block.get(AType.PHI_LIST);
......
......@@ -32,7 +32,7 @@ public class SSATransform extends AbstractVisitor {
process(mth);
}
public void process(MethodNode mth) {
private void process(MethodNode mth) {
LiveVarAnalysis la = new LiveVarAnalysis(mth);
la.runAnalysis();
for (int i = 0; i < mth.getRegsCount(); i++) {
......
......@@ -82,7 +82,7 @@ public class TypeInference extends AbstractVisitor {
for (int i = 0; i < phi.getArgsCount(); i++) {
RegisterArg arg = phi.getArg(i);
arg.setType(type);
arg.getSVar().mergeName(phi.getResult());
arg.getSVar().setName(phi.getResult().getName());
}
}
......
......@@ -31,8 +31,8 @@ public class TestInline2 extends InternalJadxTest {
System.out.println(code);
assertThat(code, containsString("i < a.length"));
assertThat(code, containsString("long i_2 ="));
assertThat(code, containsString("+ i_2"));
assertThat(code, containsString("i_2--;"));
assertThat(code, containsString("long i2 ="));
assertThat(code, containsString("+ i2"));
assertThat(code, containsString("i2--;"));
}
}
......@@ -36,8 +36,9 @@ public abstract class AbstractTest {
public static void assertEquals(Object a1, Object a2) {
if (a1 == null) {
if (a2 != null)
if (a2 != null) {
throw new AssertionError(a1 + " != " + a2);
}
} else if (!a1.equals(a2)) {
throw new AssertionError(a1 + " != " + a2);
}
......
......@@ -50,7 +50,7 @@ public class TestAnnotations extends AbstractTest {
@MyAnnotation(name = "b",
num = 7,
cls = Exception.class,
doubles = { 0.0, 1.1 },
doubles = {0.0, 1.1},
value = 9.87f,
simple = @SimpleAnnotation(false))
public static Object test(String[] a) {
......
......@@ -22,10 +22,11 @@ public class TestCF extends AbstractTest {
public int test1b(int a) {
if (a > 0) {
if (a < 5)
if (a < 5) {
a++;
else
} else {
a -= 2;
}
}
a *= 2;
return a + 3;
......@@ -134,16 +135,17 @@ public class TestCF extends AbstractTest {
public int testIfElse(String str) {
int r;
if (str.equals("a"))
if (str.equals("a")) {
r = 1;
else if (str.equals("b"))
} else if (str.equals("b")) {
r = 2;
else if (str.equals("3"))
} else if (str.equals("3")) {
r = 3;
else if (str.equals("$"))
} else if (str.equals("$")) {
r = 4;
else
} else {
r = -1;
}
r = r * 10;
return Math.abs(r);
......
......@@ -5,7 +5,7 @@ public class TestCF2 extends AbstractTest {
private boolean ready = false;
public int simple_loops() throws InterruptedException {
int[] a = new int[] { 1, 2, 4, 6, 8 };
int[] a = new int[]{1, 2, 4, 6, 8};
int b = 0;
for (int i = 0; i < a.length; i++) {
b += a[i];
......@@ -21,8 +21,9 @@ public class TestCF2 extends AbstractTest {
*/
public void run() throws InterruptedException {
while (true) {
if (!ready)
if (!ready) {
ready_mutex.wait();
}
ready = false;
func();
}
......@@ -88,8 +89,9 @@ public class TestCF2 extends AbstractTest {
public void do_while_return2(boolean k) throws InterruptedException {
int i = 3;
do {
if (k)
if (k) {
return;
}
i++;
} while (i < 5);
}
......
......@@ -3,8 +3,9 @@ package jadx.samples;
public class TestDeadCode extends AbstractTest {
private void test1(int i) {
if (i == 0)
if (i == 0) {
return;
}
return;
}
......
......@@ -77,7 +77,7 @@ public class TestGenerics extends AbstractTest {
public static boolean use() {
Pair<Integer, String> p1 = new OrderedPair<Integer, String>(1, "str1");
Pair<Integer, String> p2 = new OrderedPair<Integer, String>(2, "str2");
boolean same = Util.<Integer, String> compare(p1, p2);
boolean same = Util.<Integer, String>compare(p1, p2);
return same;
}
......@@ -107,9 +107,11 @@ public class TestGenerics extends AbstractTest {
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
for (T e : anArray) {
if (e.compareTo(elem) > 0) {
++count;
}
}
return count;
}
......@@ -117,8 +119,9 @@ public class TestGenerics extends AbstractTest {
}
public static void printList(List<?> list) {
for (Object elem : list)
for (Object elem : list) {
System.out.print(elem + " ");
}
System.out.println();
}
......
......@@ -56,6 +56,7 @@ public class TestInner extends AbstractTest {
{
count += 5;
}
@Override
public void run() {
count += 6;
......@@ -68,6 +69,7 @@ public class TestInner extends AbstractTest {
{
count += 7;
}
@Override
public String toString() {
count += 8;
......
......@@ -73,7 +73,7 @@ public class TestInner2 extends AbstractTest {
Method[] mths = TestInner2.class.getDeclaredMethods();
for (Method mth : mths) {
if(mth.getName().startsWith("access$")) {
if (mth.getName().startsWith("access$")) {
int modifiers = mth.getModifiers();
assertTrue((modifiers & SYNTHETIC) != 0, "Synthetic methods must be removed");
}
......
......@@ -14,10 +14,11 @@ public class TestInvoke extends AbstractTest {
}
private void parse(String[] args) {
if (args.length > 0)
if (args.length > 0) {
f = Integer.parseInt(args[0]);
else
} else {
f = 20;
}
}
public int getF() {
......@@ -37,18 +38,26 @@ public class TestInvoke extends AbstractTest {
return s;
}
private String testSameArgTypes(String s1, String s2) {
if (s1.equals(s2)) {
return null;
}
return s1;
}
@Override
public boolean testRun() throws Exception {
TestInvoke inv = new TestInvoke();
inv.parse(new String[] { "12", "35" });
inv.parse(new String[]{"12", "35"});
assertTrue(inv.getF() == 12);
inv.parse(new String[0]);
assertTrue(inv.getF() == 20);
assertTrue(inv.testVarArgs("a", "2", "III"));
assertTrue(inv.testVarArgs2("a".toCharArray(), new char[] { '1', '2' }).equals("a12"));
assertTrue(inv.testVarArgs2("a".toCharArray(), new char[]{'1', '2'}).equals("a12"));
assertEquals(testSameArgTypes("a", "b"), "a");
return true;
}
......
......@@ -43,10 +43,11 @@ public class TestSwitch extends AbstractTest {
int k = i;
switch (k) {
case 1:
if (j == 0)
if (j == 0) {
return 0;
else
} else {
return -1;
}
case 2:
return 1;
}
......@@ -69,8 +70,9 @@ public class TestSwitch extends AbstractTest {
int k = i;
switch (k) {
case 1:
if (b == 0)
if (b == 0) {
return 3;
}
case 2:
b++;
......
......@@ -5,14 +5,16 @@ import java.io.IOException;
public class TestTryCatch extends AbstractTest {
private static boolean exc(Object obj) throws Exception {
if (obj == null)
if (obj == null) {
throw new Exception("test");
}
return (obj instanceof Object);
}
private static boolean exc2(Object obj) throws IOException {
if (obj == null)
if (obj == null) {
throw new IOException();
}
return true;
}
......@@ -41,10 +43,11 @@ public class TestTryCatch extends AbstractTest {
try {
return exc(obj);
} catch (Exception e) {
if (obj != null)
if (obj != null) {
return true;
else
} else {
return false;
}
}
}
......@@ -78,8 +81,9 @@ public class TestTryCatch extends AbstractTest {
try {
res = "" + exc(obj);
boolean f = exc2("a");
if (!f)
if (!f) {
res = "f == false";
}
} catch (Exception e) {
res = "exc";
}
......@@ -95,8 +99,9 @@ public class TestTryCatch extends AbstractTest {
} catch (IOException e) {
res = true;
} catch (Throwable e) {
if (obj == null)
if (obj == null) {
obj = new Object();
}
}
}
}
......@@ -112,8 +117,9 @@ public class TestTryCatch extends AbstractTest {
res = true;
obj = new Object();
} catch (Throwable e) {
if (obj == null)
if (obj == null) {
res = false;
}
}
}
}
......@@ -137,16 +143,18 @@ public class TestTryCatch extends AbstractTest {
} catch (Exception e) {
e.toString();
} finally {
if (!mDiscovering)
if (!mDiscovering) {
mDiscovering = true;
}
}
return mDiscovering;
}
private static boolean testSynchronize(Object obj) throws InterruptedException {
synchronized (obj) {
if (obj instanceof String)
if (obj instanceof String) {
return false;
}
obj.wait(5);
}
return true;
......@@ -171,8 +179,9 @@ public class TestTryCatch extends AbstractTest {
public int catchInLoop(int i, int j) {
while (true) {
try {
while (i < j)
while (i < j) {
i = j++ / i;
}
} catch (RuntimeException e) {
i = 10;
continue;
......
......@@ -7,7 +7,7 @@ package jadx.samples;
*/
public class TestTypeResolver2 extends AbstractTest {
private static String result = "";
private static String result = "";
public void testOverloadedMethods() {
Object s1 = "The";
......
rootProject.name = 'jadx'
include 'jadx-core', 'jadx-samples', 'jadx-cli', 'jadx-gui'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment