fix: improve codegen methods for custom decompilation mode

This commit is contained in:
Skylot
2026-01-12 19:40:44 +00:00
parent 018c20187d
commit ae1a5e9277
5 changed files with 103 additions and 21 deletions
@@ -1,16 +1,22 @@
package jadx.core;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.DecompilationMode;
import jadx.api.ICodeInfo;
import jadx.api.JadxArgs;
import jadx.api.impl.SimpleCodeInfo;
import jadx.core.codegen.CodeGen;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.DecompileModeOverrideAttr;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.LoadStage;
import jadx.core.dex.nodes.RootNode;
@@ -154,6 +160,43 @@ public class ProcessClass {
}
}
private final Map<DecompilationMode, ProcessClass> modesMap = new EnumMap<>(DecompilationMode.class);
public @Nullable ICodeInfo forceGenerateCodeForMode(ClassNode cls, DecompilationMode mode) {
synchronized (modesMap) {
ProcessClass prCls = modesMap.computeIfAbsent(mode, m -> {
RootNode root = cls.root();
ProcessClass newPrCls = new ProcessClass(getPassesForMode(root.getArgs(), m));
newPrCls.initPasses(root);
return newPrCls;
});
try {
cls.addAttr(new DecompileModeOverrideAttr(mode));
return prCls.forceGenerateCode(cls);
} finally {
cls.remove(AType.DECOMPILE_MODE_OVERRIDE);
}
}
}
private static List<IDexTreeVisitor> getPassesForMode(JadxArgs baseArgs, DecompilationMode mode) {
switch (mode) {
case FALLBACK:
return Jadx.getFallbackPassesList();
case SIMPLE:
// copy properties into new args
// keep in sync with properties usage in Jadx.getSimpleModePasses method
JadxArgs args = new JadxArgs();
args.setDebugInfo(baseArgs.isDebugInfo());
args.setCommentsLevel(baseArgs.getCommentsLevel());
return Jadx.getSimpleModePasses(args);
default:
throw new JadxRuntimeException("Unexpected decompilation mode: " + mode);
}
}
public void initPasses(RootNode root) {
for (IDexTreeVisitor pass : passes) {
try {
@@ -9,6 +9,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.DecompilationMode;
import jadx.api.ICodeWriter;
import jadx.api.JadxArgs;
import jadx.api.args.IntegerFormat;
@@ -23,6 +24,7 @@ import jadx.core.Jadx;
import jadx.core.codegen.utils.CodeGenUtils;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.DecompileModeOverrideAttr;
import jadx.core.dex.attributes.nodes.JadxError;
import jadx.core.dex.attributes.nodes.JumpInfo;
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
@@ -266,7 +268,14 @@ public class MethodGen {
public void addInstructions(ICodeWriter code) throws CodegenException {
JadxArgs args = mth.root().getArgs();
switch (args.getDecompilationMode()) {
DecompileModeOverrideAttr modeOverrideAttr = mth.getTopParentClass().get(AType.DECOMPILE_MODE_OVERRIDE);
DecompilationMode mode;
if (modeOverrideAttr != null) {
mode = modeOverrideAttr.getMode();
} else {
mode = args.getDecompilationMode();
}
switch (mode) {
case AUTO:
if (classGen.isFallbackMode() || mth.getRegion() == null) {
// TODO: try simple mode first
@@ -7,6 +7,7 @@ import jadx.core.dex.attributes.nodes.AnonymousClassAttr;
import jadx.core.dex.attributes.nodes.ClassTypeVarsAttr;
import jadx.core.dex.attributes.nodes.CodeFeaturesAttr;
import jadx.core.dex.attributes.nodes.DeclareVariablesAttr;
import jadx.core.dex.attributes.nodes.DecompileModeOverrideAttr;
import jadx.core.dex.attributes.nodes.EdgeInsnAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumMapAttr;
@@ -62,6 +63,7 @@ public final class AType<T extends IJadxAttribute> implements IJadxAttrType<T> {
public static final AType<ClassTypeVarsAttr> CLASS_TYPE_VARS = new AType<>();
public static final AType<AnonymousClassAttr> ANONYMOUS_CLASS = new AType<>();
public static final AType<InlinedAttr> INLINED = new AType<>();
public static final AType<DecompileModeOverrideAttr> DECOMPILE_MODE_OVERRIDE = new AType<>();
// field
public static final AType<FieldInitInsnAttr> FIELD_INIT_INSN = new AType<>();
@@ -0,0 +1,29 @@
package jadx.core.dex.attributes.nodes;
import jadx.api.DecompilationMode;
import jadx.api.plugins.input.data.attributes.IJadxAttrType;
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
import jadx.core.dex.attributes.AType;
public class DecompileModeOverrideAttr implements IJadxAttribute {
private final DecompilationMode mode;
public DecompileModeOverrideAttr(DecompilationMode mode) {
this.mode = mode;
}
public DecompilationMode getMode() {
return mode;
}
@Override
public IJadxAttrType<DecompileModeOverrideAttr> getAttrType() {
return AType.DECOMPILE_MODE_OVERRIDE;
}
@Override
public String toString() {
return "DECOMPILE_MODE_OVERRIDE: " + mode;
}
}
@@ -18,7 +18,6 @@ import org.slf4j.LoggerFactory;
import jadx.api.DecompilationMode;
import jadx.api.ICodeCache;
import jadx.api.ICodeInfo;
import jadx.api.JadxArgs;
import jadx.api.JavaClass;
import jadx.api.impl.SimpleCodeInfo;
import jadx.api.impl.SimpleCodeWriter;
@@ -38,8 +37,6 @@ import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
import jadx.api.plugins.input.data.impl.ListConsumer;
import jadx.api.usage.IUsageInfoData;
import jadx.core.Consts;
import jadx.core.Jadx;
import jadx.core.ProcessClass;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.InlinedAttr;
@@ -320,23 +317,25 @@ public class ClassNode extends NotificationAttrNode
* WARNING: Slow operation! Use with caution!
*/
public ICodeInfo decompileWithMode(DecompilationMode mode) {
DecompilationMode baseMode = root.getArgs().getDecompilationMode();
if (mode == baseMode) {
return decompile(true);
}
synchronized (DECOMPILE_WITH_MODE_SYNC) {
JadxArgs args = root.getArgs();
try {
unload();
args.setDecompilationMode(mode);
ProcessClass process = new ProcessClass(Jadx.getPassesList(args));
process.initPasses(root);
ICodeInfo code = process.forceGenerateCode(this);
return Utils.getOrElse(code, ICodeInfo.EMPTY);
} finally {
args.setDecompilationMode(baseMode);
unload();
}
switch (mode) {
case AUTO:
case RESTRUCTURE:
return decompile(true);
case SIMPLE:
case FALLBACK:
synchronized (DECOMPILE_WITH_MODE_SYNC) {
try {
unload();
ICodeInfo code = root.getProcessClasses().forceGenerateCodeForMode(this, mode);
return Utils.getOrElse(code, ICodeInfo.EMPTY);
} finally {
unload();
}
}
default:
throw new JadxRuntimeException("Unknown mode: " + mode);
}
}