fix: don't apply node positions and prevent eager loading for custom decompile modes (#2116)

This commit is contained in:
Skylot
2024-03-19 20:22:28 +00:00
parent bff00d101f
commit 463d2b90fa
4 changed files with 75 additions and 45 deletions
@@ -154,7 +154,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter
@Override
public ICodeInfo finish() {
processDefinitionAnnotations();
validateAnnotations();
String code = buf.toString();
buf = null;
@@ -166,18 +165,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter
return annotations;
}
private void processDefinitionAnnotations() {
if (!annotations.isEmpty()) {
annotations.forEach((k, v) -> {
if (v instanceof NodeDeclareRef) {
NodeDeclareRef declareRef = (NodeDeclareRef) v;
declareRef.setDefPos(k);
declareRef.getNode().setDefPosition(k);
}
});
}
}
private void validateAnnotations() {
if (annotations.isEmpty()) {
return;
@@ -23,6 +23,8 @@ import jadx.api.ICodeWriter;
import jadx.api.JadxArgs;
import jadx.api.JavaClass;
import jadx.api.impl.SimpleCodeInfo;
import jadx.api.metadata.ICodeAnnotation;
import jadx.api.metadata.annotations.NodeDeclareRef;
import jadx.api.plugins.input.data.IClassData;
import jadx.api.plugins.input.data.IFieldData;
import jadx.api.plugins.input.data.IMethodData;
@@ -312,6 +314,8 @@ public class ClassNode extends NotificationAttrNode
return decompile(true);
}
private static final Object DECOMPILE_WITH_MODE_SYNC = new Object();
/**
* WARNING: Slow operation! Use with caution!
*/
@@ -320,15 +324,18 @@ public class ClassNode extends NotificationAttrNode
if (mode == baseMode) {
return decompile(true);
}
JadxArgs args = root.getArgs();
try {
unload();
args.setDecompilationMode(mode);
ProcessClass process = new ProcessClass(args);
process.initPasses(root);
return process.generateCode(this);
} finally {
args.setDecompilationMode(baseMode);
synchronized (DECOMPILE_WITH_MODE_SYNC) {
JadxArgs args = root.getArgs();
try {
unload();
args.setDecompilationMode(mode);
ProcessClass process = new ProcessClass(args);
process.initPasses(root);
return process.generateCode(this);
} finally {
args.setDecompilationMode(baseMode);
unload();
}
}
}
@@ -383,22 +390,46 @@ public class ClassNode extends NotificationAttrNode
return code;
}
}
ICodeInfo codeInfo;
try {
if (Consts.DEBUG) {
LOG.debug("Decompiling class: {}", this);
}
codeInfo = root.getProcessClasses().generateCode(this);
} catch (Throwable e) {
addError("Code generation failed", e);
codeInfo = new SimpleCodeInfo(Utils.getStackTrace(e));
}
ICodeInfo codeInfo = generateClassCode();
if (codeInfo != ICodeInfo.EMPTY) {
codeCache.add(clsRawName, codeInfo);
}
return codeInfo;
}
private ICodeInfo generateClassCode() {
try {
if (Consts.DEBUG) {
LOG.debug("Decompiling class: {}", this);
}
ICodeInfo codeInfo = root.getProcessClasses().generateCode(this);
processDefinitionAnnotations(codeInfo);
return codeInfo;
} catch (Throwable e) {
addError("Code generation failed", e);
return new SimpleCodeInfo(Utils.getStackTrace(e));
}
}
/**
* Save node definition positions found in code
*/
private static void processDefinitionAnnotations(ICodeInfo codeInfo) {
Map<Integer, ICodeAnnotation> annotations = codeInfo.getCodeMetadata().getAsMap();
if (annotations.isEmpty()) {
return;
}
for (Map.Entry<Integer, ICodeAnnotation> entry : annotations.entrySet()) {
ICodeAnnotation ann = entry.getValue();
if (ann.getAnnType() == AnnType.DECLARATION) {
NodeDeclareRef declareRef = (NodeDeclareRef) ann;
int pos = entry.getKey();
declareRef.setDefPos(pos);
declareRef.getNode().setDefPosition(pos);
}
}
}
@Nullable
public ICodeInfo getCodeFromCache() {
ICodeCache codeCache = root().getCodeCache();
@@ -134,10 +134,22 @@ public class CodePanel extends JPanel {
codeScrollPane.setLineNumbersEnabled(true);
}
private static final LineNumberFormatter SIMPLE_LINE_FORMATTER = new LineNumberFormatter() {
@Override
public String format(int lineNumber) {
return Integer.toString(lineNumber);
}
@Override
public int getMaxLength(int maxLineNumber) {
return SourceLineFormatter.getNumberLength(maxLineNumber);
}
};
private synchronized void applyLineFormatter() {
LineNumberFormatter linesFormatter = useSourceLines
? new SourceLineFormatter(codeArea.getCodeInfo())
: LineNumberList.DEFAULT_LINE_NUMBER_FORMATTER;
: SIMPLE_LINE_FORMATTER;
codeScrollPane.getGutter().setLineNumberFormatter(linesFormatter);
}
@@ -170,15 +182,13 @@ public class CodePanel extends JPanel {
}
private void initLinesModeSwitch() {
if (canShowDebugLines()) {
MousePressedHandler lineModeSwitch = new MousePressedHandler(ev -> {
useSourceLines = !useSourceLines;
applyLineFormatter();
});
for (Component gutterComp : codeScrollPane.getGutter().getComponents()) {
if (gutterComp instanceof LineNumberList) {
gutterComp.addMouseListener(lineModeSwitch);
}
MousePressedHandler lineModeSwitch = new MousePressedHandler(ev -> {
useSourceLines = !useSourceLines;
applyLineFormatter();
});
for (Component gutterComp : codeScrollPane.getGutter().getComponents()) {
if (gutterComp instanceof LineNumberList) {
gutterComp.addMouseListener(lineModeSwitch);
}
}
}
@@ -32,8 +32,10 @@ public class SourceLineFormatter implements LineNumberFormatter {
.values().stream()
.mapToInt(Integer::intValue)
.max().orElse(1);
// maxLine can be anything including zero and negative numbers,
// so use safe 'stringify' method instead faster 'Math.log10'
return Integer.toString(maxLine).length();
return getNumberLength(maxLine);
}
public static int getNumberLength(int num) {
return num < 10 ? 1 : 1 + (int) Math.log10(num);
}
}