Commit cb6ff606 authored by Skylot's avatar Skylot

Fix small issues and improve code

parent 26800fb7
...@@ -18,8 +18,6 @@ public interface IJadxArgs { ...@@ -18,8 +18,6 @@ public interface IJadxArgs {
boolean isFallbackMode(); boolean isFallbackMode();
boolean isNotObfuscated();
boolean isVerbose(); boolean isVerbose();
boolean isPrintHelp(); boolean isPrintHelp();
......
...@@ -33,9 +33,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -33,9 +33,6 @@ public class JadxArgs implements IJadxArgs {
@Parameter(names = {"-f", "--fallback"}, description = "make simple dump (using goto instead of 'if', 'for', etc)", help = true) @Parameter(names = {"-f", "--fallback"}, description = "make simple dump (using goto instead of 'if', 'for', etc)", help = true)
protected boolean fallbackMode = false; protected boolean fallbackMode = false;
@Parameter(names = {"--not-obfuscated"}, description = "set this flag if code not obfuscated")
protected boolean notObfuscated = false;
@Parameter(names = {"--cfg"}, description = "save methods control flow graph") @Parameter(names = {"--cfg"}, description = "save methods control flow graph")
protected boolean cfgOutput = false; protected boolean cfgOutput = false;
...@@ -178,11 +175,6 @@ public class JadxArgs implements IJadxArgs { ...@@ -178,11 +175,6 @@ public class JadxArgs implements IJadxArgs {
} }
@Override @Override
public boolean isNotObfuscated() {
return notObfuscated;
}
@Override
public boolean isVerbose() { public boolean isVerbose() {
return verbose; return verbose;
} }
......
...@@ -82,6 +82,9 @@ public class ClassGen { ...@@ -82,6 +82,9 @@ public class ClassGen {
if (cls.getAttributes().contains(AttributeFlag.DONT_GENERATE)) if (cls.getAttributes().contains(AttributeFlag.DONT_GENERATE))
return; return;
if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE))
code.startLine("// jadx: inconsistent code");
makeClassDeclaration(code); makeClassDeclaration(code);
makeClassBody(code); makeClassBody(code);
code.endl(); code.endl();
...@@ -124,7 +127,7 @@ public class ClassGen { ...@@ -124,7 +127,7 @@ public class ClassGen {
else else
clsCode.add("implements "); clsCode.add("implements ");
for (Iterator<ClassInfo> it = cls.getInterfaces().iterator(); it.hasNext();) { for (Iterator<ClassInfo> it = cls.getInterfaces().iterator(); it.hasNext(); ) {
ClassInfo interf = it.next(); ClassInfo interf = it.next();
clsCode.add(useClass(interf)); clsCode.add(useClass(interf));
if (it.hasNext()) if (it.hasNext())
...@@ -150,7 +153,7 @@ public class ClassGen { ...@@ -150,7 +153,7 @@ public class ClassGen {
code.add(useClass(type)); code.add(useClass(type));
if (list != null && !list.isEmpty()) { if (list != null && !list.isEmpty()) {
code.add(" extends "); code.add(" extends ");
for (Iterator<ArgType> it = list.iterator(); it.hasNext();) { for (Iterator<ArgType> it = list.iterator(); it.hasNext(); ) {
ArgType g = it.next(); ArgType g = it.next();
code.add(useClass(g)); code.add(useClass(g));
if (it.hasNext()) { if (it.hasNext()) {
...@@ -167,11 +170,16 @@ public class ClassGen { ...@@ -167,11 +170,16 @@ public class ClassGen {
public void makeClassBody(CodeWriter clsCode) throws CodegenException { public void makeClassBody(CodeWriter clsCode) throws CodegenException {
clsCode.add('{'); clsCode.add('{');
CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods()); CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods());
clsCode.add(makeFields(clsCode, cls, cls.getFields())); CodeWriter fieldsCode = makeFields(clsCode, cls, cls.getFields());
clsCode.add(fieldsCode);
if (fieldsCode.notEmpty() && mthsCode.notEmpty())
clsCode.endl();
// insert inner classes code // insert inner classes code
if (cls.getInnerClasses().size() != 0) { if (cls.getInnerClasses().size() != 0) {
clsCode.add(makeInnerClasses(cls, clsCode.getIndent())); clsCode.add(makeInnerClasses(cls, clsCode.getIndent()));
if (mthsCode.notEmpty())
clsCode.endl();
} }
clsCode.add(mthsCode); clsCode.add(mthsCode);
clsCode.startLine('}'); clsCode.startLine('}');
...@@ -192,7 +200,7 @@ public class ClassGen { ...@@ -192,7 +200,7 @@ public class ClassGen {
private CodeWriter makeMethods(CodeWriter clsCode, List<MethodNode> mthList) { private CodeWriter makeMethods(CodeWriter clsCode, List<MethodNode> mthList) {
CodeWriter code = new CodeWriter(clsCode.getIndent() + 1); CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
for (Iterator<MethodNode> it = mthList.iterator(); it.hasNext();) { for (Iterator<MethodNode> it = mthList.iterator(); it.hasNext(); ) {
MethodNode mth = it.next(); MethodNode mth = it.next();
if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE))
continue; continue;
...@@ -235,16 +243,19 @@ public class ClassGen { ...@@ -235,16 +243,19 @@ public class ClassGen {
EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS); EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS);
if (enumFields != null) { if (enumFields != null) {
MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod()); InsnGen igen = null;
InsnGen igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false); for (Iterator<EnumField> it = enumFields.getFields().iterator(); it.hasNext(); ) {
for (Iterator<EnumField> it = enumFields.getFields().iterator(); it.hasNext();) {
EnumField f = it.next(); EnumField f = it.next();
code.startLine(f.getName()); code.startLine(f.getName());
if (f.getArgs().size() != 0) { if (f.getArgs().size() != 0) {
code.add('('); code.add('(');
for (Iterator<InsnArg> aIt = f.getArgs().iterator(); aIt.hasNext();) { for (Iterator<InsnArg> aIt = f.getArgs().iterator(); aIt.hasNext(); ) {
InsnArg arg = aIt.next(); InsnArg arg = aIt.next();
if (igen == null) {
// don't init mth gen if this is simple enum
MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod());
igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false);
}
code.add(igen.arg(arg)); code.add(igen.arg(arg));
if (aIt.hasNext()) if (aIt.hasNext())
code.add(", "); code.add(", ");
...@@ -281,8 +292,6 @@ public class ClassGen { ...@@ -281,8 +292,6 @@ public class ClassGen {
} }
code.add(';'); code.add(';');
} }
if (fields.size() != 0)
code.endl();
return code; return code;
} }
...@@ -290,11 +299,11 @@ public class ClassGen { ...@@ -290,11 +299,11 @@ public class ClassGen {
if (clsType.isGenericType()) { if (clsType.isGenericType()) {
return clsType.getObject(); return clsType.getObject();
} }
return useClass(ClassInfo.fromType(cls.dex(), clsType)); return useClass(ClassInfo.fromType(clsType));
} }
public String useClass(ClassInfo classInfo) { public String useClass(ClassInfo classInfo) {
String baseClass = useClassInner(classInfo); String baseClass = useClassInternal(classInfo);
ArgType[] generics = classInfo.getType().getGenericTypes(); ArgType[] generics = classInfo.getType().getGenericTypes();
if (generics != null) { if (generics != null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
...@@ -318,9 +327,9 @@ public class ClassGen { ...@@ -318,9 +327,9 @@ public class ClassGen {
} }
} }
private String useClassInner(ClassInfo classInfo) { private String useClassInternal(ClassInfo classInfo) {
if (parentGen != null) if (parentGen != null)
return parentGen.useClassInner(classInfo); return parentGen.useClassInternal(classInfo);
String clsStr = classInfo.getFullName(); String clsStr = classInfo.getFullName();
if (fallback) if (fallback)
......
...@@ -133,6 +133,10 @@ public class CodeWriter { ...@@ -133,6 +133,10 @@ public class CodeWriter {
} }
} }
public boolean notEmpty() {
return buf.length() != 0;
}
@Override @Override
public String toString() { public String toString() {
return buf.toString(); return buf.toString();
...@@ -183,5 +187,4 @@ public class CodeWriter { ...@@ -183,5 +187,4 @@ public class CodeWriter {
throw new JadxRuntimeException("Can't create directory " + dir); throw new JadxRuntimeException("Can't create directory " + dir);
} }
} }
} }
...@@ -13,13 +13,6 @@ public final class ClassInfo { ...@@ -13,13 +13,6 @@ public final class ClassInfo {
private static final Map<ArgType, ClassInfo> CLASSINFO_CACHE = new WeakHashMap<ArgType, ClassInfo>(); private static final Map<ArgType, ClassInfo> CLASSINFO_CACHE = new WeakHashMap<ArgType, ClassInfo>();
private static final String DEFAULT_PACKAGE_NAME = "defpackage"; private static final String DEFAULT_PACKAGE_NAME = "defpackage";
private final String clsName;
private final String clsPackage;
private final ArgType type;
private final String fullName;
private final ClassInfo parentClass; // not equals null if this is inner class
public static ClassInfo fromDex(DexNode dex, int clsIndex) { public static ClassInfo fromDex(DexNode dex, int clsIndex) {
if (clsIndex == DexNode.NO_INDEX) if (clsIndex == DexNode.NO_INDEX)
return null; return null;
...@@ -28,17 +21,17 @@ public final class ClassInfo { ...@@ -28,17 +21,17 @@ public final class ClassInfo {
if (type.isArray()) if (type.isArray())
type = ArgType.OBJECT; type = ArgType.OBJECT;
return fromType(dex, type); return fromType(type);
} }
public static ClassInfo fromName(DexNode dex, String clsName) { public static ClassInfo fromName(String clsName) {
return fromType(dex, ArgType.object(clsName)); return fromType(ArgType.object(clsName));
} }
public static ClassInfo fromType(DexNode dex, ArgType type) { public static ClassInfo fromType(ArgType type) {
ClassInfo cls = CLASSINFO_CACHE.get(type); ClassInfo cls = CLASSINFO_CACHE.get(type);
if (cls == null) { if (cls == null) {
cls = new ClassInfo(dex, type); cls = new ClassInfo(type);
CLASSINFO_CACHE.put(type, cls); CLASSINFO_CACHE.put(type, cls);
} }
return cls; return cls;
...@@ -48,21 +41,28 @@ public final class ClassInfo { ...@@ -48,21 +41,28 @@ public final class ClassInfo {
CLASSINFO_CACHE.clear(); CLASSINFO_CACHE.clear();
} }
private ClassInfo(DexNode dex, ArgType type) { private final ArgType type;
private String pkg;
private String name;
private String fullName;
private ClassInfo parentClass; // not equals null if this is inner class
private ClassInfo(ArgType type) {
assert type.isObject() : "Not class type: " + type; assert type.isObject() : "Not class type: " + type;
this.type = type; this.type = type;
splitNames(true);
}
private void splitNames(boolean canBeInner) {
String fullObjectName = type.getObject(); String fullObjectName = type.getObject();
assert fullObjectName.indexOf('/') == -1 : "Raw type: " + type; assert fullObjectName.indexOf('/') == -1 : "Raw type: " + type;
boolean notObfuscated = dex.root().getJadxArgs().isNotObfuscated();
String name; String name;
String pkg;
int dot = fullObjectName.lastIndexOf('.'); int dot = fullObjectName.lastIndexOf('.');
if (dot == -1) { if (dot == -1) {
// rename default package if it used from class with package (often for obfuscated apps), // rename default package if it used from class with package (often for obfuscated apps),
pkg = (notObfuscated ? "" : DEFAULT_PACKAGE_NAME); pkg = DEFAULT_PACKAGE_NAME;
name = fullObjectName; name = fullObjectName;
} else { } else {
pkg = fullObjectName.substring(0, dot); pkg = fullObjectName.substring(0, dot);
...@@ -70,27 +70,30 @@ public final class ClassInfo { ...@@ -70,27 +70,30 @@ public final class ClassInfo {
} }
int sep = name.lastIndexOf('$'); int sep = name.lastIndexOf('$');
if (sep > 0 && sep != name.length() - 1) { if (canBeInner && sep > 0 && sep != name.length() - 1) {
String parClsName = pkg + '.' + name.substring(0, sep); String parClsName = pkg + '.' + name.substring(0, sep);
parentClass = fromName(dex, parClsName); parentClass = fromName(parClsName);
name = name.substring(sep + 1); name = name.substring(sep + 1);
} else { } else {
parentClass = null; parentClass = null;
} }
if (Character.isDigit(name.charAt(0))) char firstChar = name.charAt(0);
if (Character.isDigit(firstChar)) {
name = "InnerClass_" + name; name = "InnerClass_" + name;
} else if(firstChar == '$') {
if (NameMapper.isReserved(name)) name = "_" + name;
}
if (NameMapper.isReserved(name)) {
name += "_"; name += "_";
}
this.fullName = (parentClass != null ? parentClass.getFullName() : pkg) + "." + name; this.fullName = (parentClass != null ? parentClass.getFullName() : pkg) + "." + name;
this.clsName = name; this.name = name;
this.clsPackage = pkg;
} }
public String getFullPath() { public String getFullPath() {
return clsPackage.replace('.', File.separatorChar) + File.separatorChar return pkg.replace('.', File.separatorChar)
+ File.separatorChar
+ getNameWithoutPackage().replace('.', '_'); + getNameWithoutPackage().replace('.', '_');
} }
...@@ -99,19 +102,19 @@ public final class ClassInfo { ...@@ -99,19 +102,19 @@ public final class ClassInfo {
} }
public String getShortName() { public String getShortName() {
return clsName; return name;
} }
public String getPackage() { public String getPackage() {
return clsPackage; return pkg;
} }
public boolean isPackageDefault() { public boolean isPackageDefault() {
return clsPackage.isEmpty() || clsPackage.equals(DEFAULT_PACKAGE_NAME); return pkg.isEmpty() || pkg.equals(DEFAULT_PACKAGE_NAME);
} }
public String getNameWithoutPackage() { public String getNameWithoutPackage() {
return (parentClass != null ? parentClass.getNameWithoutPackage() + "." : "") + clsName; return (parentClass != null ? parentClass.getNameWithoutPackage() + "." : "") + name;
} }
public ClassInfo getParentClass() { public ClassInfo getParentClass() {
...@@ -122,6 +125,10 @@ public final class ClassInfo { ...@@ -122,6 +125,10 @@ public final class ClassInfo {
return parentClass != null; return parentClass != null;
} }
public void notInner() {
splitNames(false);
}
public ArgType getType() { public ArgType getType() {
return type; return type;
} }
...@@ -133,7 +140,7 @@ public final class ClassInfo { ...@@ -133,7 +140,7 @@ public final class ClassInfo {
@Override @Override
public int hashCode() { public int hashCode() {
return this.getFullName().hashCode(); return type.hashCode();
} }
@Override @Override
......
...@@ -77,6 +77,10 @@ public class TypedVar { ...@@ -77,6 +77,10 @@ public class TypedVar {
@Override @Override
public String toString() { public String toString() {
return (name != null ? "'" + name + "' " : "") + type.toString(); StringBuilder sb = new StringBuilder();
if(name != null)
sb.append('\'').append(name).append("' ");
sb.append(type);
return sb.toString();
} }
} }
...@@ -19,6 +19,7 @@ public class BlockNode extends AttrNode implements IBlock { ...@@ -19,6 +19,7 @@ public class BlockNode extends AttrNode implements IBlock {
private List<BlockNode> predecessors = new ArrayList<BlockNode>(1); private List<BlockNode> predecessors = new ArrayList<BlockNode>(1);
private List<BlockNode> successors = new ArrayList<BlockNode>(1); private List<BlockNode> successors = new ArrayList<BlockNode>(1);
private List<BlockNode> cleanSuccessors;
private BitSet doms; // all dominators private BitSet doms; // all dominators
private BlockNode idom; // immediate dominator private BlockNode idom; // immediate dominator
...@@ -48,8 +49,6 @@ public class BlockNode extends AttrNode implements IBlock { ...@@ -48,8 +49,6 @@ public class BlockNode extends AttrNode implements IBlock {
return successors; return successors;
} }
private List<BlockNode> cleanSuccessors;
public List<BlockNode> getCleanSuccessors() { public List<BlockNode> getCleanSuccessors() {
return cleanSuccessors; return cleanSuccessors;
} }
......
...@@ -154,10 +154,10 @@ public class ClassNode extends AttrNode implements ILoadable { ...@@ -154,10 +154,10 @@ public class ClassNode extends AttrNode implements ILoadable {
if (list != null && !list.isEmpty()) { if (list != null && !list.isEmpty()) {
try { try {
ArgType st = list.remove(0); ArgType st = list.remove(0);
this.superClass = ClassInfo.fromType(dex, st); this.superClass = ClassInfo.fromType(st);
int i = 0; int i = 0;
for (ArgType it : list) { for (ArgType it : list) {
ClassInfo interf = ClassInfo.fromType(dex, it); ClassInfo interf = ClassInfo.fromType(it);
interfaces.set(i, interf); interfaces.set(i, interf);
i++; i++;
} }
......
...@@ -56,16 +56,16 @@ public class RootNode { ...@@ -56,16 +56,16 @@ public class RootNode {
if (cls.getClassInfo().isInner()) if (cls.getClassInfo().isInner())
inner.add(cls); inner.add(cls);
} }
getClasses().removeAll(inner);
for (ClassNode cls : inner) { for (ClassNode cls : inner) {
ClassNode parent = resolveClass(cls.getClassInfo().getParentClass()); ClassNode parent = resolveClass(cls.getClassInfo().getParentClass());
if (parent == null) if (parent == null) {
LOG.warn("Can't add inner class: {} to {}", cls, cls.getClassInfo().getParentClass()); cls.getClassInfo().notInner();
else } else {
parent.addInnerClass(cls); parent.addInnerClass(cls);
getClasses().remove(cls);
}
} }
inner.clear();
} }
public List<ClassNode> getClasses() { public List<ClassNode> getClasses() {
......
...@@ -159,7 +159,6 @@ public class BlockMakerVisitor extends AbstractVisitor { ...@@ -159,7 +159,6 @@ public class BlockMakerVisitor extends AbstractVisitor {
BlockNode destBlock = getBlock(h.getHandleOffset(), blocksMap); BlockNode destBlock = getBlock(h.getHandleOffset(), blocksMap);
// skip self loop in handler // skip self loop in handler
if (connBlock != destBlock) if (connBlock != destBlock)
// && !connBlock.getPredecessors().contains(destBlock))
connect(connBlock, destBlock); connect(connBlock, destBlock);
} }
} }
...@@ -208,9 +207,10 @@ public class BlockMakerVisitor extends AbstractVisitor { ...@@ -208,9 +207,10 @@ public class BlockMakerVisitor extends AbstractVisitor {
} }
private static void computeDominators(MethodNode mth) { private static void computeDominators(MethodNode mth) {
int nBlocks = mth.getBasicBlocks().size(); List<BlockNode> basicBlocks = mth.getBasicBlocks();
int nBlocks = basicBlocks.size();
for (int i = 0; i < nBlocks; i++) { for (int i = 0; i < nBlocks; i++) {
BlockNode block = mth.getBasicBlocks().get(i); BlockNode block = basicBlocks.get(i);
block.setId(i); block.setId(i);
block.setDoms(new BitSet(nBlocks)); block.setDoms(new BitSet(nBlocks));
block.getDoms().set(0, nBlocks); block.getDoms().set(0, nBlocks);
...@@ -224,7 +224,7 @@ public class BlockMakerVisitor extends AbstractVisitor { ...@@ -224,7 +224,7 @@ public class BlockMakerVisitor extends AbstractVisitor {
boolean changed; boolean changed;
do { do {
changed = false; changed = false;
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : basicBlocks) {
if (block == entryBlock) if (block == entryBlock)
continue; continue;
...@@ -245,35 +245,36 @@ public class BlockMakerVisitor extends AbstractVisitor { ...@@ -245,35 +245,36 @@ public class BlockMakerVisitor extends AbstractVisitor {
markLoops(mth); markLoops(mth);
// clear self dominance // clear self dominance
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : basicBlocks) {
block.getDoms().clear(block.getId()); block.getDoms().clear(block.getId());
} }
// calculate immediate dominators // calculate immediate dominators
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : basicBlocks) {
if (block == entryBlock) if (block == entryBlock)
continue; continue;
if (block.getPredecessors().size() == 1) { List<BlockNode> preds = block.getPredecessors();
block.setIDom(block.getPredecessors().get(0)); if (preds.size() == 1) {
block.setIDom(preds.get(0));
} else { } else {
BitSet bs = new BitSet(block.getDoms().length()); BitSet bs = new BitSet(block.getDoms().length());
bs.or(block.getDoms()); bs.or(block.getDoms());
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
BlockNode dom = mth.getBasicBlocks().get(i); BlockNode dom = basicBlocks.get(i);
bs.andNot(dom.getDoms()); bs.andNot(dom.getDoms());
} }
int c = bs.cardinality(); int c = bs.cardinality();
if (c == 1) { if (c == 1) {
int id = bs.nextSetBit(0); int id = bs.nextSetBit(0);
BlockNode idom = mth.getBasicBlocks().get(id); BlockNode idom = basicBlocks.get(id);
block.setIDom(idom); block.setIDom(idom);
idom.getDominatesOn().add(block); idom.getDominatesOn().add(block);
} else { } else {
throw new JadxRuntimeException("Can't find immediate dominator for block " + block throw new JadxRuntimeException("Can't find immediate dominator for block " + block
+ " in " + bs + " prec:" + block.getPredecessors()); + " in " + bs + " preds:" + preds);
} }
} }
} }
...@@ -298,8 +299,9 @@ public class BlockMakerVisitor extends AbstractVisitor { ...@@ -298,8 +299,9 @@ public class BlockMakerVisitor extends AbstractVisitor {
private static void markReturnBlocks(MethodNode mth) { private static void markReturnBlocks(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
if (block.getInstructions().size() == 1) { List<InsnNode> insns = block.getInstructions();
if (block.getInstructions().get(0).getType() == InsnType.RETURN) if (insns.size() == 1) {
if (insns.get(0).getType() == InsnType.RETURN)
block.getAttributes().add(AttributeFlag.RETURN); block.getAttributes().add(AttributeFlag.RETURN);
} }
} }
......
...@@ -10,6 +10,7 @@ import jadx.dex.nodes.MethodNode; ...@@ -10,6 +10,7 @@ import jadx.dex.nodes.MethodNode;
import jadx.dex.trycatch.CatchAttr; import jadx.dex.trycatch.CatchAttr;
import jadx.dex.trycatch.ExcHandlerAttr; import jadx.dex.trycatch.ExcHandlerAttr;
import jadx.dex.trycatch.ExceptionHandler; import jadx.dex.trycatch.ExceptionHandler;
import jadx.dex.trycatch.TryCatchBlock;
import jadx.utils.BlockUtils; import jadx.utils.BlockUtils;
public class BlockProcessingHelper { public class BlockProcessingHelper {
...@@ -81,8 +82,12 @@ public class BlockProcessingHelper { ...@@ -81,8 +82,12 @@ public class BlockProcessingHelper {
if (insn.getType() == InsnType.THROW) { if (insn.getType() == InsnType.THROW) {
CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK);
if (catchAttr != null) { if (catchAttr != null) {
handlerAttr.getTryBlock().merge(mth, catchAttr.getTryBlock()); TryCatchBlock handlerBlock = handlerAttr.getTryBlock();
catchAttr.getTryBlock().removeInsn(insn); TryCatchBlock catchBlock = catchAttr.getTryBlock();
if (handlerBlock != catchBlock) { // TODO: why it can be?
handlerBlock.merge(mth, catchBlock);
catchBlock.removeInsn(insn);
}
} }
} }
} }
......
...@@ -18,7 +18,7 @@ public class ClassModifier extends AbstractVisitor { ...@@ -18,7 +18,7 @@ public class ClassModifier extends AbstractVisitor {
visit(inner); visit(inner);
} }
for (Iterator<MethodNode> it = cls.getMethods().iterator(); it.hasNext();) { for (Iterator<MethodNode> it = cls.getMethods().iterator(); it.hasNext(); ) {
MethodNode mth = it.next(); MethodNode mth = it.next();
AccessInfo af = mth.getAccessFlags(); AccessInfo af = mth.getAccessFlags();
...@@ -34,17 +34,26 @@ public class ClassModifier extends AbstractVisitor { ...@@ -34,17 +34,26 @@ public class ClassModifier extends AbstractVisitor {
if (af.isConstructor() if (af.isConstructor()
&& af.isPublic() && af.isPublic()
&& mth.getArguments(false).isEmpty()) { && mth.getArguments(false).isEmpty()) {
List<BlockNode> bb = mth.getBasicBlocks(); if (mth.getSuperCall() == null) {
if (bb.isEmpty() || (bb.size() == 1 && bb.get(0).getInstructions().isEmpty())) { List<BlockNode> bb = mth.getBasicBlocks();
if (mth.getSuperCall() == null) if (bb.isEmpty() || allBlocksEmpty(bb)) {
it.remove(); it.remove();
}
} }
} }
} }
return false; return false;
} }
private boolean isMethodUniq(ClassNode cls, MethodNode mth) { private static boolean allBlocksEmpty(List<BlockNode> blocks) {
for (BlockNode block : blocks) {
if (block.getInstructions().size() != 0)
return false;
}
return true;
}
private static boolean isMethodUniq(ClassNode cls, MethodNode mth) {
MethodInfo mi = mth.getMethodInfo(); MethodInfo mi = mth.getMethodInfo();
for (MethodNode otherMth : cls.getMethods()) { for (MethodNode otherMth : cls.getMethods()) {
MethodInfo omi = otherMth.getMethodInfo(); MethodInfo omi = otherMth.getMethodInfo();
......
...@@ -36,24 +36,26 @@ public class CodeShrinker extends AbstractVisitor { ...@@ -36,24 +36,26 @@ public class CodeShrinker extends AbstractVisitor {
private static void shrink(MethodNode mth) { private static void shrink(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
InstructionRemover remover = new InstructionRemover(block.getInstructions()); List<InsnNode> insnList = block.getInstructions();
for (int i = 0; i < block.getInstructions().size(); i++) { InstructionRemover remover = new InstructionRemover(insnList);
InsnNode insn = block.getInstructions().get(i); for (InsnNode insn : insnList) {
// wrap instructions // wrap instructions
if (insn.getResult() != null) { RegisterArg result = insn.getResult();
List<InsnArg> use = insn.getResult().getTypedVar().getUseList(); if (result != null) {
if (use.size() == 1) { List<InsnArg> useList = result.getTypedVar().getUseList();
if (useList.size() == 1) {
// variable is used only in this instruction // variable is used only in this instruction
// TODO not correct sometimes :( // TODO not correct sometimes :(
remover.add(insn); remover.add(insn);
} else if (use.size() == 2) { } else if (useList.size() == 2) {
InsnArg useInsnArg = use.get(1); InsnArg useInsnArg = selectOther(useList, result);
InsnNode useInsn = useInsnArg.getParentInsn(); InsnNode useInsn = useInsnArg.getParentInsn();
if (useInsn == null) { if (useInsn == null) {
LOG.debug("parent insn null in " + useInsnArg + " from " + insn + " mth: " + mth); LOG.debug("parent insn null in " + useInsnArg + " from " + insn + " mth: " + mth);
} else if (useInsn != insn) { } else if (useInsn != insn) {
boolean wrap = false; boolean wrap = false;
if (false && insn.getResult().getTypedVar().getName() != null) { // TODO
if (false && result.getTypedVar().getName() != null) {
// don't wrap if result variable has name from debug info // don't wrap if result variable has name from debug info
wrap = false; wrap = false;
} else if (BlockUtils.blockContains(block, useInsn)) { } else if (BlockUtils.blockContains(block, useInsn)) {
...@@ -181,10 +183,18 @@ public class CodeShrinker extends AbstractVisitor { ...@@ -181,10 +183,18 @@ public class CodeShrinker extends AbstractVisitor {
list.removeAll(args); list.removeAll(args);
} }
i++; i++;
if (i > 10000) if (i > 1000)
throw new JadxRuntimeException("Can't inline arguments for: " + arg + " insn: " + assignInsn); throw new JadxRuntimeException("Can't inline arguments for: " + arg + " insn: " + assignInsn);
} while (!list.isEmpty()); } while (!list.isEmpty());
return arg.wrapInstruction(assignInsn); return arg.wrapInstruction(assignInsn);
} }
private static InsnArg selectOther(List<InsnArg> list, RegisterArg insn) {
InsnArg first = list.get(0);
if (first == insn)
return list.get(1);
else
return first;
}
} }
...@@ -22,7 +22,11 @@ import java.util.ArrayList; ...@@ -22,7 +22,11 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EnumVisitor extends AbstractVisitor { public class EnumVisitor extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(EnumVisitor.class);
@Override @Override
public boolean visit(ClassNode cls) throws JadxException { public boolean visit(ClassNode cls) throws JadxException {
...@@ -32,7 +36,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -32,7 +36,7 @@ public class EnumVisitor extends AbstractVisitor {
// collect enum fields, remove synthetic // collect enum fields, remove synthetic
List<FieldNode> enumFields = new ArrayList<FieldNode>(); List<FieldNode> enumFields = new ArrayList<FieldNode>();
for (Iterator<FieldNode> it = cls.getFields().iterator(); it.hasNext();) { for (Iterator<FieldNode> it = cls.getFields().iterator(); it.hasNext(); ) {
FieldNode f = it.next(); FieldNode f = it.next();
if (f.getAccessFlags().isEnum()) { if (f.getAccessFlags().isEnum()) {
enumFields.add(f); enumFields.add(f);
...@@ -45,7 +49,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -45,7 +49,7 @@ public class EnumVisitor extends AbstractVisitor {
MethodNode staticMethod = null; MethodNode staticMethod = null;
// remove synthetic methods // remove synthetic methods
for (Iterator<MethodNode> it = cls.getMethods().iterator(); it.hasNext();) { for (Iterator<MethodNode> it = cls.getMethods().iterator(); it.hasNext(); ) {
MethodNode mth = it.next(); MethodNode mth = it.next();
MethodInfo mi = mth.getMethodInfo(); MethodInfo mi = mth.getMethodInfo();
if (mi.isClassInit()) { if (mi.isClassInit()) {
...@@ -60,11 +64,18 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -60,11 +64,18 @@ public class EnumVisitor extends AbstractVisitor {
} }
} }
if (staticMethod == null)
throw new JadxException("Enum class init method not found");
EnumClassAttr attr = new EnumClassAttr(enumFields.size()); EnumClassAttr attr = new EnumClassAttr(enumFields.size());
cls.getAttributes().add(attr); cls.getAttributes().add(attr);
if (staticMethod == null) {
LOG.warn("Enum class init method not found: {}", cls);
// for this broken enum puts found fields and mark as inconsistent
cls.getAttributes().add(AttributeFlag.INCONSISTENT_CODE);
for (FieldNode field : enumFields) {
attr.getFields().add(new EnumField(field.getName(), 0));
}
return false;
}
attr.setStaticMethod(staticMethod); attr.setStaticMethod(staticMethod);
// move enum specific instruction from static method to separate list // move enum specific instruction from static method to separate list
...@@ -117,7 +128,8 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -117,7 +128,8 @@ public class EnumVisitor extends AbstractVisitor {
constrArg = iArg; constrArg = iArg;
} else { } else {
constrArg = CodeShrinker.inlineArgument(staticMethod, (RegisterArg) iArg); constrArg = CodeShrinker.inlineArgument(staticMethod, (RegisterArg) iArg);
assert constrArg != null; if (constrArg == null)
throw new JadxException("Can't inline constructor arg in enum: " + cls);
} }
field.getArgs().add(constrArg); field.getArgs().add(constrArg);
} }
...@@ -127,7 +139,7 @@ public class EnumVisitor extends AbstractVisitor { ...@@ -127,7 +139,7 @@ public class EnumVisitor extends AbstractVisitor {
for (ClassNode innerCls : cls.getInnerClasses()) { for (ClassNode innerCls : cls.getInnerClasses()) {
if (innerCls.getClassInfo().equals(co.getClassType())) { if (innerCls.getClassInfo().equals(co.getClassType())) {
// remove constructor, because it is anonymous class // remove constructor, because it is anonymous class
for (Iterator<?> mit = innerCls.getMethods().iterator(); mit.hasNext();) { for (Iterator<?> mit = innerCls.getMethods().iterator(); mit.hasNext(); ) {
MethodNode innerMth = (MethodNode) mit.next(); MethodNode innerMth = (MethodNode) mit.next();
if (innerMth.getAccessFlags().isConstructor()) if (innerMth.getAccessFlags().isConstructor())
mit.remove(); mit.remove();
......
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