summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java')
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java853
1 files changed, 853 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
new file mode 100644
index 000000000000..90ebe2f8218d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
@@ -0,0 +1,853 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+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.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class SimplifyExprentsHelper {
+
+ private boolean firstInvocation;
+
+ public SimplifyExprentsHelper(boolean firstInvocation) {
+ this.firstInvocation = firstInvocation;
+ }
+
+ public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) {
+
+ boolean res = false;
+
+ if (stat.getExprents() == null) {
+
+ while (true) {
+
+ boolean changed = false;
+
+ for (Statement st : stat.getStats()) {
+ res |= simplifyStackVarsStatement(st, setReorderedIfs, ssa, cl);
+
+ // collapse composed if's
+ if (changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
+ break;
+ }
+
+ // collapse iff ?: statement
+ if (changed = buildIff(st, ssa)) {
+ break;
+ }
+ }
+
+ res |= changed;
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+ else {
+ res |= simplifyStackVarsExprents(stat.getExprents(), cl);
+ }
+
+ return res;
+ }
+
+ private boolean simplifyStackVarsExprents(List<Exprent> list, StructClass cl) {
+
+ boolean res = false;
+
+ int index = 0;
+
+ while (index < list.size()) {
+
+ Exprent current = list.get(index);
+
+ Exprent ret = isSimpleConstructorInvocation(current);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // lambda expression (Java 8)
+ ret = isLambda(current, cl);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // remove monitor exit
+ if (isMonitorExit(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // trivial assignment of a stack variable
+ if (isTrivialStackAssignment(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ if (index == list.size() - 1) {
+ break;
+ }
+
+
+ Exprent next = list.get(index + 1);
+
+
+ // constructor invocation
+ if (isConstructorInvocationRemote(list, index)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // remove getClass() invocation, which is part of a qualified new
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_GET_CLASS_NEW)) {
+ if (isQualifiedNewGetClass(current, next)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+ }
+
+ // direct initialization of an array
+ int arrcount = isArrayInitializer(list, index);
+ if (arrcount > 0) {
+ for (int i = 0; i < arrcount; i++) {
+ list.remove(index + 1);
+ }
+ res = true;
+
+ continue;
+ }
+
+ // add array initializer expression
+ if (addArrayInitializer(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // integer ++expr and --expr (except for vars!)
+ Exprent func = isPPIorMMI(current);
+ if (func != null) {
+ list.set(index, func);
+ res = true;
+
+ continue;
+ }
+
+ // expr++ and expr--
+ if (isIPPorIMM(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // assignment on stack
+ if (isStackAssignement(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ if (!firstInvocation && isStackAssignement2(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ index++;
+ }
+
+ return res;
+ }
+
+ private static boolean addArrayInitializer(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (!newex.getLstArrayElements().isEmpty()) {
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ if (second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)second;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue();
+
+ if (constvalue < newex.getLstArrayElements().size()) {
+ Exprent init = newex.getLstArrayElements().get(constvalue);
+ if (init.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cinit = (ConstExprent)init;
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ if (cinit.equals(defaultval)) {
+
+ Exprent tempexpr = aas.getRight();
+
+ if (!tempexpr.containsExprent(arrvar)) {
+ newex.getLstArrayElements().set(constvalue, tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ int dims = newex.getNewtype().arraydim;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static int isArrayInitializer(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (newex.getExprType().arraydim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() &&
+ newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) {
+
+ int size = ((Integer)((ConstExprent)newex.getLstDims().get(0)).getValue()).intValue();
+ if (size == 0) {
+ return 0;
+ }
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ HashMap<Integer, Exprent> mapInit = new HashMap<Integer, Exprent>();
+
+ int i = 1;
+ while (index + i < list.size() && i <= size) {
+ boolean found = false;
+
+ Exprent expr = list.get(index + i);
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)expr;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex())
+ .getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless...
+
+ if (constvalue < size && !mapInit.containsKey(constvalue)) {
+
+ if (!aas.getRight().containsExprent(arrvar)) {
+ mapInit.put(constvalue, aas.getRight());
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+
+ i++;
+ }
+
+ double fraction = ((double)mapInit.size()) / size;
+
+ if ((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) ||
+ (size > 7 && fraction >= 0.7)) {
+
+ List<Exprent> lstRet = new ArrayList<Exprent>();
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ for (int j = 0; j < size; j++) {
+ lstRet.add(defaultval.copy());
+ }
+
+ int dims = newex.getNewtype().arraydim;
+ for (Entry<Integer, Exprent> ent : mapInit.entrySet()) {
+ Exprent tempexpr = ent.getValue();
+ lstRet.set(ent.getKey(), tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+ }
+
+ newex.setLstArrayElements(lstRet);
+
+ return mapInit.size();
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ private static boolean isTrivialStackAssignment(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) {
+ VarExprent varleft = (VarExprent)asf.getLeft();
+ VarExprent varright = (VarExprent)asf.getRight();
+
+ if (varleft.getIndex() == varright.getIndex() && varleft.isStack() &&
+ varright.isStack()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && ass.getRight().type == Exprent.EXPRENT_VAR &&
+ asf.getLeft().equals(ass.getRight()) && ((VarExprent)asf.getLeft()).isStack()) {
+ if (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack()) {
+ asf.setRight(new AssignmentExprent(ass.getLeft(), asf.getRight()));
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ while (true) {
+ if (asf.getRight().equals(ass.getRight())) {
+ if ((asf.getLeft().type == Exprent.EXPRENT_VAR && ((VarExprent)asf.getLeft()).isStack()) &&
+ (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack())) {
+
+ if (!ass.getLeft().containsExprent(asf.getLeft())) {
+ asf.setRight(ass);
+ return true;
+ }
+ }
+ }
+ if (asf.getRight().type == Exprent.EXPRENT_ASSIGNMENT) {
+ asf = (AssignmentExprent)asf.getRight();
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isPPIorMMI(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)as.getRight();
+
+ if (func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
+ func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
+ Exprent econd = func.getLstOperands().get(0);
+ Exprent econst = func.getLstOperands().get(1);
+
+ if (econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
+ econd = econst;
+ econst = func.getLstOperands().get(0);
+ }
+
+ if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
+ Exprent left = as.getLeft();
+
+ if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) {
+ FunctionExprent ret = new FunctionExprent(
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI,
+ Arrays.asList(new Exprent[]{econd}));
+ ret.setImplicitType(VarType.VARTYPE_INT);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isIPPorIMM(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_FUNCTION) {
+ AssignmentExprent as = (AssignmentExprent)first;
+ FunctionExprent in = (FunctionExprent)second;
+
+ if ((in.getFunctype() == FunctionExprent.FUNCTION_MMI || in.getFunctype() == FunctionExprent.FUNCTION_PPI) &&
+ in.getLstOperands().get(0).equals(as.getRight())) {
+
+ if (in.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ in.setFunctype(FunctionExprent.FUNCTION_IMM);
+ }
+ else {
+ in.setFunctype(FunctionExprent.FUNCTION_IPP);
+ }
+ as.setRight(in);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isMonitorExit(Exprent first) {
+ if (first.type == Exprent.EXPRENT_MONITOR) {
+ MonitorExprent monexpr = (MonitorExprent)first;
+ if (monexpr.getMontype() == MonitorExprent.MONITOR_EXIT && monexpr.getValue().type == Exprent.EXPRENT_VAR
+ && !((VarExprent)monexpr.getValue()).isStack()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)first;
+
+ if (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") &&
+ invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) {
+
+ List<Exprent> lstExprents = second.getAllExprents();
+ lstExprents.add(second);
+
+ for (Exprent expr : lstExprents) {
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)expr;
+ if (nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() &&
+ nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) {
+
+ String classname = nexpr.getNewtype().value;
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
+ if (node != null && node.type != ClassNode.CLASS_ROOT) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+ //
+ // Exprent current = list.get(index);
+ //
+ // if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ // AssignmentExprent as = (AssignmentExprent)current;
+ //
+ // if(as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+ //
+ // NewExprent newexpr = (NewExprent)as.getRight();
+ // VarType newtype = newexpr.getNewtype();
+ // VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+ //
+ // if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 &&
+ // newexpr.getConstructor() == null) {
+ //
+ // Set<VarVersionPaar> setChangedVars = new HashSet<VarVersionPaar>();
+ //
+ // for(int i = index + 1; i < list.size(); i++) {
+ // Exprent remote = list.get(i);
+ //
+ // if(remote.type == Exprent.EXPRENT_INVOCATION) {
+ // InvocationExprent in = (InvocationExprent)remote;
+ //
+ // if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_VAR
+ // && as.getLeft().equals(in.getInstance())) {
+ //
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // setVars.remove(leftPaar);
+ // setVars.retainAll(setChangedVars);
+ //
+ // if(setVars.isEmpty()) {
+ //
+ // newexpr.setConstructor(in);
+ // in.setInstance(null);
+ //
+ // if(!setChangedVars.isEmpty()) { // some exprents inbetween
+ // list.add(index+1, as.copy());
+ // list.remove(i+1);
+ // } else {
+ // list.set(i, as.copy());
+ // }
+ //
+ // return true;
+ // }
+ // }
+ // }
+ //
+ // boolean isTempAssignment = false;
+ //
+ // if(remote.type == Exprent.EXPRENT_ASSIGNMENT) { // ugly solution
+ // AssignmentExprent asremote = (AssignmentExprent)remote;
+ // if(asremote.getLeft().type == Exprent.EXPRENT_VAR &&
+ // asremote.getRight().type == Exprent.EXPRENT_VAR) {
+ // setChangedVars.add(new VarVersionPaar((VarExprent)asremote.getLeft()));
+ // isTempAssignment = true;
+ // }
+ //
+ // // FIXME: needs to be rewritten
+ // // propagate (var = new X) forward to the <init> invokation and then reduce
+ //
+ //// if(asremote.getLeft().type == Exprent.EXPRENT_VAR) {
+ //// List<Exprent> lstRightExprents = asremote.getRight().getAllExprents(true);
+ //// lstRightExprents.add(asremote.getRight());
+ ////
+ //// Set<VarVersionPaar> setTempChangedVars = new HashSet<VarVersionPaar>();
+ //// boolean isTemp = true;
+ ////
+ //// for(Exprent expr : lstRightExprents) {
+ //// if(expr.type != Exprent.EXPRENT_VAR && expr.type != Exprent.EXPRENT_FIELD) {
+ //// isTemp = false;
+ //// break;
+ //// } else if(expr.type == Exprent.EXPRENT_VAR) {
+ //// setTempChangedVars.add(new VarVersionPaar((VarExprent)expr));
+ //// }
+ //// }
+ ////
+ //// if(isTemp) {
+ //// setChangedVars.addAll(setTempChangedVars);
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ //// } else if(remote.type == Exprent.EXPRENT_FUNCTION) {
+ //// FunctionExprent fexpr = (FunctionExprent)remote;
+ //// if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IPP || fexpr.getFunctype() == FunctionExprent.FUNCTION_IMM
+ //// || fexpr.getFunctype() == FunctionExprent.FUNCTION_PPI || fexpr.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ //// if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
+ //// setChangedVars.add(new VarVersionPaar((VarExprent)fexpr.getLstOperands().get(0)));
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ // }
+ //
+ // if(!isTempAssignment) {
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // if(setVars.contains(leftPaar)) {
+ // return false;
+ // } else {
+ // setChangedVars.addAll(setVars);
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // return false;
+ // }
+
+ // propagate (var = new X) forward to the <init> invokation
+ private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+
+ NewExprent newexpr = (NewExprent)as.getRight();
+ VarType newtype = newexpr.getNewtype();
+ VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+
+ if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 && newexpr.getConstructor() == null) {
+
+ for (int i = index + 1; i < list.size(); i++) {
+ Exprent remote = list.get(i);
+
+ // <init> invocation
+ if (remote.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)remote;
+
+ if (in.getFunctype() == InvocationExprent.TYP_INIT &&
+ in.getInstance().type == Exprent.EXPRENT_VAR &&
+ as.getLeft().equals(in.getInstance())) {
+
+ newexpr.setConstructor(in);
+ in.setInstance(null);
+
+ list.set(i, as.copy());
+
+ return true;
+ }
+ }
+
+ // check for variable in use
+ Set<VarVersionPaar> setVars = remote.getAllVariables();
+ if (setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isLambda(Exprent exprent, StructClass cl) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isLambda(expr, cl);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+
+ if (in.getInvocationTyp() == InvocationExprent.INVOKE_DYNAMIC) {
+
+ String lambda_class_name = cl.qualifiedName + in.getInvokeDynamicClassSuffix();
+ ClassNode lambda_class = DecompilerContext.getClassProcessor().getMapRootClasses().get(lambda_class_name);
+
+ 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);
+ newexp.setConstructor(in);
+ // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation
+ // 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
+
+ return newexp;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private static Exprent isSimpleConstructorInvocation(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isSimpleConstructorInvocation(expr);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+ if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) {
+ NewExprent newexp = (NewExprent)in.getInstance();
+ newexp.setConstructor(in);
+ in.setInstance(null);
+ return newexp;
+ }
+ }
+
+ return null;
+ }
+
+
+ private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) {
+
+ if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) {
+ IfStatement stif = (IfStatement)stat;
+ if (stif.iftype == IfStatement.IFTYPE_IFELSE) {
+ Statement ifstat = stif.getIfstat();
+ Statement elsestat = stif.getElsestat();
+
+ if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1
+ && elsestat.getExprents() != null && elsestat.getExprents().size() == 1
+ && ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1
+ && ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) {
+
+ Exprent ifexpr = ifstat.getExprents().get(0);
+ Exprent elseexpr = elsestat.getExprents().get(0);
+
+ if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ 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;
+
+ for (Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
+ if (ent.getKey().var == ifvar.getIndex()) {
+ if (ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ stif.getHeadexprent().getCondition(),
+ ifas.getRight(),
+ elseas.getRight()}))));
+ stif.setExprents(data);
+
+ if (stif.getAllSuccessorEdges().isEmpty()) {
+ StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0);
+ StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination());
+
+ stif.addSuccessor(edge);
+ if (ifedge.closure != null) {
+ ifedge.closure.addLabeledEdge(edge);
+ }
+ }
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ else if (ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ifex = (ExitExprent)ifexpr;
+ ExitExprent elseex = (ExitExprent)elseexpr;
+
+ if (ifex.getExittype() == elseex.getExittype() && ifex.getValue() != null && elseex.getValue() != null &&
+ ifex.getExittype() == ExitExprent.EXIT_RETURN) {
+
+ // 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
+ if (ifex.getExittype() == ExitExprent.EXIT_THROW &&
+ !ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point!
+ return false;
+ }
+
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new ExitExprent(ifex.getExittype(), new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ stif.getHeadexprent().getCondition(),
+ ifex.getValue(),
+ elseex.getValue()})), ifex.getRettype()));
+ stif.setExprents(data);
+
+ StatEdge retedge = ifstat.getAllSuccessorEdges().get(0);
+ stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(),
+ retedge.closure == stif ? stif.getParent() : retedge.closure));
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}