[java decompiler] cleanup (duplicates; dead code; typos; formatting)
This commit is contained in:
@@ -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;
|
int vars_count = md_content.params.length - md_lambda.params.length;
|
||||||
// if(vars_count < 0) { // should not happen, but just in case...
|
boolean is_static_lambda_content = child.lambdaInformation.is_content_method_static;
|
||||||
// vars_count = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
final 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)arrExpr.getIndex()).getIntValue();
|
||||||
|
|
||||||
int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue();
|
if (constValue < newExpr.getLstArrayElements().size()) {
|
||||||
|
Exprent init = newExpr.getLstArrayElements().get(constValue);
|
||||||
if (constvalue < newex.getLstArrayElements().size()) {
|
|
||||||
Exprent init = newex.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();
|
||||||
|
Set<Integer> ifHeadExprBytecode = (ifHeadExpr == null ? null : ifHeadExpr.bytecode);
|
||||||
|
|
||||||
Exprent ifheadexpr = stif.getHeadexprent();
|
if (statement.iftype == IfStatement.IFTYPE_IFELSE) {
|
||||||
Set<Integer> ifheadexpr_bytecode = (ifheadexpr == null ? null : ifheadexpr.bytecode);
|
Statement ifStatement = statement.getIfstat();
|
||||||
|
Statement elseStatement = statement.getElsestat();
|
||||||
|
|
||||||
if (stif.iftype == IfStatement.IFTYPE_IFELSE) {
|
if (ifStatement.getExprents() != null && ifStatement.getExprents().size() == 1 &&
|
||||||
Statement ifstat = stif.getIfstat();
|
elseStatement.getExprents() != null && elseStatement.getExprents().size() == 1 &&
|
||||||
Statement elsestat = stif.getElsestat();
|
ifStatement.getAllSuccessorEdges().size() == 1 && elseStatement.getAllSuccessorEdges().size() == 1 &&
|
||||||
|
ifStatement.getAllSuccessorEdges().get(0).getDestination() == elseStatement.getAllSuccessorEdges().get(0).getDestination()) {
|
||||||
|
Exprent ifExpr = ifStatement.getExprents().get(0);
|
||||||
|
Exprent elseExpr = elseStatement.getExprents().get(0);
|
||||||
|
|
||||||
if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1
|
if (ifExpr.type == Exprent.EXPRENT_ASSIGNMENT && elseExpr.type == Exprent.EXPRENT_ASSIGNMENT) {
|
||||||
&& elsestat.getExprents() != null && elsestat.getExprents().size() == 1
|
AssignmentExprent ifAssign = (AssignmentExprent)ifExpr;
|
||||||
&& ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1
|
AssignmentExprent elseAssign = (AssignmentExprent)elseExpr;
|
||||||
&& ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) {
|
|
||||||
|
|
||||||
Exprent ifexpr = ifstat.getExprents().get(0);
|
if (ifAssign.getLeft().type == Exprent.EXPRENT_VAR && elseAssign.getLeft().type == Exprent.EXPRENT_VAR) {
|
||||||
Exprent elseexpr = elsestat.getExprents().get(0);
|
VarExprent ifVar = (VarExprent)ifAssign.getLeft();
|
||||||
|
VarExprent elseVar = (VarExprent)elseAssign.getLeft();
|
||||||
|
|
||||||
if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) {
|
if (ifVar.getIndex() == elseVar.getIndex() && ifVar.isStack()) { // ifVar.getIndex() >= VarExprent.STACK_BASE) {
|
||||||
AssignmentExprent ifas = (AssignmentExprent)ifexpr;
|
|
||||||
AssignmentExprent elseas = (AssignmentExprent)elseexpr;
|
|
||||||
|
|
||||||
if (ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) {
|
|
||||||
VarExprent ifvar = (VarExprent)ifas.getLeft();
|
|
||||||
VarExprent elsevar = (VarExprent)elseas.getLeft();
|
|
||||||
|
|
||||||
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));
|
|
||||||
stif.setExprents(data);
|
|
||||||
|
|
||||||
if (stif.getAllSuccessorEdges().isEmpty()) {
|
if (statement.getAllSuccessorEdges().isEmpty()) {
|
||||||
StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0);
|
StatEdge ifEdge = ifStatement.getAllSuccessorEdges().get(0);
|
||||||
StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination());
|
StatEdge edge = new StatEdge(ifEdge.getType(), statement, ifEdge.getDestination());
|
||||||
|
|
||||||
stif.addSuccessor(edge);
|
statement.addSuccessor(edge);
|
||||||
if (ifedge.closure != null) {
|
if (ifEdge.closure != null) {
|
||||||
ifedge.closure.addLabeledEdge(edge);
|
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 {
|
else if (instance != null) {
|
||||||
if (instance != null) {
|
|
||||||
buf.append(instance.toJava(indent, tracer)).append(".<init>(");
|
buf.append(instance.toJava(indent, tracer)).append(".<init>(");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new RuntimeException("Unrecognized invocation of " + CodeConstants.INIT_NAME);
|
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,11 +89,9 @@ 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
|
if (newType.arrayDim != 0) {
|
||||||
lst.add(constructor_instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
lst.addAll(constructor.getLstParameters());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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,12 +109,12 @@ 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;
|
||||||
@@ -163,13 +157,13 @@ public class MatchEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user