fix: remove synchronization lock for code generation (#726)
This commit is contained in:
@@ -25,6 +25,7 @@ public final class JavaClass implements JavaNode {
|
||||
private List<JavaClass> innerClasses = Collections.emptyList();
|
||||
private List<JavaField> fields = Collections.emptyList();
|
||||
private List<JavaMethod> methods = Collections.emptyList();
|
||||
private boolean listsLoaded;
|
||||
|
||||
JavaClass(ClassNode classNode, JadxDecompiler decompiler) {
|
||||
this.decompiler = decompiler;
|
||||
@@ -59,7 +60,6 @@ public final class JavaClass implements JavaNode {
|
||||
}
|
||||
if (cls.getCode() == null) {
|
||||
cls.decompile();
|
||||
load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,13 +75,20 @@ public final class JavaClass implements JavaNode {
|
||||
|
||||
public synchronized void unload() {
|
||||
cls.unload();
|
||||
listsLoaded = false;
|
||||
}
|
||||
|
||||
public ClassNode getClassNode() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
private void load() {
|
||||
private void loadLists() {
|
||||
if (listsLoaded) {
|
||||
return;
|
||||
}
|
||||
listsLoaded = true;
|
||||
decompile();
|
||||
|
||||
JadxDecompiler rootDecompiler = getRootDecompiler();
|
||||
int inClsCount = cls.getInnerClasses().size();
|
||||
if (inClsCount != 0) {
|
||||
@@ -89,7 +96,7 @@ public final class JavaClass implements JavaNode {
|
||||
for (ClassNode inner : cls.getInnerClasses()) {
|
||||
if (!inner.contains(AFlag.DONT_GENERATE)) {
|
||||
JavaClass javaClass = new JavaClass(inner, this);
|
||||
javaClass.load();
|
||||
javaClass.loadLists();
|
||||
list.add(javaClass);
|
||||
rootDecompiler.getClassesMap().put(inner, javaClass);
|
||||
}
|
||||
@@ -205,17 +212,17 @@ public final class JavaClass implements JavaNode {
|
||||
}
|
||||
|
||||
public List<JavaClass> getInnerClasses() {
|
||||
decompile();
|
||||
loadLists();
|
||||
return innerClasses;
|
||||
}
|
||||
|
||||
public List<JavaField> getFields() {
|
||||
decompile();
|
||||
loadLists();
|
||||
return fields;
|
||||
}
|
||||
|
||||
public List<JavaMethod> getMethods() {
|
||||
decompile();
|
||||
loadLists();
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.core.codegen.CodeGen;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.ProcessState;
|
||||
import jadx.core.dex.visitors.DepthTraversal;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
@@ -22,28 +21,16 @@ public final class ProcessClass {
|
||||
}
|
||||
|
||||
public static void process(ClassNode cls) {
|
||||
process(cls, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ICodeInfo generateCode(ClassNode cls) {
|
||||
ICodeInfo codeInfo = process(cls, true);
|
||||
if (codeInfo == null) {
|
||||
throw new JadxRuntimeException("Failed to generate code for class: " + cls.getFullName());
|
||||
}
|
||||
return codeInfo;
|
||||
}
|
||||
|
||||
private static ICodeInfo process(ClassNode cls, boolean generateCode) {
|
||||
ClassNode topParentClass = cls.getTopParentClass();
|
||||
if (topParentClass != cls) {
|
||||
return process(topParentClass, generateCode);
|
||||
process(topParentClass);
|
||||
return;
|
||||
}
|
||||
if (!generateCode && cls.getState() == PROCESS_COMPLETE) {
|
||||
if (cls.getState() == PROCESS_COMPLETE) {
|
||||
// nothing to do
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
synchronized (getSyncObj(cls)) {
|
||||
synchronized (cls.getClassInfo()) {
|
||||
try {
|
||||
if (cls.getState() == NOT_LOADED) {
|
||||
cls.load();
|
||||
@@ -55,27 +42,26 @@ public final class ProcessClass {
|
||||
}
|
||||
cls.setState(PROCESS_COMPLETE);
|
||||
}
|
||||
if (generateCode && cls.getState() == PROCESS_COMPLETE) {
|
||||
processDependencies(cls);
|
||||
ICodeInfo code = CodeGen.generate(cls);
|
||||
cls.setState(ProcessState.GENERATED);
|
||||
// TODO: unload class (need to build dependency tree or allow to load class several times)
|
||||
return code;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ErrorsCounter.classError(cls, e.getClass().getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object getSyncObj(ClassNode cls) {
|
||||
return cls.getClassInfo();
|
||||
}
|
||||
@NotNull
|
||||
public static ICodeInfo generateCode(ClassNode cls) {
|
||||
ClassNode topParentClass = cls.getTopParentClass();
|
||||
if (topParentClass != cls) {
|
||||
return generateCode(topParentClass);
|
||||
}
|
||||
try {
|
||||
process(cls);
|
||||
cls.getDependencies().forEach(ProcessClass::process);
|
||||
|
||||
private static void processDependencies(ClassNode cls) {
|
||||
for (ClassNode depCls : cls.getDependencies()) {
|
||||
process(depCls, false);
|
||||
// TODO: unload class (need to build dependency tree or allow to load class several times)
|
||||
return CodeGen.generate(cls);
|
||||
} catch (Throwable e) {
|
||||
throw new JadxRuntimeException("Failed to generate code for class: " + cls.getFullName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user