[java decompiler] reworks setting/accessing decompiler context

This commit is contained in:
Roman Shevchenko
2017-11-28 19:22:17 +01:00
parent fbc3165138
commit 71d8f4d689
16 changed files with 197 additions and 228 deletions

View File

@@ -3,7 +3,6 @@ package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
@@ -28,6 +27,7 @@ import java.util.Map.Entry;
public class ClassesProcessor {
public static final int AVERAGE_CLASS_SIZE = 16 * 1024;
private final StructContext context;
private final Map<String, ClassNode> mapRootClasses = new HashMap<>();
private static class Inner {
@@ -41,6 +41,10 @@ public class ClassesProcessor {
}
public ClassesProcessor(StructContext context) {
this.context = context;
}
public void loadClasses(IIdentifierRenamer renamer) {
Map<String, Inner> mapInnerClasses = new HashMap<>();
Map<String, Set<String>> mapNestedClassReferences = new HashMap<>();
Map<String, Set<String>> mapEnclosingClassReferences = new HashMap<>();
@@ -64,12 +68,11 @@ public class ClassesProcessor {
if (savedName != null) {
simpleName = savedName;
}
else if (simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
if (renamer.toBeRenamed(IIdentifierRenamer.Type.ELEMENT_CLASS, simpleName, null, null)) {
simpleName = renamer.getNextClassName(innerName, simpleName);
mapNewSimpleNames.put(innerName, simpleName);
}
else if (simpleName != null &&
renamer != null &&
renamer.toBeRenamed(IIdentifierRenamer.Type.ELEMENT_CLASS, simpleName, null, null)) {
simpleName = renamer.getNextClassName(innerName, simpleName);
mapNewSimpleNames.put(innerName, simpleName);
}
Inner rec = new Inner();
@@ -223,9 +226,7 @@ public class ClassesProcessor {
DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);
try {
ImportCollector importCollector = new ImportCollector(root);
DecompilerContext.setImportCollector(importCollector);
DecompilerContext.setCounterContainer(new CounterContainer());
DecompilerContext.setBytecodeSourceMapper(new BytecodeSourceMapper());
DecompilerContext.startClass(importCollector);
new LambdaProcessor().processClass(root);
@@ -418,4 +419,4 @@ public class ClassesProcessor {
public boolean is_content_method_static;
}
}
}
}

View File

@@ -4,142 +4,142 @@ package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.StructContext;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
public class DecompilerContext {
public static final String CURRENT_CLASS = "CURRENT_CLASS";
public static final String CURRENT_CLASS_WRAPPER = "CURRENT_CLASS_WRAPPER";
public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE";
public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
private static final ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<>();
private static volatile DecompilerContext currentContext = null;
private final Map<String, Object> properties;
private StructContext structContext;
private final IFernflowerLogger logger;
private final StructContext structContext;
private final ClassesProcessor classProcessor;
private final PoolInterceptor poolInterceptor;
private ImportCollector importCollector;
private VarNamesCollector varNamescollector;
private VarProcessor varProcessor;
private CounterContainer counterContainer;
private ClassesProcessor classProcessor;
private PoolInterceptor poolInterceptor;
private IFernflowerLogger logger;
private BytecodeSourceMapper bytecodeSourceMapper;
private DecompilerContext(Map<String, Object> properties) {
private DecompilerContext(Map<String, Object> properties,
IFernflowerLogger logger,
StructContext structContext,
ClassesProcessor classProcessor,
PoolInterceptor interceptor) {
this.properties = properties;
this.logger = logger;
this.structContext = structContext;
this.classProcessor = classProcessor;
this.poolInterceptor = interceptor;
this.counterContainer = new CounterContainer();
}
public static void initContext(Map<String, Object> propertiesCustom) {
// *****************************************************************************
// context setup and update
// *****************************************************************************
public static void initContext(Map<String, Object> customProperties,
IFernflowerLogger logger,
StructContext structContext,
ClassesProcessor classProcessor,
PoolInterceptor interceptor) {
Objects.requireNonNull(logger);
Objects.requireNonNull(structContext);
Objects.requireNonNull(classProcessor);
Map<String, Object> properties = new HashMap<>(IFernflowerPreferences.DEFAULTS);
if (propertiesCustom != null) {
properties.putAll(propertiesCustom);
if (customProperties != null) {
properties.putAll(customProperties);
}
currentContext.set(new DecompilerContext(properties));
String level = (String)properties.get(IFernflowerPreferences.LOG_LEVEL);
if (level != null) {
try {
logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException ignore) { }
}
currentContext = new DecompilerContext(properties, logger, structContext, classProcessor, interceptor);
}
public static DecompilerContext getCurrentContext() {
return currentContext.get();
}
public static void setCurrentContext(DecompilerContext context) {
currentContext.set(context);
}
public static Object getProperty(String key) {
return getCurrentContext().properties.get(key);
public static void clearContext() {
currentContext = null;
}
public static void setProperty(String key, Object value) {
getCurrentContext().properties.put(key, value);
currentContext.properties.put(key, value);
}
public static void startClass(ImportCollector importCollector) {
currentContext.importCollector = importCollector;
currentContext.counterContainer = new CounterContainer();
currentContext.bytecodeSourceMapper = new BytecodeSourceMapper();
}
public static void startMethod(VarProcessor varProcessor) {
currentContext.varProcessor = varProcessor;
currentContext.counterContainer = new CounterContainer();
}
// *****************************************************************************
// context access
// *****************************************************************************
public static Object getProperty(String key) {
return currentContext.properties.get(key);
}
public static boolean getOption(String key) {
return "1".equals(getCurrentContext().properties.get(key));
}
public static ImportCollector getImportCollector() {
return getCurrentContext().importCollector;
}
public static void setImportCollector(ImportCollector importCollector) {
getCurrentContext().importCollector = importCollector;
}
public static VarNamesCollector getVarNamesCollector() {
return getCurrentContext().varNamescollector;
}
public static void setVarNamesCollector(VarNamesCollector varNamesCollector) {
getCurrentContext().varNamescollector = varNamesCollector;
}
public static StructContext getStructContext() {
return getCurrentContext().structContext;
}
public static void setStructContext(StructContext structContext) {
getCurrentContext().structContext = structContext;
}
public static CounterContainer getCounterContainer() {
return getCurrentContext().counterContainer;
}
public static void setCounterContainer(CounterContainer counterContainer) {
getCurrentContext().counterContainer = counterContainer;
}
public static ClassesProcessor getClassProcessor() {
return getCurrentContext().classProcessor;
}
public static void setClassProcessor(ClassesProcessor classProcessor) {
getCurrentContext().classProcessor = classProcessor;
}
public static PoolInterceptor getPoolInterceptor() {
return getCurrentContext().poolInterceptor;
}
public static void setPoolInterceptor(PoolInterceptor poolinterceptor) {
getCurrentContext().poolInterceptor = poolinterceptor;
}
public static BytecodeSourceMapper getBytecodeSourceMapper() {
return getCurrentContext().bytecodeSourceMapper;
}
public static void setBytecodeSourceMapper(BytecodeSourceMapper bytecodeSourceMapper) {
getCurrentContext().bytecodeSourceMapper = bytecodeSourceMapper;
}
public static IFernflowerLogger getLogger() {
return getCurrentContext().logger;
}
public static void setLogger(IFernflowerLogger logger) {
if (logger != null) {
String level = (String)getProperty(IFernflowerPreferences.LOG_LEVEL);
if (level != null) {
try {
logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.US)));
}
catch (IllegalArgumentException ignore) { }
}
}
getCurrentContext().logger = logger;
return "1".equals(getProperty(key));
}
public static String getNewLineSeparator() {
return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
IFernflowerPreferences.LINE_SEPARATOR_UNX : IFernflowerPreferences.LINE_SEPARATOR_WIN;
}
public static IFernflowerLogger getLogger() {
return currentContext.logger;
}
public static StructContext getStructContext() {
return currentContext.structContext;
}
public static ClassesProcessor getClassProcessor() {
return currentContext.classProcessor;
}
public static PoolInterceptor getPoolInterceptor() {
return currentContext.poolInterceptor;
}
public static ImportCollector getImportCollector() {
return currentContext.importCollector;
}
public static VarProcessor getVarProcessor() {
return currentContext.varProcessor;
}
public static CounterContainer getCounterContainer() {
return currentContext.counterContainer;
}
public static BytecodeSourceMapper getBytecodeSourceMapper() {
return currentContext.bytecodeSourceMapper;
}
}

View File

@@ -2,12 +2,10 @@
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.extern.*;
import org.jetbrains.java.decompiler.modules.renamer.ConverterHelper;
import org.jetbrains.java.decompiler.modules.renamer.IdentifierConverter;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.IDecompiledData;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructContext;
@@ -16,32 +14,50 @@ import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
import java.util.Map;
public class Fernflower implements IDecompiledData {
private final StructContext structContext;
private ClassesProcessor classesProcessor;
private final ClassesProcessor classProcessor;
private IIdentifierRenamer helper;
private IdentifierConverter converter;
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
structContext = new StructContext(saver, this, new LazyLoader(provider));
DecompilerContext.initContext(options);
DecompilerContext.setCounterContainer(new CounterContainer());
DecompilerContext.setLogger(logger);
classProcessor = new ClassesProcessor(structContext);
PoolInterceptor interceptor = null;
Object rename = options.get(IFernflowerPreferences.RENAME_ENTITIES);
if ("1".equals(rename) || rename == null && "1".equals(IFernflowerPreferences.DEFAULTS.get(IFernflowerPreferences.RENAME_ENTITIES))) {
helper = loadHelper((String)options.get(IFernflowerPreferences.USER_RENAMER_CLASS));
interceptor = new PoolInterceptor();
converter = new IdentifierConverter(structContext, helper, interceptor);
}
DecompilerContext.initContext(options, logger, structContext, classProcessor, interceptor);
}
public void decompileContext() {
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
new IdentifierConverter().rename(structContext);
if (converter != null) {
converter.rename();
}
classesProcessor = new ClassesProcessor(structContext);
DecompilerContext.setClassProcessor(classesProcessor);
DecompilerContext.setStructContext(structContext);
classProcessor.loadClasses(helper);
structContext.saveContext();
}
private static IIdentifierRenamer loadHelper(String className) {
if (className != null) {
try {
Class<?> renamerClass = Fernflower.class.getClassLoader().loadClass(className);
return (IIdentifierRenamer) renamerClass.getDeclaredConstructor().newInstance();
}
catch (Exception ignored) { }
}
return new ConverterHelper();
}
public void clearContext() {
DecompilerContext.setCurrentContext(null);
DecompilerContext.clearContext();
}
public StructContext getStructContext() {
@@ -50,18 +66,16 @@ public class Fernflower implements IDecompiledData {
@Override
public String getClassEntryName(StructClass cl, String entryName) {
ClassNode node = classesProcessor.getMapRootClasses().get(cl.qualifiedName);
ClassNode node = classProcessor.getMapRootClasses().get(cl.qualifiedName);
if (node.type != ClassNode.CLASS_ROOT) {
return null;
}
else if (converter != null) {
String simpleClassName = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simpleClassName + ".java";
}
else {
if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
String simple_classname = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simple_classname + ".java";
}
else {
return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
}
return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
}
}
@@ -70,7 +84,7 @@ public class Fernflower implements IDecompiledData {
try {
TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);
buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());
classesProcessor.writeClass(cl, buffer);
classProcessor.writeClass(cl, buffer);
return buffer.toString();
}
catch (Throwable ex) {
@@ -78,4 +92,4 @@ public class Fernflower implements IDecompiledData {
return null;
}
}
}
}

View File

@@ -2,9 +2,8 @@
package org.jetbrains.java.decompiler.main.collectors;
public class CounterContainer {
public static final int STATEMENT_COUNTER = 0;
public static final int EXPRENT_COUNTER = 1;
public static final int EXPRESSION_COUNTER = 1;
public static final int VAR_COUNTER = 2;
private final int[] values = new int[]{1, 1, 1};
@@ -20,4 +19,4 @@ public class CounterContainer {
public int getCounterAndIncrement(int counter) {
return values[counter]++;
}
}
}

View File

@@ -7,18 +7,17 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@SuppressWarnings("unused")
public class BaseDecompiler {
private final Fernflower fernflower;
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
fernflower = new Fernflower(provider, saver, options, logger);
}
public void addSpace(File file, boolean isOwn) throws IOException {
public void addSpace(File file, boolean isOwn) {
fernflower.getStructContext().addSpace(file, isOwn);
}
@@ -30,4 +29,4 @@ public class BaseDecompiler {
fernflower.clearContext();
}
}
}
}

