Fixed #1894 Switches vs loops decompilation (now with two passes)

This commit is contained in:
Jindra Petřík
2022-11-30 19:05:36 +01:00
parent ad97886306
commit a41926a662
23 changed files with 365 additions and 48 deletions

View File

@@ -16,8 +16,11 @@
*/
package com.jpexs.decompiler.flash;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.SecondPassData;
import java.util.HashSet;
import java.util.Set;
/**
*
@@ -26,6 +29,8 @@ import com.jpexs.decompiler.graph.SecondPassData;
public abstract class BaseLocalData {
public GraphSourceItem lineStartInstruction;
public Set<GraphPart> allSwitchParts = new HashSet<>();
public SecondPassData secondPassData = null;
}

View File

@@ -142,6 +142,7 @@ public class AVM2LocalData extends BaseLocalData {
}
public AVM2LocalData(AVM2LocalData localData) {
allSwitchParts = localData.allSwitchParts;
isStatic = localData.isStatic;
classIndex = localData.classIndex;
localRegs = localData.localRegs;

View File

@@ -298,6 +298,7 @@ import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.SecondPassException;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.TypeItem;
@@ -1589,7 +1590,7 @@ public class AVM2Code implements Cloneable {
return pos2adr(getIpThroughJumpAndDebugLine(adr2pos(addr, true)));
}
public ConvertOutput toSourceOutput(List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference<GraphSourceItem> lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws ConvertException, InterruptedException {
public ConvertOutput toSourceOutput(Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference<GraphSourceItem> lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws ConvertException, InterruptedException {
calcKilledStats(body);
boolean debugMode = DEBUG_MODE;
if (debugMode) {
@@ -1664,7 +1665,7 @@ public class AVM2Code implements Cloneable {
do {
AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null;
if (insAfter == null) {
ins.definition.translate(callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ip++;
break;
}
@@ -1686,14 +1687,14 @@ public class AVM2Code implements Cloneable {
//stack.add("(" + stack.pop() + ")||");
isAnd = false;
} else {
ins.definition.translate(callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ip++;
break;
//throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString());
}
} while (ins.definition instanceof DupIns);
} else if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) {
ins.definition.translate(callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
//ip = end + 1;
break;
} else if (ins.definition instanceof NewFunctionIns) {
@@ -1729,13 +1730,13 @@ public class AVM2Code implements Cloneable {
}
}
// What to do when hasDup is false?
ins.definition.translate(callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek();
nft.functionName = functionName;
ip++;
} else {
try {
ins.definition.translate(callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
} catch (RuntimeException re) {
/*String last="";
int len=5;
@@ -2150,8 +2151,11 @@ public class AVM2Code implements Cloneable {
}
//try {
list = AVM2Graph.translateViaGraph(callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive);
try{
list = AVM2Graph.translateViaGraph(null, callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive);
} catch(SecondPassException spe) {
list = AVM2Graph.translateViaGraph(spe.getData(), callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive);
}
if (initTraits != null) {
loopi:
for (int i = 0; i < list.size(); i++) {

View File

@@ -101,6 +101,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.GraphTargetVisitorInterface;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.decompiler.graph.StopPartKind;
import com.jpexs.decompiler.graph.ThrowState;
import com.jpexs.decompiler.graph.TranslateStack;
@@ -633,10 +634,11 @@ public class AVM2Graph extends Graph {
return setLocalPosToGetLocalPos;
}
public static List<GraphTargetItem> translateViaGraph(List<MethodBody> callStack, AbcIndexing abcIndex, String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs, boolean thisHasDefaultToPrimitive) throws InterruptedException {
public static List<GraphTargetItem> translateViaGraph(SecondPassData secondPassData, List<MethodBody> callStack, AbcIndexing abcIndex, String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, int staticOperation, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs, boolean thisHasDefaultToPrimitive) throws InterruptedException {
AVM2Graph g = new AVM2Graph(abcIndex, code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs);
AVM2LocalData localData = new AVM2LocalData();
localData.secondPassData = secondPassData;
localData.thisHasDefaultToPrimitive = thisHasDefaultToPrimitive;
localData.isStatic = isStatic;
localData.classIndex = classIndex;
@@ -657,7 +659,7 @@ public class AVM2Graph extends Graph {
Set<GraphPart> allParts = new HashSet<>();
for (GraphPart head : g.heads) {
populateParts(head, allParts);
}
}
return g.translate(localData, staticOperation, path);
}
@@ -2424,4 +2426,8 @@ public class AVM2Graph extends Graph {
Graph.makeAllCommands(commands, stack);
}
@Override
protected SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
return new SecondPassData();
}
}

View File

@@ -119,7 +119,7 @@ public class AVM2GraphSource extends GraphSource {
List<GraphTargetItem> ret = new ArrayList<>();
ScopeStack newstack = ((AVM2LocalData) localData).scopeStack;
Reference<GraphSourceItem> lineStartItem = new Reference<>(localData.lineStartInstruction);
ConvertOutput co = code.toSourceOutput(((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, newstack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssigmentIps, refs);
ConvertOutput co = code.toSourceOutput(localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, newstack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssigmentIps, refs);
localData.lineStartInstruction = lineStartItem.getVal();
ret.addAll(co.output);
return ret;

View File

@@ -44,6 +44,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitWithSlot;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
@@ -171,8 +172,9 @@ public abstract class InstructionDefinition implements Serializable {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) throws InterruptedException {
}
public void translate(List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, Reference<GraphSourceItem> lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2Instruction ins, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code, boolean thisHasDefaultToPrimitive) throws InterruptedException {
public void translate(Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, Reference<GraphSourceItem> lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2Instruction ins, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code, boolean thisHasDefaultToPrimitive) throws InterruptedException {
AVM2LocalData localData = new AVM2LocalData();
localData.allSwitchParts = switchParts;
localData.isStatic = isStatic;
localData.scriptIndex = scriptIndex;
localData.classIndex = classIndex;

View File

@@ -63,6 +63,7 @@ import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphPartChangeException;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -1009,11 +1010,11 @@ public abstract class Action implements GraphSourceItem {
return variables2;
}
public static List<GraphTargetItem> actionsPartToTree(SecondPassData secondPassData, boolean insideDoInitAction, Reference<GraphSourceItem> fi, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path, String charset) throws InterruptedException, GraphPartChangeException {
public static List<GraphTargetItem> actionsPartToTree(Set<GraphPart> switchParts, SecondPassData secondPassData, boolean insideDoInitAction, Reference<GraphSourceItem> fi, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path, String charset) throws InterruptedException, GraphPartChangeException {
if (start < actions.size() && (end > 0) && (start > 0)) {
logger.log(Level.FINE, "Entering {0}-{1}{2}", new Object[]{start, end, actions.size() > 0 ? (" (" + actions.get(start).toString() + " - " + actions.get(end == actions.size() ? end - 1 : end) + ")") : ""});
}
ActionLocalData localData = new ActionLocalData(secondPassData, insideDoInitAction, registerNames, variables, functions);
ActionLocalData localData = new ActionLocalData(switchParts, secondPassData, insideDoInitAction, registerNames, variables, functions);
localData.lineStartAction = fi.getVal();
List<GraphTargetItem> output = new ArrayList<>();
int ip = start;

View File

@@ -112,7 +112,7 @@ public class ActionGraphSource extends GraphSource {
public List<GraphTargetItem> translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
Reference<GraphSourceItem> fi = new Reference<>(localData.lineStartInstruction);
List<GraphTargetItem> r = Action.actionsPartToTree(localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path, charset);
List<GraphTargetItem> r = Action.actionsPartToTree(localData.allSwitchParts, localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path, charset);
localData.lineStartInstruction = fi.getVal();
return r;
}

View File

@@ -17,10 +17,12 @@
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SecondPassData;
import java.util.HashMap;
import java.util.Set;
/**
*
@@ -51,10 +53,11 @@ public class ActionLocalData extends BaseLocalData {
this.secondPassData = secondPassData;
variables = new HashMap<>();
functions = new HashMap<>();
this.insideDoInitAction = insideDoInitAction;
this.insideDoInitAction = insideDoInitAction;
}
public ActionLocalData(SecondPassData secondPassData, boolean insideDoInitAction, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions) {
public ActionLocalData(Set<GraphPart> switchParts, SecondPassData secondPassData, boolean insideDoInitAction, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions) {
this.allSwitchParts = switchParts;
this.regNames = regNames;
this.variables = variables;
this.functions = functions;

View File

@@ -29,5 +29,5 @@ import java.util.List;
public class ActionSecondPassData extends SecondPassData {
List<List<GraphPart>> switchParts = new ArrayList<>();
List<List<GraphPart>> switchOnFalseParts = new ArrayList<>();
List<List<GraphTargetItem>> switchCaseExpressions = new ArrayList<>();
List<List<GraphTargetItem>> switchCaseExpressions = new ArrayList<>();
}

View File

@@ -61,6 +61,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
@@ -116,6 +117,7 @@ public class Graph {
List<GraphPart> visited = new ArrayList<>();
for (GraphPart head : heads) {
time = head.setTime(time, ordered, visited);
head.setNumblocks(1);
}
}
@@ -446,23 +448,57 @@ public class Graph {
if (stopPart != null) {
for (GraphPart p : parts) {
for (GraphPart sp : stopPart) {
if (sp == p || p.leadsTo(localData, this, code, sp, loops, throwStates, false)) {
if (sp == p || p.leadsTo(localData, this, code, sp, new ArrayList<Loop>() /*IGNORE LOOPS*/, throwStates, false)) {
partsLeadingToStopPart.add(p);
}
}
}
}
if (debugPrintLoopList) {
System.err.println("commonset:");
for (PartCommon pc : commonSet) {
System.err.println("- " + pc);
}
System.err.println("parts:");
for(GraphPart p :parts) {
System.err.println("- "+p);
}
if (stopPart != null) {
System.err.println("stopparts:");
for(GraphPart p :stopPart) {
System.err.println("- "+p);
}
}
System.err.println("partsLeadingToStopPart:");
for (GraphPart p : partsLeadingToStopPart) {
System.err.println("- " + p);
}
if (partsLeadingToStopPart.isEmpty()) {
return null; //?
}
}
loopc:
for (PartCommon pc : commonSet) {
for (GraphPart p : partsLeadingToStopPart) {
if (p != pc.part && !p.leadsTo(localData, this, code, pc.part, loops, throwStates, false)) {
if (debugPrintLoopList) {
System.err.println("ignoring " + pc.part + ", " + p + " does not lead to it");
}
continue loopc;
}
}
if (pc.level <= 1) {
return null;
}
if (debugPrintLoopList) {
System.err.println("selected " + pc.part);
}
return pc.part;
}
@@ -489,6 +525,32 @@ public class Graph {
return "" + part.toString() + " (level=" + level;
}
@Override
public int hashCode() {
int hash = 5;
hash = 71 * hash + Objects.hashCode(this.part);
hash = 71 * hash + this.level;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PartCommon other = (PartCommon) obj;
if (this.level != other.level) {
return false;
}
return Objects.equals(this.part, other.part);
}
}
public GraphPart getNextNoJump(GraphPart part, BaseLocalData localData) {
@@ -569,6 +631,11 @@ public class Graph {
getLoops(localData, heads.get(0), loops, throwStates, null);
afterGetLoops(localData, path, allParts);
//TODO: Make getPrecontinues faster
getBackEdges(localData, loops, throwStates);
new GraphPrecontinueDetector().detectPrecontinues(heads, allParts, loops, throwStates);
if (debugPrintLoopList) {
System.err.println("<loops>");
for (Loop el : loops) {
@@ -576,12 +643,6 @@ public class Graph {
}
System.err.println("</loops>");
}
//TODO: Make getPrecontinues faster
getBackEdges(localData, loops, throwStates);
new GraphPrecontinueDetector().detectPrecontinues(heads, allParts, loops, throwStates);
/*System.err.println("<loopspre>");
for (Loop el : loops) {
System.err.println(el);
@@ -593,8 +654,19 @@ public class Graph {
if (localData.secondPassData == null) {
SecondPassData secondPassData = prepareSecondPass(ret);
if (secondPassData != null) {
throw new SecondPassException(secondPassData);
if (secondPassData == null) {
if (!localData.allSwitchParts.isEmpty()) {
secondPassData = new SecondPassData();
secondPassData.allSwitchParts = localData.allSwitchParts;
throw new SecondPassException(secondPassData);
}
} else {
if (secondPassData.getClass() == SecondPassData.class && localData.allSwitchParts.isEmpty()) {
//nothing
} else {
secondPassData.allSwitchParts = localData.allSwitchParts;
throw new SecondPassException(secondPassData);
}
}
}
@@ -1805,8 +1877,28 @@ public class Graph {
Map<GraphPart, Integer> count = new HashMap<>();
GraphPart winner = null;
int winnerCount = 0;
int winnerNumBlock = Integer.MAX_VALUE;
Set<GraphPart> bannedCandidates = new HashSet<>();
if(localData.secondPassData != null) {
bannedCandidates = localData.secondPassData.allSwitchParts;
}
if (debugPrintLoopList) {
System.err.println("bannedCandidates:");
for(GraphPart p:bannedCandidates) {
System.err.println("- "+p);
}
}
for (GraphPart cand : currentLoop.breakCandidates) {
if (bannedCandidates.contains(cand)) {
if (debugPrintLoopList) {
System.err.println("cand "+cand+" is banned");
}
continue;
}
if (!count.containsKey(cand)) {
count.put(cand, 0);
}
@@ -2690,7 +2782,18 @@ public class Graph {
}
}
finalComm.addAll(precoCommands);
boolean isAllNotBlock = true;
for (GraphTargetItem ti: precoCommands) {
if (ti instanceof Block) {
isAllNotBlock = false;
break;
}
}
if (isAllNotBlock) {
finalComm.addAll(precoCommands);
} else {
commands.addAll(precoCommands);
}
}
if (currentLoop.precontinueCommands != null) {
finalComm.addAll(currentLoop.precontinueCommands);
@@ -3098,7 +3201,7 @@ public class Graph {
}
}
}
protected SwitchItem handleSwitch(GraphTargetItem switchedObject,
GraphSourceItem switchStartItem, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, Set<GraphPart> allParts, TranslateStack stack, List<GraphPart> stopPart, List<StopPartKind> stopPartKind, List<Loop> loops, List<ThrowState> throwStates, BaseLocalData localData, int staticOperation, String path,
List<GraphTargetItem> caseValuesMap, GraphPart defaultPart, List<GraphPart> caseBodyParts, Reference<GraphPart> nextRef, Reference<GraphTargetItem> tiRef) throws InterruptedException {
@@ -3236,6 +3339,8 @@ public class Graph {
}
}
localData.allSwitchParts.add(caseBodies.get(i));
List<GraphPart> stopPart2x = new ArrayList<>(stopPart);
List<StopPartKind> stopPartKind2x = new ArrayList<>(stopPartKind);
for (GraphPart b : caseBodies) {

View File

@@ -73,6 +73,8 @@ public class GraphPart implements Serializable {
public int finishedTime;
public int order;
public int numBlocks = Integer.MAX_VALUE;
//public List<GraphPart> throwParts = new ArrayList<>();
@@ -123,6 +125,16 @@ public class GraphPart implements Serializable {
ordered.add(this);
return time;
}
public void setNumblocks(int numBlocks) {
this.numBlocks = numBlocks;
numBlocks++;
for (GraphPart next : nextParts) {
if (next.numBlocks > numBlocks) {
next.setNumblocks(numBlocks);
}
}
}
private boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart prev, GraphPart part, HashSet<GraphPart> visited, List<Loop> loops, List<ThrowState> throwStates, boolean useThrow) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.graph;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -64,7 +65,12 @@ public class Loop implements Serializable {
for (GraphPart p : backEdges) {
edgesAsStr.add(p.toString());
}
return "loop(id:" + id + (loopPreContinue != null ? ",precontinue:" + loopPreContinue : "") + ",continue:" + loopContinue + ", break:" + loopBreak + ", phase:" + phase + ", backedges: " + String.join(",", edgesAsStr) + ")";
Set<String> bcAsStr = new LinkedHashSet<>();
for (int i = 0; i < breakCandidates.size(); i++) {
bcAsStr.add(breakCandidates.get(i) + " - level " + breakCandidatesLevels.get(i) +" - numblocks " + breakCandidates.get(i).numBlocks);
}
return "loop(id:" + id + (loopPreContinue != null ? ",precontinue:" + loopPreContinue : "") + ",continue:" + loopContinue + ", break:" + loopBreak + ", phase:" + phase + ", backedges: " + String.join(",", edgesAsStr) + ", breakCandidates: " + String.join(",", bcAsStr) + ")";
}
@Override

View File

@@ -16,10 +16,13 @@
*/
package com.jpexs.decompiler.graph;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author JPEXS
*/
public abstract class SecondPassData {
public class SecondPassData {
public Set<GraphPart> allSwitchParts = new HashSet<>();
}