[java decompiler] cleanup (duplicates; dead code; typos; formatting)

master
Roman Shevchenko 7 years ago
parent acf6646941
commit b3171e60c9
  1. 21
      src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
  2. 17
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  3. 5
      src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
  4. 60
      src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
  5. 32
      src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
  6. 374
      src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
  7. 117
      src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
  8. 35
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java
  9. 8
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
  10. 32
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
  11. 82
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
  12. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
  13. 26
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
  14. 1
      src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
  15. 3
      src/org/jetbrains/java/decompiler/struct/match/IMatchable.java
  16. 117
      src/org/jetbrains/java/decompiler/struct/match/MatchEngine.java
  17. 9
      src/org/jetbrains/java/decompiler/struct/match/MatchNode.java
  18. 2
      test/org/jetbrains/java/decompiler/DecompilerTestFixture.java

@ -42,10 +42,8 @@ public class ClassReference14Processor {
ctor.setStringDescriptor("()V"); ctor.setStringDescriptor("()V");
ctor.setFunctype(InvocationExprent.TYP_INIT); ctor.setFunctype(InvocationExprent.TYP_INIT);
ctor.setDescriptor(MethodDescriptor.parseDescriptor("()V")); ctor.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
NewExprent newExpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<>(), null); NewExprent newExpr = new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<>(), null);
newExpr.setConstructor(ctor); newExpr.setConstructor(ctor);
InvocationExprent invCause = new InvocationExprent(); InvocationExprent invCause = new InvocationExprent();
invCause.setName("initCause"); invCause.setName("initCause");
invCause.setClassname("java/lang/NoClassDefFoundError"); invCause.setClassname("java/lang/NoClassDefFoundError");
@ -54,18 +52,18 @@ public class ClassReference14Processor {
invCause.setInstance(newExpr); invCause.setInstance(newExpr);
invCause.setLstParameters( invCause.setLstParameters(
Collections.singletonList(new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null))); Collections.singletonList(new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)));
HANDLER_EXPR = new ExitExprent(ExitExprent.EXIT_THROW, invCause, null, null); HANDLER_EXPR = new ExitExprent(ExitExprent.EXIT_THROW, invCause, null, null);
} }
public static void processClassReferences(ClassNode node) { public static void processClassReferences(ClassNode node) {
// find the synthetic method Class class$(String) if present // find the synthetic method Class class$(String) if present
HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<>(); Map<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<>();
mapClassMethods(node, mapClassMeths); mapClassMethods(node, mapClassMeths);
if (mapClassMeths.isEmpty()) { if (mapClassMeths.isEmpty()) {
return; return;
} }
HashSet<ClassWrapper> setFound = new HashSet<>();
Set<ClassWrapper> setFound = new HashSet<>();
processClassRec(node, mapClassMeths, setFound); processClassRec(node, mapClassMeths, setFound);
if (!setFound.isEmpty()) { if (!setFound.isEmpty()) {
@ -76,15 +74,11 @@ public class ClassReference14Processor {
} }
} }
private static void processClassRec(ClassNode node, private static void processClassRec(ClassNode node, Map<ClassWrapper, MethodWrapper> mapClassMeths, Set<ClassWrapper> setFound) {
final HashMap<ClassWrapper, MethodWrapper> mapClassMeths, ClassWrapper wrapper = node.getWrapper();
final HashSet<ClassWrapper> setFound) {
final ClassWrapper wrapper = node.getWrapper();
// search code // search code
for (MethodWrapper meth : wrapper.getMethods()) { for (MethodWrapper meth : wrapper.getMethods()) {
RootStatement root = meth.root; RootStatement root = meth.root;
if (root != null) { if (root != null) {
DirectGraph graph = meth.getOrBuildGraph(); DirectGraph graph = meth.getOrBuildGraph();
@ -166,13 +160,10 @@ public class ClassReference14Processor {
} }
} }
private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) { private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
boolean res = false; boolean res = false;
while (true) { while (true) {
boolean found = false; boolean found = false;
for (Exprent expr : exprent.getAllExprents()) { for (Exprent expr : exprent.getAllExprents()) {
@ -195,9 +186,7 @@ public class ClassReference14Processor {
return res; return res;
} }
private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) { private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
if (exprent.type == Exprent.EXPRENT_FUNCTION) { if (exprent.type == Exprent.EXPRENT_FUNCTION) {
FunctionExprent fexpr = (FunctionExprent)exprent; FunctionExprent fexpr = (FunctionExprent)exprent;
if (fexpr.getFuncType() == FunctionExprent.FUNCTION_IIF) { if (fexpr.getFuncType() == FunctionExprent.FUNCTION_IIF) {

@ -647,11 +647,13 @@ public class ClassWriter {
descriptor = GenericMain.parseMethodSignature(attr.getSignature()); descriptor = GenericMain.parseMethodSignature(attr.getSignature());
if (descriptor != null) { if (descriptor != null) {
long actualParams = md.params.length; long actualParams = md.params.length;
List<VarVersionPair> sigFields = methodWrapper.signatureFields; List<VarVersionPair> mask = methodWrapper.synthParameters;
if (sigFields != null) { if (mask != null) {
actualParams = sigFields.stream().filter(Objects::isNull).count(); actualParams = mask.stream().filter(Objects::isNull).count();
}
else if (isEnum && init) {
actualParams -= 2;
} }
else if (isEnum && init) actualParams -= 2;
if (actualParams != descriptor.params.size()) { if (actualParams != descriptor.params.size()) {
String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName; String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName;
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
@ -685,12 +687,11 @@ public class ClassWriter {
buffer.append(toValidJavaIdentifier(name)); buffer.append(toValidJavaIdentifier(name));
buffer.append('('); buffer.append('(');
// parameters List<VarVersionPair> mask = methodWrapper.synthParameters;
List<VarVersionPair> signFields = methodWrapper.signatureFields;
int lastVisibleParameterIndex = -1; int lastVisibleParameterIndex = -1;
for (int i = 0; i < md.params.length; i++) { for (int i = 0; i < md.params.length; i++) {
if (signFields == null || signFields.get(i) == null) { if (mask == null || mask.get(i) == null) {
lastVisibleParameterIndex = i; lastVisibleParameterIndex = i;
} }
} }
@ -701,7 +702,7 @@ public class ClassWriter {
int start = isEnum && init && !hasDescriptor ? 2 : 0; int start = isEnum && init && !hasDescriptor ? 2 : 0;
int params = hasDescriptor ? descriptor.params.size() : md.params.length; int params = hasDescriptor ? descriptor.params.size() : md.params.length;
for (int i = start; i < params; i++) { for (int i = start; i < params; i++) {
if (hasDescriptor || (signFields == null || signFields.get(i) == null)) { if (hasDescriptor || mask == null || mask.get(i) == null) {
if (!firstParameter) { if (!firstParameter) {
buffer.append(", "); buffer.append(", ");
} }

@ -11,16 +11,17 @@ import org.jetbrains.java.decompiler.struct.StructMethod;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class MethodWrapper { public class MethodWrapper {
public final RootStatement root; public final RootStatement root;
public final VarProcessor varproc; public final VarProcessor varproc;
public final StructMethod methodStruct; public final StructMethod methodStruct;
public final CounterContainer counter; public final CounterContainer counter;
public final HashSet<String> setOuterVarNames = new HashSet<>(); public final Set<String> setOuterVarNames = new HashSet<>();
public DirectGraph graph; public DirectGraph graph;
public List<VarVersionPair> signatureFields; public List<VarVersionPair> synthParameters;
public boolean decompiledWithErrors; public boolean decompiledWithErrors;
public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) { public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {

@ -28,7 +28,6 @@ import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
public class NestedClassProcessor { public class NestedClassProcessor {
public void processClass(ClassNode root, ClassNode node) { public void processClass(ClassNode root, ClassNode node) {
// hide synthetic lambda content methods // hide synthetic lambda content methods
if (node.type == ClassNode.CLASS_LAMBDA && !node.lambdaInformation.is_method_reference) { if (node.type == ClassNode.CLASS_LAMBDA && !node.lambdaInformation.is_method_reference) {
@ -93,22 +92,18 @@ public class NestedClassProcessor {
} }
MethodWrapper method = parent.getWrapper().getMethods().getWithKey(child.lambdaInformation.content_method_key); MethodWrapper method = parent.getWrapper().getMethods().getWithKey(child.lambdaInformation.content_method_key);
final MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod);
MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambdaInformation.method_descriptor); MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambdaInformation.method_descriptor);
final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambdaInformation.content_method_descriptor); MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambdaInformation.content_method_descriptor);
final int vars_count = md_content.params.length - md_lambda.params.length;
// if(vars_count < 0) { // should not happen, but just in case...
// vars_count = 0;
// }
final boolean is_static_lambda_content = child.lambdaInformation.is_content_method_static; int vars_count = md_content.params.length - md_lambda.params.length;
boolean is_static_lambda_content = child.lambdaInformation.is_content_method_static;
String parent_class_name = parent.getWrapper().getClassStruct().qualifiedName; String parent_class_name = parent.getWrapper().getClassStruct().qualifiedName;
String lambda_class_name = child.simpleName; String lambda_class_name = child.simpleName;
final VarType lambda_class_type = new VarType(lambda_class_name, true); VarType lambda_class_type = new VarType(lambda_class_name, true);
// this pointer // this pointer
if (!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) { if (!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
@ -116,7 +111,7 @@ public class NestedClassProcessor {
method.varproc.setVarName(new VarVersionPair(0, 0), parent.simpleName + ".this"); method.varproc.setVarName(new VarVersionPair(0, 0), parent.simpleName + ".this");
} }
final Map<VarVersionPair, String> mapNewNames = new HashMap<>(); Map<VarVersionPair, String> mapNewNames = new HashMap<>();
enclosingMethod.getOrBuildGraph().iterateExprents(exprent -> { enclosingMethod.getOrBuildGraph().iterateExprents(exprent -> {
List<Exprent> lst = exprent.getAllExprents(true); List<Exprent> lst = exprent.getAllExprents(true);
@ -172,7 +167,7 @@ public class NestedClassProcessor {
List<ClassNode> copy = new ArrayList<>(node.nested); List<ClassNode> copy = new ArrayList<>(node.nested);
for (ClassNode child : copy) { for (ClassNode child : copy) {
if (child.classStruct.hasModifier(CodeConstants.ACC_SYNTHETIC)) { if (child.classStruct.isSynthetic()) {
continue; continue;
} }
@ -234,19 +229,15 @@ public class NestedClassProcessor {
return false; return false;
} }
private static void computeLocalVarsAndDefinitions(final ClassNode node) { private static void computeLocalVarsAndDefinitions(ClassNode node) {
// local var masks // class name -> constructor descriptor -> var to field link
// class name, constructor descriptor, field mask Map<String, Map<String, List<VarFieldPair>>> mapVarMasks = new HashMap<>();
final Map<String, Map<String, List<VarFieldPair>>> mapVarMasks = new HashMap<>();
int clTypes = 0; int clTypes = 0;
for (ClassNode nd : node.nested) { for (ClassNode nd : node.nested) {
if (nd.classStruct.hasModifier(CodeConstants.ACC_SYNTHETIC)) {
continue;
}
if (nd.type != ClassNode.CLASS_LAMBDA && if (nd.type != ClassNode.CLASS_LAMBDA &&
!nd.classStruct.isSynthetic() &&
(nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_STATIC) == 0 &&
(nd.access & CodeConstants.ACC_INTERFACE) == 0) { (nd.access & CodeConstants.ACC_INTERFACE) == 0) {
clTypes |= nd.type; clTypes |= nd.type;
@ -263,11 +254,11 @@ public class NestedClassProcessor {
} }
// local var masks // local var masks
final Map<String, Map<String, List<VarFieldPair>>> mapVarFieldPairs = new HashMap<>(); Map<String, Map<String, List<VarFieldPair>>> mapVarFieldPairs = new HashMap<>();
if (clTypes != ClassNode.CLASS_MEMBER) { if (clTypes != ClassNode.CLASS_MEMBER) {
// iterate enclosing class // iterate enclosing class
for (final MethodWrapper method : node.getWrapper().getMethods()) { for (MethodWrapper method : node.getWrapper().getMethods()) {
if (method.root != null) { // neither abstract, nor native if (method.root != null) { // neither abstract, nor native
method.getOrBuildGraph().iterateExprents(exprent -> { method.getOrBuildGraph().iterateExprents(exprent -> {
List<Exprent> lst = exprent.getAllExprents(true); List<Exprent> lst = exprent.getAllExprents(true);
@ -388,34 +379,33 @@ public class NestedClassProcessor {
for (Entry<String, List<VarFieldPair>> entry : enclosing.getValue().entrySet()) { for (Entry<String, List<VarFieldPair>> entry : enclosing.getValue().entrySet()) {
mergeListSignatures(entry.getValue(), interPairMask, false); mergeListSignatures(entry.getValue(), interPairMask, false);
MethodWrapper method = nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entry.getKey()); List<VarVersionPair> mask = new ArrayList<>(entry.getValue().size());
method.signatureFields = new ArrayList<>();
boolean firstSignField = nestedNode.type != ClassNode.CLASS_ANONYMOUS; boolean firstSignField = nestedNode.type != ClassNode.CLASS_ANONYMOUS;
for (VarFieldPair pair : entry.getValue()) { for (VarFieldPair pair : entry.getValue()) {
method.signatureFields.add(pair == null || (!firstSignField && pair.fieldKey.isEmpty()) ? null : pair.varPair); mask.add(pair == null || (!firstSignField && pair.fieldKey.isEmpty()) ? null : pair.varPair);
firstSignField = false; firstSignField = false;
} }
nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entry.getKey()).synthParameters = mask;
} }
} }
} }
private static void insertLocalVars(ClassNode parent, final ClassNode child) { private static void insertLocalVars(ClassNode parent, ClassNode child) {
// enclosing method, is null iff member class // enclosing method, is null iff member class
MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod);
// iterate all child methods // iterate all child methods
for (final MethodWrapper method : child.getWrapper().getMethods()) { for (MethodWrapper method : child.getWrapper().getMethods()) {
if (method.root != null) { // neither abstract nor native if (method.root != null) { // neither abstract nor native
Map<VarVersionPair, String> mapNewNames = new HashMap<>(); // local var names Map<VarVersionPair, String> mapNewNames = new HashMap<>(); // local var names
Map<VarVersionPair, VarType> mapNewTypes = new HashMap<>(); // local var types Map<VarVersionPair, VarType> mapNewTypes = new HashMap<>(); // local var types
final Map<Integer, VarVersionPair> mapParamsToNewVars = new HashMap<>(); Map<Integer, VarVersionPair> mapParamsToNewVars = new HashMap<>();
if (method.signatureFields != null) { if (method.synthParameters != null) {
int index = 0, varIndex = 1; int index = 0, varIndex = 1;
MethodDescriptor md = MethodDescriptor.parseDescriptor(method.methodStruct.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(method.methodStruct.getDescriptor());
for (VarVersionPair pair : method.signatureFields) { for (VarVersionPair pair : method.synthParameters) {
if (pair != null) { if (pair != null) {
VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
@ -450,7 +440,7 @@ public class NestedClassProcessor {
} }
} }
final Map<String, VarVersionPair> mapFieldsToNewVars = new HashMap<>(); Map<String, VarVersionPair> mapFieldsToNewVars = new HashMap<>();
for (ClassNode classNode = child; classNode != null; classNode = classNode.parent) { for (ClassNode classNode = child; classNode != null; classNode = classNode.parent) {
for (Entry<String, VarVersionPair> entry : classNode.mapFieldsToVars.entrySet()) { for (Entry<String, VarVersionPair> entry : classNode.mapFieldsToVars.entrySet()) {
VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
@ -632,10 +622,10 @@ public class NestedClassProcessor {
assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) { assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
FieldExprent left = (FieldExprent)assignExpr.getLeft(); FieldExprent left = (FieldExprent)assignExpr.getLeft();
StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString); StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString);
if (fd != null &&
if (fd != null && cl.qualifiedName.equals(left.getClassname()) && cl.qualifiedName.equals(left.getClassname()) &&
fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_FINAL) &&
(fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) { (fd.isSynthetic() || noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE))) {
// local (== not inherited) field // local (== not inherited) field
field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString);
break; break;

@ -9,39 +9,25 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
public class IfHelper { public class IfHelper {
public static boolean mergeAllIfs(RootStatement root) { public static boolean mergeAllIfs(RootStatement root) {
boolean res = mergeAllIfsRec(root, new HashSet<>()); boolean res = mergeAllIfsRec(root, new HashSet<>());
if (res) { if (res) {
SequenceHelper.condenseSequences(root); SequenceHelper.condenseSequences(root);
} }
return res; return res;
} }
private static boolean mergeAllIfsRec(Statement stat, Set<Integer> setReorderedIfs) {
private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
boolean res = false; boolean res = false;
if (stat.getExprents() == null) { if (stat.getExprents() == null) {
while (true) { while (true) {
boolean changed = false; boolean changed = false;
for (Statement st : stat.getStats()) { for (Statement st : stat.getStats()) {
res |= mergeAllIfsRec(st, setReorderedIfs); res |= mergeAllIfsRec(st, setReorderedIfs);
// collapse composed if's // collapse composed if's
@ -61,7 +47,7 @@ public class IfHelper {
return res; return res;
} }
public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) { public static boolean mergeIfs(Statement statement, Set<Integer> setReorderedIfs) {
if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) { if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
return false; return false;
} }
@ -193,11 +179,9 @@ public class IfHelper {
} }
private static boolean collapseIfElse(IfNode rtnode) { private static boolean collapseIfElse(IfNode rtnode) {
if (rtnode.edgetypes.get(0) == 0) { if (rtnode.edgetypes.get(0) == 0) {
IfNode ifbranch = rtnode.succs.get(0); IfNode ifbranch = rtnode.succs.get(0);
if (ifbranch.succs.size() == 2) { if (ifbranch.succs.size() == 2) {
// if-else branch // if-else branch
if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) { if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
@ -245,9 +229,7 @@ public class IfHelper {
return false; return false;
} }
private static boolean collapseElse(IfNode rtnode) { private static boolean collapseElse(IfNode rtnode) {
if (rtnode.edgetypes.get(1) == 0) { if (rtnode.edgetypes.get(1) == 0) {
IfNode elsebranch = rtnode.succs.get(1); IfNode elsebranch = rtnode.succs.get(1);
if (elsebranch.succs.size() == 2) { if (elsebranch.succs.size() == 2) {
@ -308,9 +290,7 @@ public class IfHelper {
} }
} }
else if (elsebranch.succs.size() == 1) { else if (elsebranch.succs.size() == 1) {
if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) { if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
IfStatement firstif = (IfStatement)rtnode.value; IfStatement firstif = (IfStatement)rtnode.value;
Statement second = elsebranch.value; Statement second = elsebranch.value;
@ -349,9 +329,7 @@ public class IfHelper {
return false; return false;
} }
private static IfNode buildGraph(IfStatement stat, boolean stsingle) { private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
if (stat.iftype == IfStatement.IFTYPE_IFELSE) { if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
return null; return null;
} }
@ -664,9 +642,7 @@ public class IfHelper {
return false; return false;
} }
private static Statement getNextStatement(Statement stat) { private static Statement getNextStatement(Statement stat) {
Statement parent = stat.getParent(); Statement parent = stat.getParent();
switch (parent.type) { switch (parent.type) {
case Statement.TYPE_ROOT: case Statement.TYPE_ROOT:
@ -688,7 +664,6 @@ public class IfHelper {
} }
private static boolean existsPath(Statement from, Statement to) { private static boolean existsPath(Statement from, Statement to) {
for (StatEdge edge : to.getAllPredecessorEdges()) { for (StatEdge edge : to.getAllPredecessorEdges()) {
if (from.containsStatementStrict(edge.getSource())) { if (from.containsStatementStrict(edge.getSource())) {
return true; return true;
@ -700,7 +675,6 @@ public class IfHelper {
private static class IfNode { private static class IfNode {
public final Statement value; public final Statement value;
public final List<IfNode> succs = new ArrayList<>(); public final List<IfNode> succs = new ArrayList<>();
public final List<Integer> edgetypes = new ArrayList<>(); public final List<Integer> edgetypes = new ArrayList<>();

@ -21,7 +21,29 @@ import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
public class SimplifyExprentsHelper { public class SimplifyExprentsHelper {
static final MatchEngine class14Builder = new MatchEngine(); @SuppressWarnings("SpellCheckingInspection") private static final MatchEngine class14Builder = new MatchEngine(
"statement type:if iftype:if exprsize:-1\n" +
" exprent position:head type:if\n" +
" exprent type:function functype:eq\n" +
" exprent type:field name:$fieldname$\n" +
" exprent type:constant consttype:null\n" +
" statement type:basicblock\n" +
" exprent position:-1 type:assignment ret:$assignfield$\n" +
" exprent type:var index:$var$\n" +
" exprent type:field name:$fieldname$\n" +
" statement type:sequence statsize:2\n" +
" statement type:trycatch\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:var index:$var$\n" +
" exprent type:invocation invclass:java/lang/Class signature:forName(Ljava/lang/String;)Ljava/lang/Class;\n" +
" exprent position:0 type:constant consttype:string constvalue:$classname$\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:exit exittype:throw\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:field name:$fieldname$ ret:$field$\n" +
" exprent type:var index:$var$");
private final boolean firstInvocation; private final boolean firstInvocation;
@ -29,10 +51,11 @@ public class SimplifyExprentsHelper {
this.firstInvocation = firstInvocation; this.firstInvocation = firstInvocation;
} }
public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) { public boolean simplifyStackVarsStatement(Statement stat, Set<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) {
boolean res = false; boolean res = false;
if (stat.getExprents() == null) { List<Exprent> expressions = stat.getExprents();
if (expressions == null) {
boolean processClass14 = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4); boolean processClass14 = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4);
while (true) { while (true) {
@ -65,7 +88,7 @@ public class SimplifyExprentsHelper {
} }
} }
else { else {
res = simplifyStackVarsExprents(stat.getExprents(), cl); res = simplifyStackVarsExprents(expressions, cl);
} }
return res; return res;
@ -75,7 +98,6 @@ public class SimplifyExprentsHelper {
boolean res = false; boolean res = false;
int index = 0; int index = 0;
while (index < list.size()) { while (index < list.size()) {
Exprent current = list.get(index); Exprent current = list.get(index);
@ -131,9 +153,9 @@ public class SimplifyExprentsHelper {
} }
// direct initialization of an array // direct initialization of an array
int arrcount = isArrayInitializer(list, index); int arrCount = isArrayInitializer(list, index);
if (arrcount > 0) { if (arrCount > 0) {
for (int i = 0; i < arrcount; i++) { for (int i = 0; i < arrCount; i++) {
list.remove(index + 1); list.remove(index + 1);
} }
res = true; res = true;
@ -163,13 +185,13 @@ public class SimplifyExprentsHelper {
} }
// assignment on stack // assignment on stack
if (isStackAssignement(current, next)) { if (isStackAssignment(current, next)) {
list.remove(index + 1); list.remove(index + 1);
res = true; res = true;
continue; continue;
} }
if (!firstInvocation && isStackAssignement2(current, next)) { if (!firstInvocation && isStackAssignment2(current, next)) {
list.remove(index + 1); list.remove(index + 1);
res = true; res = true;
continue; continue;
@ -186,38 +208,38 @@ public class SimplifyExprentsHelper {
AssignmentExprent as = (AssignmentExprent)first; AssignmentExprent as = (AssignmentExprent)first;
if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) { if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
NewExprent newex = (NewExprent)as.getRight(); NewExprent newExpr = (NewExprent)as.getRight();
if (!newex.getLstArrayElements().isEmpty()) { if (!newExpr.getLstArrayElements().isEmpty()) {
VarExprent arrvar = (VarExprent)as.getLeft(); VarExprent arrVar = (VarExprent)as.getLeft();
if (second.type == Exprent.EXPRENT_ASSIGNMENT) { if (second.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent aas = (AssignmentExprent)second; AssignmentExprent aas = (AssignmentExprent)second;
if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) { if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
ArrayExprent arrex = (ArrayExprent)aas.getLeft(); ArrayExprent arrExpr = (ArrayExprent)aas.getLeft();
if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray()) if (arrExpr.getArray().type == Exprent.EXPRENT_VAR &&
&& arrex.getIndex().type == Exprent.EXPRENT_CONST) { arrVar.equals(arrExpr.getArray()) &&
arrExpr.getIndex().type == Exprent.EXPRENT_CONST) {
int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue(); int constValue = ((ConstExprent)arrExpr.getIndex()).getIntValue();
if (constvalue < newex.getLstArrayElements().size()) { if (constValue < newExpr.getLstArrayElements().size()) {
Exprent init = newex.getLstArrayElements().get(constvalue); Exprent init = newExpr.getLstArrayElements().get(constValue);
if (init.type == Exprent.EXPRENT_CONST) { if (init.type == Exprent.EXPRENT_CONST) {
ConstExprent cinit = (ConstExprent)init; ConstExprent cinit = (ConstExprent)init;
VarType arrtype = newex.getNewType().decreaseArrayDim(); VarType arrType = newExpr.getNewType().decreaseArrayDim();
ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype); ConstExprent defaultVal = ExprProcessor.getDefaultArrayValue(arrType);
if (cinit.equals(defaultval)) { if (cinit.equals(defaultVal)) {
Exprent tempexpr = aas.getRight(); Exprent tempExpr = aas.getRight();
if (!tempexpr.containsExprent(arrvar)) { if (!tempExpr.containsExprent(arrVar)) {
newex.getLstArrayElements().set(constvalue, tempexpr); newExpr.getLstArrayElements().set(constValue, tempExpr);
if (tempexpr.type == Exprent.EXPRENT_NEW) { if (tempExpr.type == Exprent.EXPRENT_NEW) {
NewExprent tempnewex = (NewExprent)tempexpr; NewExprent tempNewExpr = (NewExprent)tempExpr;
int dims = newex.getNewType().arrayDim; int dims = newExpr.getNewType().arrayDim;
if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) { if (dims > 1 && !tempNewExpr.getLstArrayElements().isEmpty()) {
tempnewex.setDirectArrayInit(true); tempNewExpr.setDirectArrayInit(true);
} }
} }
@ -242,19 +264,18 @@ public class SimplifyExprentsHelper {
AssignmentExprent as = (AssignmentExprent)current; AssignmentExprent as = (AssignmentExprent)current;
if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) { if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
NewExprent newex = (NewExprent)as.getRight(); NewExprent newExpr = (NewExprent)as.getRight();
if (newex.getExprType().arrayDim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() && if (newExpr.getExprType().arrayDim > 0 && newExpr.getLstDims().size() == 1 && newExpr.getLstArrayElements().isEmpty() &&
newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) { newExpr.getLstDims().get(0).type == Exprent.EXPRENT_CONST) {
int size = (Integer)((ConstExprent)newex.getLstDims().get(0)).getValue(); int size = (Integer)((ConstExprent)newExpr.getLstDims().get(0)).getValue();
if (size == 0) { if (size == 0) {
return 0; return 0;
} }
VarExprent arrvar = (VarExprent)as.getLeft(); VarExprent arrVar = (VarExprent)as.getLeft();
Map<Integer, Exprent> mapInit = new HashMap<>();
HashMap<Integer, Exprent> mapInit = new HashMap<>();
int i = 1; int i = 1;
while (index + i < list.size() && i <= size) { while (index + i < list.size() && i <= size) {
@ -264,17 +285,14 @@ public class SimplifyExprentsHelper {
if (expr.type == Exprent.EXPRENT_ASSIGNMENT) { if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent aas = (AssignmentExprent)expr; AssignmentExprent aas = (AssignmentExprent)expr;
if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) { if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
ArrayExprent arrex = (ArrayExprent)aas.getLeft(); ArrayExprent arrExpr = (ArrayExprent)aas.getLeft();
if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray()) if (arrExpr.getArray().type == Exprent.EXPRENT_VAR && arrVar.equals(arrExpr.getArray()) &&
&& arrex.getIndex().type == Exprent.EXPRENT_CONST) { arrExpr.getIndex().type == Exprent.EXPRENT_CONST) {
// TODO: check for a number type. Failure extremely improbable, but nevertheless...
int constvalue = ((ConstExprent)arrex.getIndex()) int constValue = ((ConstExprent)arrExpr.getIndex()).getIntValue();
.getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless... if (constValue < size && !mapInit.containsKey(constValue)) {
if (!aas.getRight().containsExprent(arrVar)) {
if (constvalue < size && !mapInit.containsKey(constvalue)) { mapInit.put(constValue, aas.getRight());
if (!aas.getRight().containsExprent(arrvar)) {
mapInit.put(constvalue, aas.getRight());
found = true; found = true;
} }
} }
@ -291,33 +309,29 @@ public class SimplifyExprentsHelper {
double fraction = ((double)mapInit.size()) / size; double fraction = ((double)mapInit.size()) / size;
if ((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) || if ((arrVar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) || (size > 7 && fraction >= 0.7)) {
(size > 7 && fraction >= 0.7)) {
List<Exprent> lstRet = new ArrayList<>(); List<Exprent> lstRet = new ArrayList<>();
VarType arrtype = newex.getNewType().decreaseArrayDim(); VarType arrayType = newExpr.getNewType().decreaseArrayDim();
ConstExprent defaultVal = ExprProcessor.getDefaultArrayValue(arrayType);
ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
for (int j = 0; j < size; j++) { for (int j = 0; j < size; j++) {
lstRet.add(defaultval.copy()); lstRet.add(defaultVal.copy());
} }
int dims = newex.getNewType().arrayDim; int dims = newExpr.getNewType().arrayDim;
for (Entry<Integer, Exprent> ent : mapInit.entrySet()) { for (Entry<Integer, Exprent> ent : mapInit.entrySet()) {
Exprent tempexpr = ent.getValue(); Exprent tempExpr = ent.getValue();
lstRet.set(ent.getKey(), tempexpr); lstRet.set(ent.getKey(), tempExpr);
if (tempexpr.type == Exprent.EXPRENT_NEW) { if (tempExpr.type == Exprent.EXPRENT_NEW) {
NewExprent tempnewex = (NewExprent)tempexpr; NewExprent tempNewExpr = (NewExprent)tempExpr;
if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) { if (dims > 1 && !tempNewExpr.getLstArrayElements().isEmpty()) {
tempnewex.setDirectArrayInit(true); tempNewExpr.setDirectArrayInit(true);
} }
} }
} }
newex.setLstArrayElements(lstRet); newExpr.setLstArrayElements(lstRet);
return mapInit.size(); return mapInit.size();
} }
@ -333,17 +347,16 @@ public class SimplifyExprentsHelper {
AssignmentExprent asf = (AssignmentExprent)first; AssignmentExprent asf = (AssignmentExprent)first;
if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) { if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) {
VarExprent varleft = (VarExprent)asf.getLeft(); VarExprent left = (VarExprent)asf.getLeft();
VarExprent varright = (VarExprent)asf.getRight(); VarExprent right = (VarExprent)asf.getRight();
return left.getIndex() == right.getIndex() && left.isStack() && right.isStack();
return varleft.getIndex() == varright.getIndex() && varleft.isStack() && varright.isStack();
} }
} }
return false; return false;
} }
private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation private static boolean isStackAssignment2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) { if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent asf = (AssignmentExprent)first; AssignmentExprent asf = (AssignmentExprent)first;
AssignmentExprent ass = (AssignmentExprent)second; AssignmentExprent ass = (AssignmentExprent)second;
@ -360,7 +373,7 @@ public class SimplifyExprentsHelper {
return false; return false;
} }
private static boolean isStackAssignement(Exprent first, Exprent second) { private static boolean isStackAssignment(Exprent first, Exprent second) {
if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) { if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent asf = (AssignmentExprent)first; AssignmentExprent asf = (AssignmentExprent)first;
AssignmentExprent ass = (AssignmentExprent)second; AssignmentExprent ass = (AssignmentExprent)second;
@ -395,8 +408,7 @@ public class SimplifyExprentsHelper {
if (as.getRight().type == Exprent.EXPRENT_FUNCTION) { if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
FunctionExprent func = (FunctionExprent)as.getRight(); FunctionExprent func = (FunctionExprent)as.getRight();
if (func.getFuncType() == FunctionExprent.FUNCTION_ADD || if (func.getFuncType() == FunctionExprent.FUNCTION_ADD || func.getFuncType() == FunctionExprent.FUNCTION_SUB) {
func.getFuncType() == FunctionExprent.FUNCTION_SUB) {
Exprent econd = func.getLstOperands().get(0); Exprent econd = func.getLstOperands().get(0);
Exprent econst = func.getLstOperands().get(1); Exprent econst = func.getLstOperands().get(1);
@ -410,9 +422,8 @@ public class SimplifyExprentsHelper {
Exprent left = as.getLeft(); Exprent left = as.getLeft();
if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) { if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) {
FunctionExprent ret = new FunctionExprent( int type = func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI;
func.getFuncType() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI, FunctionExprent ret = new FunctionExprent(type, econd, func.bytecode);
econd, func.bytecode);
ret.setImplicitType(VarType.VARTYPE_INT); ret.setImplicitType(VarType.VARTYPE_INT);
return ret; return ret;
} }
@ -449,10 +460,10 @@ public class SimplifyExprentsHelper {
private static boolean isMonitorExit(Exprent first) { private static boolean isMonitorExit(Exprent first) {
if (first.type == Exprent.EXPRENT_MONITOR) { if (first.type == Exprent.EXPRENT_MONITOR) {
MonitorExprent monexpr = (MonitorExprent)first; MonitorExprent expr = (MonitorExprent)first;
return monexpr.getMonType() == MonitorExprent.MONITOR_EXIT && return expr.getMonType() == MonitorExprent.MONITOR_EXIT &&
monexpr.getValue().type == Exprent.EXPRENT_VAR && expr.getValue().type == Exprent.EXPRENT_VAR &&
!((VarExprent)monexpr.getValue()).isStack(); !((VarExprent)expr.getValue()).isStack();
} }
return false; return false;
@ -460,21 +471,21 @@ public class SimplifyExprentsHelper {
private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) { private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) {
if (first.type == Exprent.EXPRENT_INVOCATION) { if (first.type == Exprent.EXPRENT_INVOCATION) {
InvocationExprent invexpr = (InvocationExprent)first; InvocationExprent invocation = (InvocationExprent)first;
if (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") && if (!invocation.isStatic() && invocation.getInstance().type == Exprent.EXPRENT_VAR && invocation.getName().equals("getClass") &&
invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) { invocation.getStringDescriptor().equals("()Ljava/lang/Class;")) {
List<Exprent> lstExprents = second.getAllExprents(); List<Exprent> lstExprents = second.getAllExprents();
lstExprents.add(second); lstExprents.add(second);
for (Exprent expr : lstExprents) { for (Exprent expr : lstExprents) {
if (expr.type == Exprent.EXPRENT_NEW) { if (expr.type == Exprent.EXPRENT_NEW) {
NewExprent nexpr = (NewExprent)expr; NewExprent newExpr = (NewExprent)expr;
if (nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() && if (newExpr.getConstructor() != null && !newExpr.getConstructor().getLstParameters().isEmpty() &&
nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) { newExpr.getConstructor().getLstParameters().get(0).equals(invocation.getInstance())) {
String classname = nexpr.getNewType().value; String classname = newExpr.getNewType().value;
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
if (node != null && node.type != ClassNode.CLASS_ROOT) { if (node != null && node.type != ClassNode.CLASS_ROOT) {
return true; return true;
@ -488,7 +499,7 @@ public class SimplifyExprentsHelper {
return false; return false;
} }
// propagate (var = new X) forward to the <init> invokation // propagate (var = new X) forward to the <init> invocation
private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) { private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
Exprent current = list.get(index); Exprent current = list.get(index);
@ -497,12 +508,11 @@ public class SimplifyExprentsHelper {
if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) { if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
NewExprent newexpr = (NewExprent)as.getRight(); NewExprent newExpr = (NewExprent)as.getRight();
VarType newtype = newexpr.getNewType(); VarType newType = newExpr.getNewType();
VarVersionPair leftPaar = new VarVersionPair((VarExprent)as.getLeft()); VarVersionPair leftPair = new VarVersionPair((VarExprent)as.getLeft());
if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arrayDim == 0 && newexpr.getConstructor() == null) {
if (newType.type == CodeConstants.TYPE_OBJECT && newType.arrayDim == 0 && newExpr.getConstructor() == null) {
for (int i = index + 1; i < list.size(); i++) { for (int i = index + 1; i < list.size(); i++) {
Exprent remote = list.get(i); Exprent remote = list.get(i);
@ -513,8 +523,7 @@ public class SimplifyExprentsHelper {
if (in.getFunctype() == InvocationExprent.TYP_INIT && if (in.getFunctype() == InvocationExprent.TYP_INIT &&
in.getInstance().type == Exprent.EXPRENT_VAR && in.getInstance().type == Exprent.EXPRENT_VAR &&
as.getLeft().equals(in.getInstance())) { as.getLeft().equals(in.getInstance())) {
newExpr.setConstructor(in);
newexpr.setConstructor(in);
in.setInstance(null); in.setInstance(null);
list.set(i, as.copy()); list.set(i, as.copy());
@ -525,7 +534,7 @@ public class SimplifyExprentsHelper {
// check for variable in use // check for variable in use
Set<VarVersionPair> setVars = remote.getAllVariables(); Set<VarVersionPair> setVars = remote.getAllVariables();
if (setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code if (setVars.contains(leftPair)) { // variable used somewhere in between -> exit, need a better reduced code
return false; return false;
} }
} }
@ -553,13 +562,13 @@ public class SimplifyExprentsHelper {
ClassNode lambda_class = DecompilerContext.getClassProcessor().getMapRootClasses().get(lambda_class_name); ClassNode lambda_class = DecompilerContext.getClassProcessor().getMapRootClasses().get(lambda_class_name);
if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class
NewExprent newexp = new NewExprent(new VarType(lambda_class_name, true), null, 0, in.bytecode); NewExprent newExpr = new NewExprent(new VarType(lambda_class_name, true), null, 0, in.bytecode);
newexp.setConstructor(in); newExpr.setConstructor(in);
// note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invocation
// lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);) // lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);)
// in this case instance will hold the corresponding object // in this case instance will hold the corresponding object
return newexp; return newExpr;
} }
} }
} }
@ -579,10 +588,10 @@ public class SimplifyExprentsHelper {
if (exprent.type == Exprent.EXPRENT_INVOCATION) { if (exprent.type == Exprent.EXPRENT_INVOCATION) {
InvocationExprent in = (InvocationExprent)exprent; InvocationExprent in = (InvocationExprent)exprent;
if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) { if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) {
NewExprent newexp = (NewExprent)in.getInstance(); NewExprent newExpr = (NewExprent)in.getInstance();
newexp.setConstructor(in); newExpr.setConstructor(in);
in.setInstance(null); in.setInstance(null);
return newexp; return newExpr;
} }
} }
@ -591,37 +600,35 @@ public class SimplifyExprentsHelper {
private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) { private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) {
if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) { if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) {
IfStatement stif = (IfStatement)stat; IfStatement statement = (IfStatement)stat;
Exprent ifHeadExpr = statement.getHeadexprent();
Exprent ifheadexpr = stif.getHeadexprent(); Set<Integer> ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode);
Set<Integer> ifheadexpr_bytecode = (ifheadexpr == null ? null : ifheadexpr.bytecode);
if (statement.iftype == IfStatement.IFTYPE_IFELSE) {
if (stif.iftype == IfStatement.IFTYPE_IFELSE) { Statement ifStatement = statement.getIfstat();
Statement ifstat = stif.getIfstat(); Statement elseStatement = statement.getElsestat();
Statement elsestat = stif.getElsestat();
if (ifStatement.getExprents() != null && ifStatement.getExprents().size() == 1 &&
if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1 elseStatement.getExprents() != null && elseStatement.getExprents().size() == 1 &&
&& elsestat.getExprents() != null && elsestat.getExprents().size() == 1 ifStatement.getAllSuccessorEdges().size() == 1 && elseStatement.getAllSuccessorEdges().size() == 1 &&
&& ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1 ifStatement.getAllSuccessorEdges().get(0).getDestination() == elseStatement.getAllSuccessorEdges().get(0).getDestination()) {
&& ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) { Exprent ifExpr = ifStatement.getExprents().get(0);
Exprent elseExpr = elseStatement.getExprents().get(0);
Exprent ifexpr = ifstat.getExprents().get(0);
Exprent elseexpr = elsestat.getExprents().get(0); if (ifExpr.type == Exprent.EXPRENT_ASSIGNMENT && elseExpr.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent ifAssign = (AssignmentExprent)ifExpr;
if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) { AssignmentExprent elseAssign = (AssignmentExprent)elseExpr;
AssignmentExprent ifas = (AssignmentExprent)ifexpr;
AssignmentExprent elseas = (AssignmentExprent)elseexpr; if (ifAssign.getLeft().type == Exprent.EXPRENT_VAR && elseAssign.getLeft().type == Exprent.EXPRENT_VAR) {
VarExprent ifVar = (VarExprent)ifAssign.getLeft();
if (ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) { VarExprent elseVar = (VarExprent)elseAssign.getLeft();
VarExprent ifvar = (VarExprent)ifas.getLeft();
VarExprent elsevar = (VarExprent)elseas.getLeft(); if (ifVar.getIndex() == elseVar.getIndex() && ifVar.isStack()) { // ifVar.getIndex() >= VarExprent.STACK_BASE) {
if (ifvar.getIndex() == elsevar.getIndex() && ifvar.isStack()) { // ifvar.getIndex() >= VarExprent.STACK_BASE) {
boolean found = false; boolean found = false;
for (Entry<VarVersionPair, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) { for (Entry<VarVersionPair, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
if (ent.getKey().var == ifvar.getIndex()) { if (ent.getKey().var == ifVar.getIndex()) {
if (ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) { if (ent.getValue().contains(ifVar.getVersion()) && ent.getValue().contains(elseVar.getVersion())) {
found = true; found = true;
break; break;
} }
@ -629,65 +636,61 @@ public class SimplifyExprentsHelper {
} }
if (found) { if (found) {
List<Exprent> data = new ArrayList<>(stif.getFirst().getExprents()); List<Exprent> data = new ArrayList<>(statement.getFirst().getExprents());
data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF, List<Exprent> operands = Arrays.asList(statement.getHeadexprent().getCondition(), ifAssign.getRight(), elseAssign.getRight());
Arrays.asList( data.add(new AssignmentExprent(ifVar, new FunctionExprent(FunctionExprent.FUNCTION_IIF, operands, ifHeadExprBytecode), ifHeadExprBytecode));
stif.getHeadexprent().getCondition(), statement.setExprents(data);
ifas.getRight(),
elseas.getRight()), ifheadexpr_bytecode), ifheadexpr_bytecode)); if (statement.getAllSuccessorEdges().isEmpty()) {
stif.setExprents(data); StatEdge ifEdge = ifStatement.getAllSuccessorEdges().get(0);
StatEdge edge = new StatEdge(ifEdge.getType(), statement, ifEdge.getDestination());
if (stif.getAllSuccessorEdges().isEmpty()) {
StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0); statement.addSuccessor(edge);
StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination()); if (ifEdge.closure != null) {
ifEdge.closure.addLabeledEdge(edge);
stif.addSuccessor(edge);
if (ifedge.closure != null) {
ifedge.closure.addLabeledEdge(edge);
} }
} }
SequenceHelper.destroyAndFlattenStatement(stif); SequenceHelper.destroyAndFlattenStatement(statement);
return true; return true;
} }
} }
} }
} }
else if (ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) { else if (ifExpr.type == Exprent.EXPRENT_EXIT && elseExpr.type == Exprent.EXPRENT_EXIT) {
ExitExprent ifex = (ExitExprent)ifexpr; ExitExprent ifExit = (ExitExprent)ifExpr;
ExitExprent elseex = (ExitExprent)elseexpr; ExitExprent elseExit = (ExitExprent)elseExpr;
if (ifex.getExitType() == elseex.getExitType() && ifex.getValue() != null && elseex.getValue() != null &&
ifex.getExitType() == ExitExprent.EXIT_RETURN) {
if (ifExit.getExitType() == elseExit.getExitType() && ifExit.getValue() != null && elseExit.getValue() != null &&
ifExit.getExitType() == ExitExprent.EXIT_RETURN) {
// throw is dangerous, because of implicit casting to a common superclass // throw is dangerous, because of implicit casting to a common superclass
// e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work // e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work
if (ifex.getExitType() == ExitExprent.EXIT_THROW && if (ifExit.getExitType() == ExitExprent.EXIT_THROW &&
!ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point! !ifExit.getValue().getExprType().equals(elseExit.getValue().getExprType())) { // note: getExprType unreliable at this point!
return false; return false;
} }
// avoid flattening to 'iff' if any of the branches is an 'iff' already // avoid flattening to 'iff' if any of the branches is an 'iff' already
if (isIff(ifex.getValue()) || isIff(elseex.getValue())) { if (isIff(ifExit.getValue()) || isIff(elseExit.getValue())) {
return false; return false;
} }
List<Exprent> data = new ArrayList<>(stif.getFirst().getExprents()); List<Exprent> data = new ArrayList<>(statement.getFirst().getExprents());
data.add(new ExitExprent(ifex.getExitType(), new FunctionExprent(FunctionExprent.FUNCTION_IIF, data.add(new ExitExprent(ifExit.getExitType(), new FunctionExprent(FunctionExprent.FUNCTION_IIF,
Arrays.asList( Arrays.asList(
stif.getHeadexprent().getCondition(), statement.getHeadexprent().getCondition(),
ifex.getValue(), ifExit.getValue(),
elseex.getValue()), ifheadexpr_bytecode), ifex.getRetType(), ifheadexpr_bytecode)); elseExit.getValue()), ifHeadExprBytecode), ifExit.getRetType(), ifHeadExprBytecode));
stif.setExprents(data); statement.setExprents(data);
StatEdge retedge = ifstat.getAllSuccessorEdges().get(0); StatEdge retEdge = ifStatement.getAllSuccessorEdges().get(0);
stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(), Statement closure = retEdge.closure == statement ? statement.getParent() : retEdge.closure;
retedge.closure == stif ? stif.getParent() : retedge.closure)); statement.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, statement, retEdge.getDestination(), closure));
SequenceHelper.destroyAndFlattenStatement(stif); SequenceHelper.destroyAndFlattenStatement(statement);
return true; return true;
} }
@ -703,41 +706,14 @@ public class SimplifyExprentsHelper {
return exp.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent) exp).getFuncType() == FunctionExprent.FUNCTION_IIF; return exp.type == Exprent.EXPRENT_FUNCTION && ((FunctionExprent) exp).getFuncType() == FunctionExprent.FUNCTION_IIF;
} }
static {
class14Builder.parse(
"statement type:if iftype:if exprsize:-1\n" +
" exprent position:head type:if\n" +
" exprent type:function functype:eq\n" +
" exprent type:field name:$fieldname$\n" +
" exprent type:constant consttype:null\n" +
" statement type:basicblock\n" +
" exprent position:-1 type:assignment ret:$assignfield$\n" +
" exprent type:var index:$var$\n" +
" exprent type:field name:$fieldname$\n" +
" statement type:sequence statsize:2\n" +
" statement type:trycatch\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:var index:$var$\n" +
" exprent type:invocation invclass:java/lang/Class signature:forName(Ljava/lang/String;)Ljava/lang/Class;\n" +
" exprent position:0 type:constant consttype:string constvalue:$classname$\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:exit exittype:throw\n" +
" statement type:basicblock exprsize:1\n" +
" exprent type:assignment\n" +
" exprent type:field name:$fieldname$ ret:$field$\n" +
" exprent type:var index:$var$"
);
}
private static boolean collapseInlinedClass14(Statement stat) { private static boolean collapseInlinedClass14(Statement stat) {
boolean ret = class14Builder.match(stat); boolean ret = class14Builder.match(stat);
if (ret) { if (ret) {
String class_name = (String)class14Builder.getVariableValue("$classname$"); String class_name = (String)class14Builder.getVariableValue("$classname$");
AssignmentExprent assfirst = (AssignmentExprent)class14Builder.getVariableValue("$assignfield$"); AssignmentExprent assignment = (AssignmentExprent)class14Builder.getVariableValue("$assignfield$");
FieldExprent fieldexpr = (FieldExprent)class14Builder.getVariableValue("$field$"); FieldExprent fieldExpr = (FieldExprent)class14Builder.getVariableValue("$field$");
assfirst.replaceExprent(assfirst.getRight(), new ConstExprent(VarType.VARTYPE_CLASS, class_name, null)); assignment.replaceExprent(assignment.getRight(), new ConstExprent(VarType.VARTYPE_CLASS, class_name, null));
List<Exprent> data = new ArrayList<>(stat.getFirst().getExprents()); List<Exprent> data = new ArrayList<>(stat.getFirst().getExprents());
@ -747,7 +723,7 @@ public class SimplifyExprentsHelper {
ClassWrapper wrapper = (ClassWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_WRAPPER); ClassWrapper wrapper = (ClassWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_WRAPPER);
if (wrapper != null) { if (wrapper != null) {
wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fieldexpr.getName(), fieldexpr.getDescriptor().descriptorString)); wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fieldExpr.getName(), fieldExpr.getDescriptor().descriptorString));
} }
} }

@ -20,36 +20,22 @@ import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
public class StackVarsProcessor { public class StackVarsProcessor {
public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) { public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) {
Set<Integer> setReorderedIfs = new HashSet<>();
HashSet<Integer> setReorderedIfs = new HashSet<>();
SSAUConstructorSparseEx ssau = null; SSAUConstructorSparseEx ssau = null;
while (true) { while (true) {
boolean found = false; boolean found = false;
// System.out.println("--------------- \r\n"+root.toJava());
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx(); SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
ssa.splitVariables(root, mt); ssa.splitVariables(root, mt);
// System.out.println("--------------- \r\n"+root.toJava());
SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null); SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null);
while (sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) { while (sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) {
// System.out.println("--------------- \r\n"+root.toJava());
found = true; found = true;
} }
// System.out.println("=============== \r\n"+root.toJava());
setVersionsToNull(root); setVersionsToNull(root);
SequenceHelper.condenseSequences(root); SequenceHelper.condenseSequences(root);
@ -57,21 +43,10 @@ public class StackVarsProcessor {
ssau = new SSAUConstructorSparseEx(); ssau = new SSAUConstructorSparseEx();
ssau.splitVariables(root, mt); ssau.splitVariables(root, mt);
// try {
// DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
// } catch(Exception ex) {
// ex.printStackTrace();
// }
// System.out.println("++++++++++++++++ \r\n"+root.toJava());
if (iterateStatements(root, ssau)) { if (iterateStatements(root, ssau)) {
found = true; found = true;
} }
// System.out.println("***************** \r\n"+root.toJava());
setVersionsToNull(root); setVersionsToNull(root);
if (!found) { if (!found) {
@ -83,21 +58,12 @@ public class StackVarsProcessor {
ssau = new SSAUConstructorSparseEx(); ssau = new SSAUConstructorSparseEx();
ssau.splitVariables(root, mt); ssau.splitVariables(root, mt);
// try {
// DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
// } catch(Exception ex) {
// ex.printStackTrace();
// }
iterateStatements(root, ssau); iterateStatements(root, ssau);
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
setVersionsToNull(root); setVersionsToNull(root);
} }
private static void setVersionsToNull(Statement stat) { private static void setVersionsToNull(Statement stat) {
if (stat.getExprents() == null) { if (stat.getExprents() == null) {
for (Object obj : stat.getSequentialObjects()) { for (Object obj : stat.getSequentialObjects()) {
if (obj instanceof Statement) { if (obj instanceof Statement) {
@ -116,7 +82,6 @@ public class StackVarsProcessor {
} }
private static void setExprentVersionsToNull(Exprent exprent) { private static void setExprentVersionsToNull(Exprent exprent) {
List<Exprent> lst = exprent.getAllExprents(true); List<Exprent> lst = exprent.getAllExprents(true);
lst.add(exprent); lst.add(exprent);
@ -127,25 +92,22 @@ public class StackVarsProcessor {
} }
} }
private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) { private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) {
FlattenStatementsHelper flatthelper = new FlattenStatementsHelper(); FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
DirectGraph dgraph = flatthelper.buildDirectGraph(root); DirectGraph dgraph = flatthelper.buildDirectGraph(root);
boolean res = false; boolean res = false;
HashSet<DirectNode> setVisited = new HashSet<>(); Set<DirectNode> setVisited = new HashSet<>();
LinkedList<DirectNode> stack = new LinkedList<>(); LinkedList<DirectNode> stack = new LinkedList<>();
LinkedList<HashMap<VarVersionPair, Exprent>> stackMaps = new LinkedList<>(); LinkedList<Map<VarVersionPair, Exprent>> stackMaps = new LinkedList<>();
stack.add(dgraph.first); stack.add(dgraph.first);
stackMaps.add(new HashMap<>()); stackMaps.add(new HashMap<>());
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
DirectNode nd = stack.removeFirst(); DirectNode nd = stack.removeFirst();
HashMap<VarVersionPair, Exprent> mapVarValues = stackMaps.removeFirst(); Map<VarVersionPair, Exprent> mapVarValues = stackMaps.removeFirst();
if (setVisited.contains(nd)) { if (setVisited.contains(nd)) {
continue; continue;
@ -182,9 +144,6 @@ public class StackVarsProcessor {
} }
int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa); int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa);
//System.out.println("***************** \r\n"+root.toJava());
if (ret[0] >= 0) { if (ret[0] >= 0) {
index = ret[0]; index = ret[0];
} }
@ -221,26 +180,21 @@ public class StackVarsProcessor {
return res; return res;
} }
private static Exprent isReplaceableVar(Exprent exprent, Map<VarVersionPair, Exprent> mapVarValues) {
private static Exprent isReplaceableVar(Exprent exprent, HashMap<VarVersionPair, Exprent> mapVarValues) {
Exprent dest = null; Exprent dest = null;
if (exprent.type == Exprent.EXPRENT_VAR) { if (exprent.type == Exprent.EXPRENT_VAR) {
VarExprent var = (VarExprent)exprent; VarExprent var = (VarExprent)exprent;
dest = mapVarValues.get(new VarVersionPair(var)); dest = mapVarValues.get(new VarVersionPair(var));
} }
return dest; return dest;
} }
private static void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) { private static void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) {
parent.replaceExprent(var, dest); parent.replaceExprent(var, dest);
// live sets // live sets
SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPair(var)); SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPair(var));
HashSet<VarVersionPair> setVars = getAllVersions(dest); Set<VarVersionPair> setVars = getAllVersions(dest);
for (VarVersionPair varpaar : setVars) { for (VarVersionPair varpaar : setVars) {
VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar); VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar);
@ -265,9 +219,11 @@ public class StackVarsProcessor {
} }
} }
private int[] iterateExprent(List<Exprent> lstExprents, int index, Exprent next, HashMap<VarVersionPair, private int[] iterateExprent(List<Exprent> lstExprents,
Exprent> mapVarValues, SSAUConstructorSparseEx ssau) { int index,
Exprent next,
Map<VarVersionPair, Exprent> mapVarValues,
SSAUConstructorSparseEx ssau) {
Exprent exprent = lstExprents.get(index); Exprent exprent = lstExprents.get(index);
int changed = 0; int changed = 0;
@ -354,14 +310,14 @@ public class StackVarsProcessor {
return new int[]{-1, changed}; return new int[]{-1, changed};
} }
HashMap<Integer, HashSet<VarVersionPair>> mapVars = getAllVarVersions(leftpaar, right, ssau); Map<Integer, Set<VarVersionPair>> mapVars = getAllVarVersions(leftpaar, right, ssau);
boolean isSelfReference = mapVars.containsKey(leftpaar.var); boolean isSelfReference = mapVars.containsKey(leftpaar.var);
if (isSelfReference && notdom) { if (isSelfReference && notdom) {
return new int[]{-1, changed}; return new int[]{-1, changed};
} }
HashSet<VarVersionPair> setNextVars = next == null ? null : getAllVersions(next); Set<VarVersionPair> setNextVars = next == null ? null : getAllVersions(next);
// FIXME: fix the entire method! // FIXME: fix the entire method!
if (right.type != Exprent.EXPRENT_CONST && if (right.type != Exprent.EXPRENT_CONST &&
@ -380,8 +336,7 @@ public class StackVarsProcessor {
boolean vernotreplaced = false; boolean vernotreplaced = false;
boolean verreplaced = false; boolean verreplaced = false;
Set<VarVersionPair> setTempUsedVers = new HashSet<>();
HashSet<VarVersionPair> setTempUsedVers = new HashSet<>();
for (VarVersionNode usedvar : usedVers) { for (VarVersionNode usedvar : usedVers) {
VarVersionPair usedver = new VarVersionPair(usedvar.var, usedvar.version); VarVersionPair usedver = new VarVersionPair(usedvar.var, usedvar.version);
@ -424,9 +379,8 @@ public class StackVarsProcessor {
} }
} }
private static HashSet<VarVersionPair> getAllVersions(Exprent exprent) { private static Set<VarVersionPair> getAllVersions(Exprent exprent) {
Set<VarVersionPair> res = new HashSet<>();
HashSet<VarVersionPair> res = new HashSet<>();
List<Exprent> listTemp = new ArrayList<>(exprent.getAllExprents(true)); List<Exprent> listTemp = new ArrayList<>(exprent.getAllExprents(true));
listTemp.add(exprent); listTemp.add(exprent);
@ -444,9 +398,8 @@ public class StackVarsProcessor {
private static Object[] iterateChildExprent(Exprent exprent, private static Object[] iterateChildExprent(Exprent exprent,
Exprent parent, Exprent parent,
Exprent next, Exprent next,
HashMap<VarVersionPair, Exprent> mapVarValues, Map<VarVersionPair, Exprent> mapVarValues,
SSAUConstructorSparseEx ssau) { SSAUConstructorSparseEx ssau) {
boolean changed = false; boolean changed = false;
for (Exprent expr : exprent.getAllExprents()) { for (Exprent expr : exprent.getAllExprents()) {
@ -527,23 +480,21 @@ public class StackVarsProcessor {
return new Object[]{null, changed, false}; return new Object[]{null, changed, false};
} }
HashMap<Integer, HashSet<VarVersionPair>> mapVars = getAllVarVersions(leftpaar, right, ssau); Map<Integer, Set<VarVersionPair>> mapVars = getAllVarVersions(leftpaar, right, ssau);
if (mapVars.containsKey(leftpaar.var) && notdom) { if (mapVars.containsKey(leftpaar.var) && notdom) {
return new Object[]{null, changed, false}; return new Object[]{null, changed, false};
} }
mapVars.remove(leftpaar.var); mapVars.remove(leftpaar.var);
HashSet<VarVersionPair> setAllowedVars = getAllVersions(parent); Set<VarVersionPair> setAllowedVars = getAllVersions(parent);
if (next != null) { if (next != null) {
setAllowedVars.addAll(getAllVersions(next)); setAllowedVars.addAll(getAllVersions(next));
} }
boolean vernotreplaced = false; boolean vernotreplaced = false;
HashSet<VarVersionPair> setTempUsedVers = new HashSet<>(); Set<VarVersionPair> setTempUsedVers = new HashSet<>();
for (VarVersionNode usedvar : usedVers) { for (VarVersionNode usedvar : usedVers) {
VarVersionPair usedver = new VarVersionPair(usedvar.var, usedvar.version); VarVersionPair usedver = new VarVersionPair(usedvar.var, usedvar.version);
@ -558,7 +509,6 @@ public class StackVarsProcessor {
} }
if (!notdom && !vernotreplaced) { if (!notdom && !vernotreplaced) {
for (VarVersionPair usedver : setTempUsedVers) { for (VarVersionPair usedver : setTempUsedVers) {
Exprent copy = right.copy(); Exprent copy = right.copy();
if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) { if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
@ -576,19 +526,16 @@ public class StackVarsProcessor {
} }
private static boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPair var, List<VarVersionNode> res) { private static boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPair var, List<VarVersionNode> res) {
VarVersionsGraph ssuversions = ssa.getSsuversions(); VarVersionsGraph ssuversions = ssa.getSsuversions();
VarVersionNode varnode = ssuversions.nodes.getWithKey(var); VarVersionNode varnode = ssuversions.nodes.getWithKey(var);
HashSet<VarVersionNode> setVisited = new HashSet<>(); Set<VarVersionNode> setVisited = new HashSet<>();
Set<VarVersionNode> setNotDoms = new HashSet<>();
HashSet<VarVersionNode> setNotDoms = new HashSet<>();
LinkedList<VarVersionNode> stack = new LinkedList<>(); LinkedList<VarVersionNode> stack = new LinkedList<>();
stack.add(varnode); stack.add(varnode);
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
VarVersionNode nd = stack.remove(0); VarVersionNode nd = stack.remove(0);
setVisited.add(nd); setVisited.add(nd);
@ -625,10 +572,9 @@ public class StackVarsProcessor {
} }
private static boolean isVersionToBeReplaced(VarVersionPair usedvar, private static boolean isVersionToBeReplaced(VarVersionPair usedvar,
HashMap<Integer, HashSet<VarVersionPair>> mapVars, Map<Integer, Set<VarVersionPair>> mapVars,
SSAUConstructorSparseEx ssau, SSAUConstructorSparseEx ssau,
VarVersionPair leftpaar) { VarVersionPair leftpaar) {
VarVersionsGraph ssuversions = ssau.getSsuversions(); VarVersionsGraph ssuversions = ssau.getSsuversions();
SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar); SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar);
@ -643,13 +589,13 @@ public class StackVarsProcessor {
return false; return false;
} }
for (Entry<Integer, HashSet<VarVersionPair>> ent : mapVars.entrySet()) { for (Entry<Integer, Set<VarVersionPair>> ent : mapVars.entrySet()) {
FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey()); FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey());
if (liveverset == null) { if (liveverset == null) {
return false; return false;
} }
HashSet<VarVersionNode> domset = new HashSet<>(); Set<VarVersionNode> domset = new HashSet<>();
for (VarVersionPair verpaar : ent.getValue()) { for (VarVersionPair verpaar : ent.getValue()) {
domset.add(ssuversions.nodes.getWithKey(verpaar)); domset.add(ssuversions.nodes.getWithKey(verpaar));
} }
@ -673,11 +619,10 @@ public class StackVarsProcessor {
return true; return true;
} }
private static HashMap<Integer, HashSet<VarVersionPair>> getAllVarVersions(VarVersionPair leftvar, private static Map<Integer, Set<VarVersionPair>> getAllVarVersions(VarVersionPair leftvar,
Exprent exprent, Exprent exprent,
SSAUConstructorSparseEx ssau) { SSAUConstructorSparseEx ssau) {
Map<Integer, Set<VarVersionPair>> map = new HashMap<>();
HashMap<Integer, HashSet<VarVersionPair>> map = new HashMap<>();
SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar); SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar);
List<Exprent> lst = exprent.getAllExprents(true); List<Exprent> lst = exprent.getAllExprents(true);
@ -688,7 +633,7 @@ public class StackVarsProcessor {
int varindex = ((VarExprent)expr).getIndex(); int varindex = ((VarExprent)expr).getIndex();
if (leftvar.var != varindex) { if (leftvar.var != varindex) {
if (mapLiveVars.containsKey(varindex)) { if (mapLiveVars.containsKey(varindex)) {
HashSet<VarVersionPair> verset = new HashSet<>(); Set<VarVersionPair> verset = new HashSet<>();
for (Integer vers : mapLiveVars.get(varindex)) { for (Integer vers : mapLiveVars.get(varindex)) {
verset.add(new VarVersionPair(varindex, vers.intValue())); verset.add(new VarVersionPair(varindex, vers.intValue()));
} }
@ -706,7 +651,7 @@ public class StackVarsProcessor {
if (ssau.getMapFieldVars().containsKey(expr.id)) { if (ssau.getMapFieldVars().containsKey(expr.id)) {
int varindex = ssau.getMapFieldVars().get(expr.id); int varindex = ssau.getMapFieldVars().get(expr.id);
if (mapLiveVars.containsKey(varindex)) { if (mapLiveVars.containsKey(varindex)) {
HashSet<VarVersionPair> verset = new HashSet<>(); Set<VarVersionPair> verset = new HashSet<>();
for (Integer vers : mapLiveVars.get(varindex)) { for (Integer vers : mapLiveVars.get(varindex)) {
verset.add(new VarVersionPair(varindex, vers.intValue())); verset.add(new VarVersionPair(varindex, vers.intValue()));
} }

@ -0,0 +1,35 @@
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ExprUtil {
public static List<VarVersionPair> getSyntheticParametersMask(String className, String descriptor, int parameters) {
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(className);
return node != null ? getSyntheticParametersMask(node, descriptor, parameters) : null;
}
public static List<VarVersionPair> getSyntheticParametersMask(ClassNode node, String descriptor, int parameters) {
List<VarVersionPair> mask = null;
ClassWrapper wrapper = node.getWrapper();
if (wrapper != null) {
// own class
mask = wrapper.getMethodWrapper(CodeConstants.INIT_NAME, descriptor).synthParameters;
}
else if (parameters > 0 && node.type == ClassNode.CLASS_MEMBER && node.classStruct.hasModifier(CodeConstants.ACC_STATIC)) {
// non-static member class
mask = new ArrayList<>(Collections.nCopies(parameters, null));
mask.set(0, new VarVersionPair(-1, 0));
}
return mask;
}
}

@ -217,9 +217,7 @@ public class FunctionExprent extends Exprent {
public VarType getExprType() { public VarType getExprType() {
VarType exprType = null; VarType exprType = null;
if (funcType <= FUNCTION_NEG || funcType == FUNCTION_IPP || funcType == FUNCTION_PPI if (funcType <= FUNCTION_NEG || funcType == FUNCTION_IPP || funcType == FUNCTION_PPI || funcType == FUNCTION_IMM || funcType == FUNCTION_MMI) {
|| funcType == FUNCTION_IMM || funcType == FUNCTION_MMI) {
VarType type1 = lstOperands.get(0).getExprType(); VarType type1 = lstOperands.get(0).getExprType();
VarType type2 = null; VarType type2 = null;
if (lstOperands.size() > 1) { if (lstOperands.size() > 1) {
@ -268,7 +266,6 @@ public class FunctionExprent extends Exprent {
Exprent param1 = lstOperands.get(1); Exprent param1 = lstOperands.get(1);
Exprent param2 = lstOperands.get(2); Exprent param2 = lstOperands.get(2);
VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType()); VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType());
if (param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST && if (param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST &&
supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) { supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) {
exprType = VarType.VARTYPE_INT; exprType = VarType.VARTYPE_INT;
@ -324,9 +321,6 @@ public class FunctionExprent extends Exprent {
switch (funcType) { switch (funcType) {
case FUNCTION_IIF: case FUNCTION_IIF:
VarType supertype = getExprType(); VarType supertype = getExprType();
if (supertype == null) {
supertype = getExprType();
}
result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN); result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN);
result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.typeFamily)); result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.typeFamily));
result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.typeFamily)); result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.typeFamily));

@ -300,10 +300,11 @@ public class InvocationExprent extends Exprent {
buf.append("<invokedynamic>"); buf.append("<invokedynamic>");
} }
buf.append("("); buf.append("(");
break; break;
case TYP_CLINIT: case TYP_CLINIT:
throw new RuntimeException("Explicit invocation of " + CodeConstants.CLINIT_NAME); throw new RuntimeException("Explicit invocation of " + CodeConstants.CLINIT_NAME);
case TYP_INIT: case TYP_INIT:
if (super_qualifier != null) { if (super_qualifier != null) {
buf.append("super("); buf.append("super(");
@ -311,31 +312,20 @@ public class InvocationExprent extends Exprent {
else if (isInstanceThis) { else if (isInstanceThis) {
buf.append("this("); buf.append("this(");
} }
else if (instance != null) {
buf.append(instance.toJava(indent, tracer)).append(".<init>(");
}
else { else {
if (instance != null) { throw new RuntimeException("Unrecognized invocation of " + CodeConstants.INIT_NAME);
buf.append(instance.toJava(indent, tracer)).append(".<init>(");
}
else {
throw new RuntimeException("Unrecognized invocation of " + CodeConstants.INIT_NAME);
}
} }
} }
List<VarVersionPair> sigFields = null; List<VarVersionPair> mask = null;
boolean isEnum = false; boolean isEnum = false;
if (functype == TYP_INIT) { if (functype == TYP_INIT) {
ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
if (newNode != null) {
if (newNode != null) { // own class mask = ExprUtil.getSyntheticParametersMask(newNode, stringDescriptor, lstParameters.size());
if (newNode.getWrapper() != null) {
sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, stringDescriptor).signatureFields;
}
else {
if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class
sigFields = new ArrayList<>(Collections.nCopies(lstParameters.size(), (VarVersionPair)null));
sigFields.set(0, new VarVersionPair(-1, 0));
}
}
isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
} }
} }
@ -353,7 +343,7 @@ public class InvocationExprent extends Exprent {
boolean firstParameter = true; boolean firstParameter = true;
int start = isEnum ? 2 : 0; int start = isEnum ? 2 : 0;
for (int i = start; i < lstParameters.size(); i++) { for (int i = start; i < lstParameters.size(); i++) {
if (sigFields == null || sigFields.get(i) == null) { if (mask == null || mask.get(i) == null) {
TextBuffer buff = new TextBuffer(); TextBuffer buff = new TextBuffer();
boolean ambiguous = setAmbiguousParameters.get(i); boolean ambiguous = setAmbiguousParameters.get(i);
@ -373,7 +363,7 @@ public class InvocationExprent extends Exprent {
} }
} }
buf.append(")"); buf.append(')');
return buf; return buf;
} }

@ -20,7 +20,6 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack; import org.jetbrains.java.decompiler.util.ListStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -90,10 +89,8 @@ public class NewExprent extends Exprent {
} }
} }
} }
else { else if (constructor != null) {
if (constructor != null) { return constructor.checkExprTypeBounds();
return constructor.checkExprTypeBounds();
}
} }
return result; return result;
@ -102,21 +99,18 @@ public class NewExprent extends Exprent {
@Override @Override
public List<Exprent> getAllExprents() { public List<Exprent> getAllExprents() {
List<Exprent> lst = new ArrayList<>(); List<Exprent> lst = new ArrayList<>();
if (newType.arrayDim == 0) {
if (constructor != null) {
Exprent constructor_instance = constructor.getInstance();
if (constructor_instance != null) { // should be true only for a lambda expression with a virtual content method
lst.add(constructor_instance);
}
lst.addAll(constructor.getLstParameters()); if (newType.arrayDim != 0) {
}
}
else {
lst.addAll(lstDims); lst.addAll(lstDims);
lst.addAll(lstArrayElements); lst.addAll(lstArrayElements);
} }
else if (constructor != null) {
Exprent constructor = this.constructor.getInstance();
if (constructor != null) { // should be true only for a lambda expression with a virtual content method
lst.add(constructor);
}
lst.addAll(this.constructor.getLstParameters());
}
return lst; return lst;
} }
@ -193,35 +187,22 @@ public class NewExprent extends Exprent {
buf.append('('); buf.append('(');
if (!lambda && constructor != null) { if (!lambda && constructor != null) {
InvocationExprent invSuper = child.superInvocation; List<Exprent> parameters = constructor.getLstParameters();
List<VarVersionPair> mask = child.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).synthParameters;
ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invSuper.getClassname()); if (mask == null) {
InvocationExprent superCall = child.superInvocation;
List<VarVersionPair> sigFields = child.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).signatureFields; mask = ExprUtil.getSyntheticParametersMask(superCall.getClassname(), superCall.getStringDescriptor(), parameters.size());
if (sigFields == null && newNode != null) { // own class
if (newNode.getWrapper() != null) {
sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, invSuper.getStringDescriptor()).signatureFields;
}
else {
if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0 &&
!constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
sigFields = new ArrayList<>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPair)null));
sigFields.set(0, new VarVersionPair(-1, 0));
}
}
} }
List<Exprent> lstParameters = constructor.getLstParameters();
int start = enumConst ? 2 : 0; int start = enumConst ? 2 : 0;
boolean firstParam = true; boolean firstParam = true;
for (int i = start; i < lstParameters.size(); i++) { for (int i = start; i < parameters.size(); i++) {
if (sigFields == null || sigFields.get(i) == null) { if (mask == null || mask.get(i) == null) {
if (!firstParam) { if (!firstParam) {
buf.append(", "); buf.append(", ");
} }
ExprProcessor.getCastedExprent(lstParameters.get(i), constructor.getDescriptor().params[i], buf, indent, true, tracer); ExprProcessor.getCastedExprent(parameters.get(i), constructor.getDescriptor().params[i], buf, indent, true, tracer);
firstParam = false; firstParam = false;
} }
@ -289,33 +270,20 @@ public class NewExprent extends Exprent {
} }
if (constructor != null) { if (constructor != null) {
List<Exprent> lstParameters = constructor.getLstParameters(); List<Exprent> parameters = constructor.getLstParameters();
List<VarVersionPair> mask = ExprUtil.getSyntheticParametersMask(constructor.getClassname(), constructor.getStringDescriptor(), parameters.size());
ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(constructor.getClassname());
List<VarVersionPair> sigFields = null;
if (newNode != null) { // own class
if (newNode.getWrapper() != null) {
sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).signatureFields;
}
else if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0 && !constructor.getLstParameters().isEmpty()) {
// member non-static class invoked with enclosing class instance
sigFields = new ArrayList<>(Collections.nCopies(lstParameters.size(), (VarVersionPair)null));
sigFields.set(0, new VarVersionPair(-1, 0));
}
}
int start = enumConst ? 2 : 0; int start = enumConst ? 2 : 0;
if (!enumConst || start < lstParameters.size()) { if (!enumConst || start < parameters.size()) {
buf.append('('); buf.append('(');
boolean firstParam = true; boolean firstParam = true;
for (int i = start; i < lstParameters.size(); i++) { for (int i = start; i < parameters.size(); i++) {
if (sigFields == null || sigFields.get(i) == null) { if (mask == null || mask.get(i) == null) {
Exprent expr = InvocationExprent.unboxIfNeeded(lstParameters.get(i)); Exprent expr = InvocationExprent.unboxIfNeeded(parameters.get(i));
VarType leftType = constructor.getDescriptor().params[i]; VarType leftType = constructor.getDescriptor().params[i];
if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) { if (i == parameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) {
ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value); ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value);
if (node != null && node.namelessConstructorStub) { if (node != null && node.namelessConstructorStub) {
break; // skip last parameter of synthetic constructor call break; // skip last parameter of synthetic constructor call

@ -158,7 +158,7 @@ public class VarDefinitionHelper {
boolean defset = false; boolean defset = false;
// search for the first assignement to var [index] // search for the first assignment to var [index]
int addindex = 0; int addindex = 0;
for (Exprent expr : lst) { for (Exprent expr : lst) {
if (setDefinition(expr, index)) { if (setDefinition(expr, index)) {

@ -23,24 +23,21 @@ public class VarVersionsGraph {
nodes.addAllWithKey(colnodes, colpaars); nodes.addAllWithKey(colnodes, colpaars);
} }
public boolean isDominatorSet(VarVersionNode node, HashSet<VarVersionNode> domnodes) { public boolean isDominatorSet(VarVersionNode node, Set<VarVersionNode> domnodes) {
if (domnodes.size() == 1) { if (domnodes.size() == 1) {
return engine.isDominator(node, domnodes.iterator().next()); return engine.isDominator(node, domnodes.iterator().next());
} }
else { else {
Set<VarVersionNode> marked = new HashSet<>();
HashSet<VarVersionNode> marked = new HashSet<>();
if (domnodes.contains(node)) { if (domnodes.contains(node)) {
return true; return true;
} }
LinkedList<VarVersionNode> lstNodes = new LinkedList<>(); List<VarVersionNode> lstNodes = new LinkedList<>();
lstNodes.add(node); lstNodes.add(node);
while (!lstNodes.isEmpty()) { while (!lstNodes.isEmpty()) {
VarVersionNode nd = lstNodes.remove(0); VarVersionNode nd = lstNodes.remove(0);
if (marked.contains(nd)) { if (marked.contains(nd)) {
continue; continue;
@ -66,8 +63,7 @@ public class VarVersionsGraph {
} }
public void initDominators() { public void initDominators() {
Set<VarVersionNode> roots = new HashSet<>();
final HashSet<VarVersionNode> roots = new HashSet<>();
for (VarVersionNode node : nodes) { for (VarVersionNode node : nodes) {
if (node.preds.isEmpty()) { if (node.preds.isEmpty()) {
@ -88,23 +84,20 @@ public class VarVersionsGraph {
engine.initialize(); engine.initialize();
} }
private static LinkedList<VarVersionNode> getReversedPostOrder(Collection<VarVersionNode> roots) { private static List<VarVersionNode> getReversedPostOrder(Collection<VarVersionNode> roots) {
List<VarVersionNode> lst = new LinkedList<>();
LinkedList<VarVersionNode> lst = new LinkedList<>(); Set<VarVersionNode> setVisited = new HashSet<>();
HashSet<VarVersionNode> setVisited = new HashSet<>();
for (VarVersionNode root : roots) { for (VarVersionNode root : roots) {
List<VarVersionNode> lstTemp = new LinkedList<>();
LinkedList<VarVersionNode> lstTemp = new LinkedList<>();
addToReversePostOrderListIterative(root, lstTemp, setVisited); addToReversePostOrderListIterative(root, lstTemp, setVisited);
lst.addAll(lstTemp); lst.addAll(lstTemp);
} }
return lst; return lst;
} }
private static void addToReversePostOrderListIterative(VarVersionNode root, List<VarVersionNode> lst, HashSet<VarVersionNode> setVisited) { private static void addToReversePostOrderListIterative(VarVersionNode root, List<VarVersionNode> lst, Set<VarVersionNode> setVisited) {
Map<VarVersionNode, List<VarVersionEdge>> mapNodeSuccs = new HashMap<>(); Map<VarVersionNode, List<VarVersionEdge>> mapNodeSuccs = new HashMap<>();
LinkedList<VarVersionNode> stackNode = new LinkedList<>(); LinkedList<VarVersionNode> stackNode = new LinkedList<>();
LinkedList<Integer> stackIndex = new LinkedList<>(); LinkedList<Integer> stackIndex = new LinkedList<>();
@ -113,7 +106,6 @@ public class VarVersionsGraph {
stackIndex.add(0); stackIndex.add(0);
while (!stackNode.isEmpty()) { while (!stackNode.isEmpty()) {
VarVersionNode node = stackNode.getLast(); VarVersionNode node = stackNode.getLast();
int index = stackIndex.removeLast(); int index = stackIndex.removeLast();

@ -8,7 +8,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
public class MethodDescriptor { public class MethodDescriptor {
public final VarType[] params; public final VarType[] params;
public final VarType ret; public final VarType ret;

@ -1,9 +1,7 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct.match; package org.jetbrains.java.decompiler.struct.match;
public interface IMatchable { public interface IMatchable {
enum MatchProperties { enum MatchProperties {
STATEMENT_TYPE, STATEMENT_TYPE,
STATEMENT_RET, STATEMENT_RET,
@ -29,5 +27,4 @@ public interface IMatchable {
IMatchable findObject(MatchNode matchNode, int index); IMatchable findObject(MatchNode matchNode, int index);
boolean match(MatchNode matchNode, MatchEngine engine); boolean match(MatchNode matchNode, MatchEngine engine);
} }

@ -12,13 +12,7 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import java.util.*; import java.util.*;
public class MatchEngine { public class MatchEngine {
private MatchNode rootNode = null;
private final Map<String, Object> variables = new HashMap<>();
private static final Map<String, MatchProperties> stat_properties = new HashMap<>(); private static final Map<String, MatchProperties> stat_properties = new HashMap<>();
private static final Map<String, MatchProperties> expr_properties = new HashMap<>(); private static final Map<String, MatchProperties> expr_properties = new HashMap<>();
private static final Map<String, Integer> stat_type = new HashMap<>(); private static final Map<String, Integer> stat_type = new HashMap<>();
@ -83,19 +77,19 @@ public class MatchEngine {
expr_const_type.put("string", VarType.VARTYPE_STRING); expr_const_type.put("string", VarType.VARTYPE_STRING);
} }
private final MatchNode rootNode;
private final Map<String, Object> variables = new HashMap<>();
public void parse(String description) { public MatchEngine(String description) {
// each line is a separate statement/exprent // each line is a separate statement/exprent
String[] lines = description.split("\n"); String[] lines = description.split("\n");
int depth = 0; int depth = 0;
LinkedList<MatchNode> stack = new LinkedList<>(); LinkedList<MatchNode> stack = new LinkedList<>();
for(String line : lines) { for (String line : lines) {
List<String> properties = new ArrayList<>(Arrays.asList(line.split("\\s+"))); // split on any number of whitespaces List<String> properties = new ArrayList<>(Arrays.asList(line.split("\\s+"))); // split on any number of whitespaces
if(properties.get(0).isEmpty()) { if (properties.get(0).isEmpty()) {
properties.remove(0); properties.remove(0);
} }
@ -103,11 +97,11 @@ public class MatchEngine {
// create new node // create new node
MatchNode matchNode = new MatchNode(node_type); MatchNode matchNode = new MatchNode(node_type);
for(int i = 1; i < properties.size(); ++i) { for (int i = 1; i < properties.size(); ++i) {
String[] values = properties.get(i).split(":"); String[] values = properties.get(i).split(":");
MatchProperties property = (node_type == MatchNode.MATCHNODE_STATEMENT ? stat_properties : expr_properties).get(values[0]); MatchProperties property = (node_type == MatchNode.MATCHNODE_STATEMENT ? stat_properties : expr_properties).get(values[0]);
if(property == null) { // unknown property defined if (property == null) { // unknown property defined
throw new RuntimeException("Unknown matching property"); throw new RuntimeException("Unknown matching property");
} }
else { else {
@ -115,61 +109,61 @@ public class MatchEngine {
int parameter = 0; int parameter = 0;
String strValue = values[1]; String strValue = values[1];
if(values.length == 3) { if (values.length == 3) {
parameter = Integer.parseInt(values[1]); parameter = Integer.parseInt(values[1]);
strValue = values[2]; strValue = values[2];
} }
switch(property) { switch (property) {
case STATEMENT_TYPE: case STATEMENT_TYPE:
value = stat_type.get(strValue); value = stat_type.get(strValue);
break; break;
case STATEMENT_STATSIZE: case STATEMENT_STATSIZE:
case STATEMENT_EXPRSIZE: case STATEMENT_EXPRSIZE:
value = Integer.valueOf(strValue); value = Integer.valueOf(strValue);
break; break;
case STATEMENT_POSITION: case STATEMENT_POSITION:
case EXPRENT_POSITION: case EXPRENT_POSITION:
case EXPRENT_INVOCATION_CLASS: case EXPRENT_INVOCATION_CLASS:
case EXPRENT_INVOCATION_SIGNATURE: case EXPRENT_INVOCATION_SIGNATURE:
case EXPRENT_INVOCATION_PARAMETER: case EXPRENT_INVOCATION_PARAMETER:
case EXPRENT_VAR_INDEX: case EXPRENT_VAR_INDEX:
case EXPRENT_FIELD_NAME: case EXPRENT_FIELD_NAME:
case EXPRENT_CONSTVALUE: case EXPRENT_CONSTVALUE:
case STATEMENT_RET: case STATEMENT_RET:
case EXPRENT_RET: case EXPRENT_RET:
value = strValue; value = strValue;
break; break;
case STATEMENT_IFTYPE: case STATEMENT_IFTYPE:
value = stat_if_type.get(strValue); value = stat_if_type.get(strValue);
break; break;
case EXPRENT_FUNCTYPE: case EXPRENT_FUNCTYPE:
value = expr_func_type.get(strValue); value = expr_func_type.get(strValue);
break; break;
case EXPRENT_EXITTYPE: case EXPRENT_EXITTYPE:
value = expr_exit_type.get(strValue); value = expr_exit_type.get(strValue);
break; break;
case EXPRENT_CONSTTYPE: case EXPRENT_CONSTTYPE:
value = expr_const_type.get(strValue); value = expr_const_type.get(strValue);
break; break;
case EXPRENT_TYPE: case EXPRENT_TYPE:
value = expr_type.get(strValue); value = expr_type.get(strValue);
break; break;
default: default:
throw new RuntimeException("Unhandled matching property"); throw new RuntimeException("Unhandled matching property");
} }
matchNode.addRule(property, new RuleValue(parameter, value)); matchNode.addRule(property, new RuleValue(parameter, value));
} }
} }
if(stack.isEmpty()) { // first line, root node if (stack.isEmpty()) { // first line, root node
stack.push(matchNode); stack.push(matchNode);
} else { }
else {
// return to the correct parent on the stack // return to the correct parent on the stack
int new_depth = line.lastIndexOf(' ', depth) + 1; int new_depth = line.lastIndexOf(' ', depth) + 1;
for(int i = new_depth; i <= depth; ++i) { for (int i = new_depth; i <= depth; ++i) {
stack.pop(); stack.pop();
} }
@ -190,25 +184,24 @@ public class MatchEngine {
} }
private boolean match(MatchNode matchNode, IMatchable object) { private boolean match(MatchNode matchNode, IMatchable object) {
if (!object.match(matchNode, this)) {
if(!object.match(matchNode, this)) {
return false; return false;
} }
int expr_index = 0; int expr_index = 0;
int stat_index = 0; int stat_index = 0;
for (MatchNode childNode : matchNode.getChildren()) {
for(MatchNode childNode : matchNode.getChildren()) {
boolean isStatement = childNode.getType() == MatchNode.MATCHNODE_STATEMENT; boolean isStatement = childNode.getType() == MatchNode.MATCHNODE_STATEMENT;
IMatchable childObject = object.findObject(childNode, isStatement ? stat_index : expr_index); IMatchable childObject = object.findObject(childNode, isStatement ? stat_index : expr_index);
if(childObject == null || !match(childNode, childObject)) { if (childObject == null || !match(childNode, childObject)) {
return false; return false;
} }
if(isStatement) { if (isStatement) {
stat_index++; stat_index++;
} else { }
else {
expr_index++; expr_index++;
} }
} }

@ -1,15 +1,14 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct.match; package org.jetbrains.java.decompiler.struct.match;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
public class MatchNode { public class MatchNode {
public static class RuleValue { public static class RuleValue {
public final int parameter; public final int parameter;
public final Object value; public final Object value;
@ -33,12 +32,9 @@ public class MatchNode {
public static final int MATCHNODE_EXPRENT = 1; public static final int MATCHNODE_EXPRENT = 1;
private final int type; private final int type;
private final Map<MatchProperties, RuleValue> rules = new HashMap<>(); private final Map<MatchProperties, RuleValue> rules = new HashMap<>();
private final List<MatchNode> children = new ArrayList<>(); private final List<MatchNode> children = new ArrayList<>();
public MatchNode(int type) { public MatchNode(int type) {
this.type = type; this.type = type;
} }
@ -67,5 +63,4 @@ public class MatchNode {
RuleValue rule = rules.get(property); RuleValue rule = rules.get(property);
return rule == null ? null : rule.value; return rule == null ? null : rule.value;
} }
} }

@ -14,7 +14,7 @@ import java.util.Objects;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class DecompilerTestFixture { public class DecompilerTestFixture {

Loading…
Cancel
Save