View File

@@ -17,7 +17,6 @@ import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public static void main(String[] args) {
if (args.length < 2) {
@@ -102,11 +101,6 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
private final Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<>();
private final Map<String, Set<String>> mapArchiveEntries = new HashMap<>();
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public ConsoleDecompiler(File destination, Map<String, Object> options) {
this(destination, options, new PrintStreamLogger(System.out));
}
protected ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger) {
root = destination;
fernflower = new Fernflower(this, this, options, logger);

View File

@@ -25,7 +25,6 @@ import java.util.List;
import java.util.Set;
public class ClassWrapper {
private final StructClass classStruct;
private final Set<String> hiddenMembers = new HashSet<>();
private final VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<>();
@@ -47,15 +46,12 @@ public class ClassWrapper {
for (StructMethod mt : classStruct.getMethods()) {
DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
VarNamesCollector vc = new VarNamesCollector();
DecompilerContext.setVarNamesCollector(vc);
CounterContainer counter = new CounterContainer();
DecompilerContext.setCounterContainer(counter);
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
VarProcessor varProc = new VarProcessor(mt, md);
DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varProc);
DecompilerContext.startMethod(varProc);
VarNamesCollector vc = varProc.getVarNamesCollector();
CounterContainer counter = DecompilerContext.getCounterContainer();
RootStatement root = null;
@@ -67,7 +63,7 @@ public class ClassWrapper {
root = MethodProcessorRunnable.codeToJava(mt, md, varProc);
}
else {
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc, DecompilerContext.getCurrentContext());
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc);
Thread mtThread = new Thread(mtProc, "Java decompiler");
long stopAt = System.currentTimeMillis() + maxSec * 1000;
@@ -128,9 +124,8 @@ public class ClassWrapper {
}
}
catch (Throwable ex) {
DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.",
IFernflowerLogger.Severity.WARN,
ex);
String message = "Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.";
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN, ex);
isError = true;
}

View File

@@ -25,23 +25,19 @@ public class MethodProcessorRunnable implements Runnable {
private final StructMethod method;
private final MethodDescriptor methodDescriptor;
private final VarProcessor varProc;
private final DecompilerContext parentContext;
private volatile RootStatement root;
private volatile Throwable error;
private volatile boolean finished = false;
public MethodProcessorRunnable(StructMethod method, MethodDescriptor methodDescriptor, VarProcessor varProc, DecompilerContext parentContext) {
public MethodProcessorRunnable(StructMethod method, MethodDescriptor methodDescriptor, VarProcessor varProc) {
this.method = method;
this.methodDescriptor = methodDescriptor;
this.varProc = varProc;
this.parentContext = parentContext;
}
@Override
public void run() {
DecompilerContext.setCurrentContext(parentContext);
error = null;
root = null;
@@ -54,9 +50,6 @@ public class MethodProcessorRunnable implements Runnable {
catch (Throwable ex) {
error = ex;
}
finally {
DecompilerContext.setCurrentContext(null);
}
finished = true;
synchronized (lock) {