From ceb7e16b90ce8ab7570b1dd905d2e14e6ceea9b2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Hannu=20Niemist=C3=B6?= Date: Mon, 29 May 2017 12:23:24 +0300 Subject: [PATCH] (refs #7245) The first version of decompiler for SCL compilations It is intentional that the new fragment org.simantics.scl.compiler.decompiler is not added to the module listings in bundles/pom.xml, because currently this feature is intended only for development purposes. Change-Id: Iff184f783c1a924ff00823486b4c13aa957ca184 --- .../.classpath | 7 +++ .../.project | 28 ++++++++++++ .../.settings/org.eclipse.jdt.core.prefs | 7 +++ .../META-INF/MANIFEST.MF | 13 ++++++ .../build.properties | 4 ++ .../decompiler/impl/DecompilerImpl.java | 43 +++++++++++++++++++ .../decompilation/DecompilerFactory.java | 26 +++++++++++ .../internal/decompilation/IDecompiler.java | 9 ++++ .../runtime/ExpressionClassLoader.java | 1 + .../compiler/runtime/MutableClassLoader.java | 1 + .../scl/compiler/runtime/RuntimeModule.java | 26 +++++++++-- .../top/SCLCompilerConfiguration.java | 2 +- 12 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 bundles/org.simantics.scl.compiler.decompiler/.classpath create mode 100644 bundles/org.simantics.scl.compiler.decompiler/.project create mode 100644 bundles/org.simantics.scl.compiler.decompiler/.settings/org.eclipse.jdt.core.prefs create mode 100644 bundles/org.simantics.scl.compiler.decompiler/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.scl.compiler.decompiler/build.properties create mode 100644 bundles/org.simantics.scl.compiler.decompiler/src/org/simantics/scl/compiler/internal/decompiler/impl/DecompilerImpl.java create mode 100644 bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/DecompilerFactory.java create mode 100644 bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/IDecompiler.java diff --git a/bundles/org.simantics.scl.compiler.decompiler/.classpath b/bundles/org.simantics.scl.compiler.decompiler/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.scl.compiler.decompiler/.project b/bundles/org.simantics.scl.compiler.decompiler/.project new file mode 100644 index 000000000..c8b32a7f2 --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/.project @@ -0,0 +1,28 @@ + + + org.simantics.scl.compiler.decompiler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.scl.compiler.decompiler/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.scl.compiler.decompiler/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.simantics.scl.compiler.decompiler/META-INF/MANIFEST.MF b/bundles/org.simantics.scl.compiler.decompiler/META-INF/MANIFEST.MF new file mode 100644 index 000000000..f4e9fa792 --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: SCL bytecode decompiler +Bundle-SymbolicName: org.simantics.scl.compiler.decompiler +Bundle-Version: 1.0.0.qualifier +Fragment-Host: org.simantics.scl.compiler;bundle-version="0.6.1" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.jboss.windup.decompiler.procyon;bundle-version="4.0.0", + org.jboss.windup.decompiler.procyon.windup-procyon-compilertools;bundle-version="1.0.0", + org.jboss.windup.decompiler.procyon.windup-procyon-core;bundle-version="1.0.0", + org.jboss.windup.decompiler.procyon.windup-procyon-reflection;bundle-version="1.0.0", + org.jboss.windup.decompiler.api.forge-addon;bundle-version="4.0.0", + org.jboss.windup.utils.windup-utils.forge-addon;bundle-version="4.0.0" diff --git a/bundles/org.simantics.scl.compiler.decompiler/build.properties b/bundles/org.simantics.scl.compiler.decompiler/build.properties new file mode 100644 index 000000000..34d2e4d2d --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/org.simantics.scl.compiler.decompiler/src/org/simantics/scl/compiler/internal/decompiler/impl/DecompilerImpl.java b/bundles/org.simantics.scl.compiler.decompiler/src/org/simantics/scl/compiler/internal/decompiler/impl/DecompilerImpl.java new file mode 100644 index 000000000..8cc103309 --- /dev/null +++ b/bundles/org.simantics.scl.compiler.decompiler/src/org/simantics/scl/compiler/internal/decompiler/impl/DecompilerImpl.java @@ -0,0 +1,43 @@ +package org.simantics.scl.compiler.internal.decompiler.impl; + +import java.io.IOException; +import java.io.Writer; + +import org.simantics.scl.compiler.internal.decompilation.IDecompiler; +import org.simantics.scl.compiler.runtime.MutableClassLoader; + +import com.strobel.assembler.metadata.Buffer; +import com.strobel.assembler.metadata.ITypeLoader; +import com.strobel.core.VerifyArgument; +import com.strobel.decompiler.Decompiler; +import com.strobel.decompiler.DecompilerSettings; +import com.strobel.decompiler.PlainTextOutput; + +public class DecompilerImpl implements IDecompiler { + @Override + public void decompile(MutableClassLoader classLoader, String className, Writer output) { + VerifyArgument.isNonNegative(3.0, "asd"); + DecompilerSettings settings = DecompilerSettings.javaDefaults(); + settings.setTypeLoader(new ITypeLoader() { + @Override + public boolean tryLoadType(String internalName, Buffer buffer) { + byte[] bytes = classLoader.getBytes(internalName.replace('/', '.')); + if(bytes == null) + return false; + + buffer.reset(bytes.length); + System.arraycopy(bytes, 0, buffer.array(), 0, bytes.length); + return true; + } + }); + Decompiler.decompile( + className, + new PlainTextOutput(output), + settings); + try { + output.flush(); + } catch (IOException e) { + } + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/DecompilerFactory.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/DecompilerFactory.java new file mode 100644 index 000000000..d2cbcd0b4 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/DecompilerFactory.java @@ -0,0 +1,26 @@ +package org.simantics.scl.compiler.internal.decompilation; + +public class DecompilerFactory { + private static boolean initialized; + private static IDecompiler DECOMPILER; + public static IDecompiler getDecompiler() { + if(!initialized) { + try { + Class clazz = DecompilerFactory.class.getClassLoader().loadClass("org.simantics.scl.compiler.internal.decompiler.impl.DecompilerImpl"); + if(clazz != null) { + DECOMPILER = (IDecompiler)clazz.newInstance(); + } + } catch(ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch(NoClassDefFoundError e) { + e.printStackTrace(); + } + initialized = true; + } + return DECOMPILER; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/IDecompiler.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/IDecompiler.java new file mode 100644 index 000000000..4640acfde --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/decompilation/IDecompiler.java @@ -0,0 +1,9 @@ +package org.simantics.scl.compiler.internal.decompilation; + +import java.io.Writer; + +import org.simantics.scl.compiler.runtime.MutableClassLoader; + +public interface IDecompiler { + void decompile(MutableClassLoader classLoader, String className, Writer output); +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java index 0c134ee5c..45e302720 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java @@ -60,6 +60,7 @@ public class ExpressionClassLoader extends ClassLoader implements MutableClassLo return defineClass(name, bytes, 0, bytes.length); } + @Override public byte[] getBytes(String name) { // Non-SCL classes are not handled here if(!name.startsWith(SCL_PACKAGE_PREFIX)) diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/MutableClassLoader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/MutableClassLoader.java index adf36f8af..422d38dc6 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/MutableClassLoader.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/MutableClassLoader.java @@ -16,5 +16,6 @@ public interface MutableClassLoader { String getFreshPackageName(); THashMap getConstantCache(); ClassLoader getClassLoader(); + byte[] getBytes(String className); } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java index aeb21ffa6..4ed45005b 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java @@ -1,5 +1,6 @@ package org.simantics.scl.compiler.runtime; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -13,12 +14,19 @@ import org.simantics.scl.compiler.environment.GlobalOnlyEnvironment; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy; import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder; +import org.simantics.scl.compiler.internal.decompilation.DecompilerFactory; +import org.simantics.scl.compiler.internal.decompilation.IDecompiler; import org.simantics.scl.compiler.module.Module; +import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.top.ValueNotFound; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; public class RuntimeModule { + private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeModule.class); + public static final boolean VALIDATE_CLASS_NAMES = true; public static final boolean TRACE_CLASS_CREATION = false; @@ -66,6 +74,7 @@ public class RuntimeModule { */ } + @Override public byte[] getBytes(String name) { // Non-SCL classes are not handled here if(!name.startsWith(SCL_PACKAGE_PREFIX)) @@ -93,7 +102,7 @@ public class RuntimeModule { return parentModule.classLoader.getBytes(name); } } - + synchronized Class getLocalClass(String name) throws ClassNotFoundException { // Is class already loaded Class clazz = findLoadedClass(name); @@ -107,7 +116,9 @@ public class RuntimeModule { bytes = localClasses.get(internalName); if(bytes == null) throw new ClassNotFoundException(name); - } + } + if(SCLCompilerConfiguration.SHOW_DECOMPILED_BYTECODE) + showDecompiledBytecode(internalName); return defineClass(name, bytes, 0, bytes.length); } @@ -139,8 +150,8 @@ public class RuntimeModule { { RuntimeModule parentModule = parentModuleMap.get(requestedModuleName); if(parentModule == null) { - System.err.println("requestedModuleName = " + requestedModuleName); - System.err.println("this.moduleName = " + this.moduleName); + LOGGER.error("requestedModuleName = " + requestedModuleName); + LOGGER.error("this.moduleName = " + this.moduleName); throw new ClassNotFoundException(name); } @@ -187,6 +198,13 @@ public class RuntimeModule { public ClassLoader getClassLoader() { return this; } + + private void showDecompiledBytecode(String className) { + IDecompiler decompiler = DecompilerFactory.getDecompiler(); + if(decompiler == null) + return; + decompiler.decompile(this, className, new OutputStreamWriter(System.out)); + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLCompilerConfiguration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLCompilerConfiguration.java index 763bc9d9c..57f7102cb 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLCompilerConfiguration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/SCLCompilerConfiguration.java @@ -10,6 +10,7 @@ public interface SCLCompilerConfiguration { public static final boolean SHOW_SSA_BEFORE_LAMBDA_LIFTING = false; public static final boolean SHOW_FINAL_SSA = false; public static final boolean SHOW_COMPILED_BYTECODE = false; + public static final boolean SHOW_DECOMPILED_BYTECODE = false; public static final boolean SHOW_EXPRESSION_BEFORE_EVALUATION = false; public static final boolean SHOW_INTERPRETED_EXPRESSION = false; @@ -19,7 +20,6 @@ public interface SCLCompilerConfiguration { public static final boolean VALIDATE_AFTER_OPTIMIZATIONS = false; public static final boolean TRACE_CONSTRAINT_SOLVER = false; public static final boolean PRINT_OPTIMIZATION_TRANSFORMATIONS = false; - public static final boolean EXCEPTIONS_TO_COMPILATION_ERRORS = false; public static final boolean NULL_CHECK_THREAD_LOCAL_VARIABLES = false; -- 2.43.2