improved loop detection

fixed AS1/2 switch
This commit is contained in:
Jindra Petk
2013-06-29 17:29:38 +02:00
parent a47ba09cf9
commit 681127a92a
6 changed files with 555 additions and 91 deletions

View File

@@ -112,6 +112,7 @@ public class AVM2Graph extends Graph {
public static List<GraphTargetItem> translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, Stack<GraphTargetItem> scopeStack, HashMap<Integer, String> localRegNames, List<String> fullyQualifiedNames) {
AVM2Graph g = new AVM2Graph(code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames);
g.init();
List<GraphPart> allParts = new ArrayList<>();
for (GraphPart head : g.heads) {
populateParts(head, allParts);
@@ -135,7 +136,49 @@ public class AVM2Graph extends Graph {
}
@Override
protected List<GraphTargetItem> check(GraphSource srcCode, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output) {
protected void checkGraph(List<GraphPart> allBlocks) {
for (ABCException ex : body.exceptions) {
int startIp = code.adr2pos(ex.start);
int endIp = code.adr2pos(ex.end);
int targetIp = code.adr2pos(ex.target);
GraphPart target = null;
for (GraphPart p : allBlocks) {
if (p.start == targetIp) {
target = p;
break;
}
}
for (GraphPart p : allBlocks) {
if (p.start >= startIp && p.end <= endIp) {
p.throwParts.add(target);
target.refs.add(p);
}
}
}
/*for(ABCException ex:body.exceptions){
for(GraphPart p:allBlocks){
boolean next_is_ex_start=false;
for(GraphPart n:p.nextParts){
if(n.start==code.adr2pos(ex.start)){
next_is_ex_start = true;
break;
}
}
if(next_is_ex_start){
for(GraphPart q:allBlocks){ //find target part
if(q.start==code.adr2pos(ex.target)){
p.nextParts.add(q);
break;
}
}
}
}
}*/
}
@Override
protected List<GraphTargetItem> check(GraphSource srcCode, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop) {
List<GraphTargetItem> ret = null;
@@ -164,6 +207,9 @@ public class AVM2Graph extends Graph {
}
}
if (catchedExceptions.size() > 0) {
if (currentLoop != null) {
//currentLoop.phase=0;
}
parsedExceptions.addAll(catchedExceptions);
int endpos = code.adr2pos(code.fixAddrAfterDebugLine(catchedExceptions.get(0).end));
int endposStartBlock = code.adr2pos(catchedExceptions.get(0).end);
@@ -235,7 +281,7 @@ public class AVM2Graph extends Graph {
}
}
}
List<GraphPart> catchParts = new ArrayList<>();
for (int e = 0; e < catchedExceptions.size(); e++) {
int eendpos;
if (e < catchedExceptions.size() - 1) {
@@ -249,6 +295,7 @@ public class AVM2Graph extends Graph {
for (GraphPart p : allParts) {
if (p.start == findpos) {
npart = p;
catchParts.add(p);
break;
}
}
@@ -279,6 +326,7 @@ public class AVM2Graph extends Graph {
}
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(nepart);
stopPart2.addAll(catchParts);
List<GraphTargetItem> tryCommands = printGraph(new ArrayList<GraphPart>(), localData, stack, allParts, parent, part, stopPart2, loops);
output.clear();
@@ -432,9 +480,8 @@ public class AVM2Graph extends Graph {
}
GraphTargetItem ti = checkLoop(next, stopPart, loops);
Loop currentLoop = new Loop(loops.size(), null, next);
currentLoop = new Loop(loops.size(), null, next);
currentLoop.phase = 1;
currentLoop.used = true;
loops.add(currentLoop);
//switchLoc.getNextPartPath(new ArrayList<GraphPart>());
List<Integer> valuesMapping = new ArrayList<>();

View File

@@ -21,7 +21,10 @@ import com.jpexs.decompiler.flash.action.swf4.ActionIf;
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.Null;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
import com.jpexs.decompiler.flash.action.treemodel.DirectValueTreeItem;
import com.jpexs.decompiler.flash.action.treemodel.EnumerateTreeItem;
import com.jpexs.decompiler.flash.action.treemodel.FunctionTreeItem;
@@ -41,8 +44,6 @@ import com.jpexs.decompiler.flash.graph.Loop;
import com.jpexs.decompiler.flash.graph.SwitchItem;
import com.jpexs.decompiler.flash.graph.WhileItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
@@ -68,6 +69,7 @@ public class ActionGraph extends Graph {
ActionGraph g = new ActionGraph(code, registerNames, variables, functions, version);
List<Object> localData = new ArrayList<>();
localData.add(registerNames);
g.init();
return g.translate(localData);
}
@@ -124,7 +126,64 @@ public class ActionGraph extends Graph {
}
@Override
protected List<GraphTargetItem> check(GraphSource code, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output) {
protected List<GraphPart> checkPrecoNextParts(GraphPart part) {
List<GraphSourceItem> items = getPartItems(part);
part = makeMultiPart(part);
if (!items.isEmpty()) {
if (items.get(items.size() - 1) instanceof ActionIf) {
if (items.get(items.size() - 2) instanceof ActionStrictEquals) {
List<Integer> storeRegisters = new ArrayList<>();
for (GraphSourceItem s : items) {
if (s instanceof ActionStoreRegister) {
ActionStoreRegister sr = (ActionStoreRegister) s;
storeRegisters.add(sr.registerNumber);
}
}
if (!storeRegisters.isEmpty()) {
List<GraphPart> caseBodies = new ArrayList<>();
boolean proceed = false;
do {
proceed = false;
caseBodies.add(part.nextParts.get(0)); //jump
part = part.nextParts.get(1); //nojump
items = getPartItems(part);
part = makeMultiPart(part);
if (!items.isEmpty()) {
if (items.get(0) instanceof ActionPush) {
ActionPush pu = (ActionPush) items.get(0);
if (!pu.values.isEmpty()) {
if (pu.values.get(0) instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) pu.values.get(0);
if (storeRegisters.contains(rn.number)) {
storeRegisters.clear();
storeRegisters.add(rn.number);
if (items.get(items.size() - 1) instanceof ActionIf) {
if (items.size() > 1) {
if (items.get(items.size() - 2) instanceof ActionStrictEquals) {
proceed = true;
}
}
}
}
}
}
}
}
} while (proceed);
if (caseBodies.size() > 1) {
caseBodies.add(part); //TODO: properly detect default clause (?)
return caseBodies;
}
}
}
}
}
return null;
}
@Override
protected List<GraphTargetItem> check(GraphSource code, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop) {
if (!output.isEmpty()) {
if (output.get(output.size() - 1) instanceof StoreRegisterTreeItem) {
StoreRegisterTreeItem str = (StoreRegisterTreeItem) output.get(output.size() - 1);
@@ -175,7 +234,7 @@ public class ActionGraph extends Graph {
} else {
part = part.nextParts.get(1);
GraphPart defaultPart = part;
GraphPart defaultPart = part; //21-21
//caseBodyParts.add(defaultPart);
@@ -184,7 +243,7 @@ public class ActionGraph extends Graph {
defaultAndLastPart.add(defaultPart);
defaultAndLastPart.add(caseBodyParts.get(caseBodyParts.size() - 1));
GraphPart defaultPart2 = getCommonPart(defaultAndLastPart, new ArrayList<Loop>());
GraphPart defaultPart2 = getCommonPart(defaultAndLastPart, loops);//34-37
List<GraphTargetItem> defaultCommands = new ArrayList<>();
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
@@ -200,25 +259,26 @@ public class ActionGraph extends Graph {
}
List<GraphPart> breakParts = new ArrayList<>();
for (int g = 0; g < caseBodyParts.size(); g++) {
if (g < caseBodyParts.size() - 1) {
if (caseBodyParts.get(g).leadsTo(code, caseBodyParts.get(g + 1), loops)) {
continue;
}
}
GraphPart nsp = caseBodyParts.get(g).getNextSuperPartPath(loopContinues);
if (nsp != null) {
breakParts.add(nsp);
}
}
Collections.sort(breakParts, new Comparator<GraphPart>() {
@Override
public int compare(GraphPart o1, GraphPart o2) {
return o2.path.length() - o1.path.length();
}
});
/*for (int g = 0; g < caseBodyParts.size(); g++) {
if (g < caseBodyParts.size() - 1) {
if (caseBodyParts.get(g).leadsTo(code, caseBodyParts.get(g + 1), loops)) {
continue;
}
}
GraphPart nsp = caseBodyParts.get(g).getNextSuperPartPath(loopContinues);
if (nsp != null) {
breakParts.add(nsp);
}
}
Collections.sort(breakParts, new Comparator<GraphPart>() {
@Override
public int compare(GraphPart o1, GraphPart o2) {
return o2.path.length() - o1.path.length();
}
});*/
GraphPart breakPart = breakParts.isEmpty() ? null : breakParts.get(0);
//GraphPart breakPart = breakParts.isEmpty() ? null : breakParts.get(0);
GraphPart breakPart = getMostCommonPart(caseBodyParts, loops);
if ((defaultPart2 != breakPart) && (defaultCommands.isEmpty())) {
defaultPart = defaultPart2;
}
@@ -241,7 +301,7 @@ public class ActionGraph extends Graph {
next = breakPart;
GraphTargetItem ti = checkLoop(next, stopPart, loops);
Loop currentLoop = new Loop(loops.size(), null, next);
currentLoop = new Loop(loops.size(), null, next);
loops.add(currentLoop);
//switchLoc.getNextPartPath(new ArrayList<GraphPart>());
List<Integer> valuesMapping = new ArrayList<>();
@@ -291,7 +351,18 @@ public class ActionGraph extends Graph {
}
}
List<GraphPart> stopPart2x = new ArrayList<>(stopPart);
stopPart2.add(nextCase);
//stopPart2.add(nextCase);
for (GraphPart b : caseBodies) {
if (b != caseBodies.get(i)) {
stopPart2x.add(b);
}
}
if (defaultPart != null) {
stopPart2x.add(defaultPart);
}
if (breakPart != null) {
stopPart2x.add(breakPart);
}
cc.addAll(0, printGraph(new ArrayList<GraphPart>(), localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops));
if (cc.size() >= 2) {
if (cc.get(cc.size() - 1) instanceof BreakItem) {

View File

@@ -206,6 +206,9 @@ public class DirectValueTreeItem extends TreeItem {
if (obj == null) {
return false;
}
if (!(obj instanceof DirectValueTreeItem)) {
return false;
}
final DirectValueTreeItem other = (DirectValueTreeItem) obj;
if (!Objects.equals(this.value, other.value)) {
return false;

View File

@@ -36,15 +36,24 @@ public class Graph {
public List<GraphPart> heads;
protected GraphSource code;
private List<Integer> alternateEntries;
public Graph(GraphSource code, List<Integer> alternateEntries) {
this.code = code;
this.alternateEntries = alternateEntries;
}
public void init() {
heads = makeGraph(code, new ArrayList<GraphPart>(), alternateEntries);
int time = 1;
List<GraphPart> ordered = new ArrayList<>();
List<GraphPart> visited = new ArrayList<>();
for (GraphPart head : heads) {
time = head.setTime(time, ordered, visited);
fixGraph(head);
makeMulti(head, new ArrayList<GraphPart>());
}
}
protected static void populateParts(GraphPart part, List<GraphPart> allParts) {
@@ -394,6 +403,117 @@ public class Graph {
return null;
}
public GraphPart getMostCommonPart(List<GraphPart> parts, List<Loop> loops) {
if (parts.isEmpty()) {
return null;
}
Set<GraphPart> s = new HashSet<>(parts); //unique
parts = new ArrayList<>(s); //make local copy
List<GraphPart> loopContinues = new ArrayList<>();//getLoopsContinues(loops);
for (Loop l : loops) {
if (l.phase == 1) {
loopContinues.add(l.loopContinue);
loopContinues.add(l.loopPreContinue);
}
}
for (GraphPart p : parts) {
if (loopContinues.contains(p)) {
break;
}
boolean common = true;
for (GraphPart q : parts) {
if (q == p) {
continue;
}
if (!q.leadsTo(code, p, loops)) {
common = false;
break;
}
}
if (common) {
return p;
}
}
loopi:
for (int i = 0; i < parts.size(); i++) {
for (int j = 0; j < parts.size(); j++) {
if (j == i) {
continue;
}
if (parts.get(i).leadsTo(code, parts.get(j), loops)) {
parts.remove(i);
i--;
continue loopi;
}
}
}
List<List<GraphPart>> reachable = new ArrayList<>();
for (GraphPart p : parts) {
List<GraphPart> r1 = new ArrayList<>();
getReachableParts(p, r1, loops);
r1.add(0, p);
reachable.add(r1);
}
///List<GraphPart> first = reachable.get(0);
int commonLevel = 0;
Map<GraphPart, Integer> levelMap = new HashMap<>();
for (List<GraphPart> first : reachable) {
int maxclevel = 0;
Set<GraphPart> visited = new HashSet<>();
for (GraphPart p : first) {
if (loopContinues.contains(p)) {
break;
}
if (visited.contains(p)) {
continue;
}
visited.add(p);
boolean common = true;
commonLevel = 1;
for (List<GraphPart> r : reachable) {
if (r == first) {
continue;
}
if (r.contains(p)) {
commonLevel++;
}
}
if (commonLevel <= maxclevel) {
continue;
}
maxclevel = commonLevel;
if (levelMap.containsKey(p)) {
if (levelMap.get(p) > commonLevel) {
commonLevel = levelMap.get(p);
}
}
levelMap.put(p, commonLevel);
if (common) {
//return p;
}
}
}
for (int i = reachable.size() - 1; i >= 2; i--) {
for (GraphPart p : levelMap.keySet()) {
if (levelMap.get(p) == i) {
return p;
}
}
}
for (GraphPart p : levelMap.keySet()) {
if (levelMap.get(p) == parts.size()) {
return p;
}
}
return null;
}
public GraphPart getNextNoJump(GraphPart part) {
while (code.get(part.start).isJump()) {
part = part.getSubParts().get(0).nextParts.get(0);
@@ -403,6 +523,7 @@ public class Graph {
public static List<GraphTargetItem> translateViaGraph(List<Object> localData, String path, GraphSource code, List<Integer> alternateEntries) {
Graph g = new Graph(code, alternateEntries);
g.init();
return g.translate(localData);
}
@@ -422,10 +543,10 @@ public class Graph {
System.out.println("</loops>");*/
getPrecontinues(null, heads.get(0), loops, null);
/*System.out.println("<loopspre>");
for (Loop el : loops) {
System.out.println(el);
}
System.out.println("</loopspre>");*/
for (Loop el : loops) {
System.out.println(el);
}
System.out.println("</loopspre>");//*/
List<GraphTargetItem> ret = printGraph(new ArrayList<GraphPart>(), localData, stack, allParts, null, heads.get(0), null, loops);
processIfs(ret);
@@ -608,7 +729,7 @@ public class Graph {
return false;
}
protected List<GraphTargetItem> check(GraphSource code, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output) {
protected List<GraphTargetItem> check(GraphSource code, List<Object> localData, List<GraphPart> allParts, Stack<GraphTargetItem> stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop) {
return null;
}
@@ -693,18 +814,61 @@ public class Graph {
}
private void getPrecontinues(GraphPart parent, GraphPart part, List<Loop> loops, List<GraphPart> stopPart) {
clearLoops(loops);
getPrecontinues(parent, part, loops, stopPart, 0, new ArrayList<GraphPart>());
clearLoops(loops);
//Note: this also marks part as precontinue when there is if
/*
while(k<10){
if(k==7){
trace(a);
}else{
trace(b);
}
//precontinue
k++;
}
*/
looploops:
for (Loop l : loops) {
if (l.loopContinue != null) {
Set<GraphPart> uniqueRefs = new HashSet<>();
uniqueRefs.addAll(l.loopContinue.refs);
if (uniqueRefs.size() == 2) { //only one path - from precontinue
List<GraphPart> uniqueRefsList = new ArrayList<>(uniqueRefs);
if (uniqueRefsList.get(0).discoveredTime > uniqueRefsList.get(1).discoveredTime) { //latch node is discovered later
part = uniqueRefsList.get(0);
} else {
part = uniqueRefsList.get(1);
}
if (part == l.loopContinue) {
continue looploops;
}
while (part.refs.size() == 1) {
if (part.refs.get(0).nextParts.size() != 1) {
continue looploops;
}
part = part.refs.get(0);
if (part == l.loopContinue) {
break;
}
}
if (part != l.loopContinue) {
l.loopPreContinue = part;
}
}
}
}
/*clearLoops(loops);
getPrecontinues(parent, part, loops, stopPart, 0, new ArrayList<GraphPart>());
clearLoops(loops);*/
}
private void getPrecontinues(GraphPart parent, GraphPart part, List<Loop> loops, List<GraphPart> stopPart, int level, List<GraphPart> visited) {
boolean debugMode = false;
boolean debugMode = true;
if (stopPart == null) {
stopPart = new ArrayList<>();
}
if (debugMode) {
System.err.println("preco " + part);
}
@@ -773,35 +937,46 @@ public class Graph {
break;
}
}
if (part.nextParts.size() == 2) {
GraphPart next = getNextCommonPart(part, loops);//part.getNextPartPath(new ArrayList<GraphPart>());
List<GraphPart> stopParts2 = new ArrayList<>(stopPart);
List<GraphPart> nextParts = checkPrecoNextParts(part);
if (nextParts == null) {
nextParts = part.nextParts;
}
if (nextParts.size() == 2) {
GraphPart next = getCommonPart(nextParts, loops);//part.getNextPartPath(new ArrayList<GraphPart>());
List<GraphPart> stopParts2 = new ArrayList<>(); //stopPart);
if (next != null) {
stopParts2.add(next);
} else if (!stopPart.isEmpty()) {
stopParts2.add(stopPart.get(stopPart.size() - 1));
}
if (next != part.nextParts.get(0)) {
getPrecontinues(part, part.nextParts.get(0), loops, next == null ? stopPart : stopParts2, level + 1, visited);
if (next != nextParts.get(0)) {
getPrecontinues(part, nextParts.get(0), loops, next == null ? stopPart : stopParts2, level + 1, visited);
}
if (next != part.nextParts.get(1)) {
getPrecontinues(part, part.nextParts.get(1), loops, next == null ? stopPart : stopParts2, level + 1, visited);
if (next != nextParts.get(1)) {
getPrecontinues(part, nextParts.get(1), loops, next == null ? stopPart : stopParts2, level + 1, visited);
}
if (next != null) {
getPrecontinues(part, next, loops, stopPart, level, visited);
}
}
if (part.nextParts.size() > 2) {
GraphPart next = getNextCommonPart(part, loops);
if (nextParts.size() > 2) {
GraphPart next = getCommonPart(nextParts, loops);
List<GraphPart> vis = new ArrayList<>();
for (GraphPart p : part.nextParts) {
for (GraphPart p : nextParts) {
if (vis.contains(p)) {
continue;
}
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
List<GraphPart> stopPart2 = new ArrayList<>(); //(stopPart);
if (next != null) {
stopPart2.add(next);
} else if (!stopPart.isEmpty()) {
stopPart2.add(stopPart.get(stopPart.size() - 1));
}
for (GraphPart p2 : part.nextParts) {
for (GraphPart p2 : nextParts) {
if (p2 == p) {
continue;
}
@@ -826,9 +1001,16 @@ public class Graph {
}
}
if (part.nextParts.size() == 1) {
getPrecontinues(part, part.nextParts.get(0), loops, stopPart, level, visited);
if (nextParts.size() == 1) {
getPrecontinues(part, nextParts.get(0), loops, stopPart, level, visited);
}
for (GraphPart t : part.throwParts) {
if (!visited.contains(t)) {
getPrecontinues(part, t, loops, stopPart, level, visited);
}
}
if (isLoop) {
if (currentLoop.loopBreak != null) {
currentLoop.phase = 2;
@@ -845,11 +1027,11 @@ public class Graph {
private void getLoops(GraphPart part, List<Loop> loops, List<GraphPart> stopPart) {
clearLoops(loops);
getLoops(part, loops, stopPart, true, 1);
getLoops(part, loops, stopPart, true, 1, new ArrayList<GraphPart>());
clearLoops(loops);
}
private void getLoops(GraphPart part, List<Loop> loops, List<GraphPart> stopPart, boolean first, int level) {
private void getLoops(GraphPart part, List<Loop> loops, List<GraphPart> stopPart, boolean first, int level, List<GraphPart> visited) {
boolean debugMode = false;
if (stopPart == null) {
@@ -858,6 +1040,9 @@ public class Graph {
if (part == null) {
return;
}
if (!visited.contains(part)) {
visited.add(part);
}
if (debugMode) {
System.err.println("getloops: " + part);
@@ -865,7 +1050,7 @@ public class Graph {
List<GraphPart> loopContinues = getLoopsContinues(loops);
Loop lastP1 = null;
for (Loop el : loops) {
if ((el.phase == 1) && el.loopBreak == null) { //break not found yet
if ((el.phase == 1) && el.loopBreak == null) { //break not found yet
if (el.loopContinue != part) {
lastP1 = el;
@@ -884,9 +1069,37 @@ public class Graph {
List<Loop> loops2 = new ArrayList<>(loops);
loops2.remove(lastP1);
if (!part.leadsTo(code, lastP1.loopContinue, loops2)) {
lastP1.breakCandidates.add(part);
lastP1.breakCandidatesLevels.add(level);
return;
/*boolean notlead=true;
for(GraphPart p:part.throwParts){
if(p.leadsTo(code, lastP1.loopContinue, loops2)){
notlead=false;
break;
}
}*/
//if(notlead){
/*boolean isthrow = false;
loopthrow:
for (GraphPart p : part.refs) {
if (p.throwParts.contains(part)) {
isthrow = true;
break;
}
for (GraphPart t : p.throwParts) {
if (t.leadsTo(code, part, loops)) {
isthrow = true;
break loopthrow;
}
}
}
if (!isthrow) {*/
if (lastP1.breakCandidatesLocked == 0) {
lastP1.breakCandidates.add(part);
lastP1.breakCandidatesLevels.add(level);
return;
}
//}
//}
}
}
}
@@ -918,13 +1131,13 @@ public class Graph {
stopPart2.add(next);
}
if (next != part.nextParts.get(0)) {
getLoops(part.nextParts.get(0), loops, stopPart2, false, level + 1);
getLoops(part.nextParts.get(0), loops, stopPart2, false, level + 1, visited);
}
if (next != part.nextParts.get(1)) {
getLoops(part.nextParts.get(1), loops, stopPart2, false, level + 1);
getLoops(part.nextParts.get(1), loops, stopPart2, false, level + 1, visited);
}
if (next != null) {
getLoops(next, loops, stopPart, false, level);
getLoops(next, loops, stopPart, false, level, visited);
}
}
if (part.nextParts.size() > 2) {
@@ -945,17 +1158,29 @@ public class Graph {
}
}
if (next != p) {
getLoops(p, loops, stopPart2, false, level + 1);
getLoops(p, loops, stopPart2, false, level + 1, visited);
}
}
if (next != null) {
getLoops(next, loops, stopPart, false, level);
getLoops(next, loops, stopPart, false, level, visited);
}
}
if (part.nextParts.size() == 1) {
getLoops(part.nextParts.get(0), loops, stopPart, false, level);
getLoops(part.nextParts.get(0), loops, stopPart, false, level, visited);
}
List<Loop> loops2 = new ArrayList<>(loops);
for (Loop l : loops2) {
l.breakCandidatesLocked++;
}
for (GraphPart t : part.throwParts) {
if (!visited.contains(t)) {
getLoops(t, loops, stopPart, false, level, visited);
}
}
for (Loop l : loops2) {
l.breakCandidatesLocked--;
}
if (isLoop) {
@@ -974,7 +1199,7 @@ public class Graph {
backupCandidates.add(currentLoop.breakCandidates.remove(i));
}
}
Set<GraphPart> removed = new HashSet<>();
Map<GraphPart, Integer> removed = new HashMap<>();
/*
Set<GraphPart> newcommon=new HashSet<>();
for (GraphPart cand : currentLoop.breakCandidates) {
@@ -985,7 +1210,7 @@ public class Graph {
List<GraphPart> c=new ArrayList<>();
c.add(cand);
c.add(cand2);
GraphPart common=getCommonPart(c, loops);
if(common!=null){
if(!currentLoop.breakCandidates.contains(common)){
@@ -1018,7 +1243,7 @@ public class Graph {
}
}
}
if (lev1 < lev2) {
if (lev1 <= lev2) {
found = cand2;
} else {
found = cand;
@@ -1029,12 +1254,21 @@ public class Graph {
}
}
if (found != null) {
int maxlevel = 0;
while (currentLoop.breakCandidates.contains(found)) {
int ind = currentLoop.breakCandidates.indexOf(found);
currentLoop.breakCandidates.remove(ind);
currentLoop.breakCandidatesLevels.remove(ind);
int lev = currentLoop.breakCandidatesLevels.remove(ind);
if (lev > maxlevel) {
maxlevel = lev;
}
}
removed.add(found);
if (removed.containsKey(found)) {
if (removed.get(found) > maxlevel) {
maxlevel = removed.get(found);
}
}
removed.put(found, maxlevel);
}
} while ((found != null) && (currentLoop.breakCandidates.size() > 1));
@@ -1079,9 +1313,16 @@ public class Graph {
winner = backupCandidates.get(backupCandidates.size() - 1);
}
}
for (GraphPart cand : currentLoop.breakCandidates) {
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
GraphPart cand = currentLoop.breakCandidates.get(i);
if (cand != winner) {
removed.add(cand);
int lev = currentLoop.breakCandidatesLevels.get(i);
if (removed.containsKey(cand)) {
if (removed.get(cand) > lev) {
lev = removed.get(cand);
}
}
removed.put(cand, lev);
}
}
currentLoop.loopBreak = winner;
@@ -1096,8 +1337,8 @@ public class Graph {
start = true;
}
}
for (GraphPart r : removed) {
getLoops(r, loops, stopPart, false, 1/*FIXME?*/);
for (GraphPart r : removed.keySet()) {
getLoops(r, loops, stopPart, false, removed.get(r), visited);
}
start = false;
for (int l = 0; l < loops.size(); l++) {
@@ -1110,7 +1351,7 @@ public class Graph {
}
}
//currentLoop.phase = 2;
getLoops(currentLoop.loopBreak, loops, stopPart, false, level);
getLoops(currentLoop.loopBreak, loops, stopPart, false, level, visited);
}
}
@@ -1134,7 +1375,7 @@ public class Graph {
System.err.println("PART " + part);
}
/*while (((part != null) && (part.getHeight() == 1)) && (code.size() > part.start) && (code.get(part.start).isJump())) { //Parts with only jump in it gets ignored
/*while (((part != null) && (part.getHeight() == 1)) && (code.size() > part.start) && (code.get(part.start).isJump())) { //Parts with only jump in it gets ignored
if (part == stopPart) {
return ret;
@@ -1163,7 +1404,6 @@ public class Graph {
return ret;
}
/* if ((parent != null) && (part.path.length() < parent.path.length())) {
boolean can = true;
for (Loop el : loops) {
@@ -1280,12 +1520,6 @@ public class Graph {
ret.add(new ScriptEndItem());
return ret;
}
if (currentLoop != null) {
currentLoop.used = true;
}
List<GraphTargetItem> currentRet = ret;
UniversalLoopItem loopItem = null;
if (isLoop) {
@@ -1456,15 +1690,19 @@ public class Graph {
//********************************END PART DECOMPILING
if (parseNext) {
List<GraphTargetItem> retCheck = check(code, localData, allParts, stack, parent, part, stopPart, loops, output);
List<GraphTargetItem> retCheck = check(code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop);
if (retCheck != null) {
if (!retCheck.isEmpty()) {
currentRet.addAll(retCheck);
}
return ret;
parseNext = false;
//return ret;
} else {
currentRet.addAll(output);
}
}
if (parseNext) {
if (part.nextParts.size() == 2) {
//List<GraphPart> ignore = new ArrayList<>();
@@ -1525,17 +1763,51 @@ public class Graph {
}
} else if (part.nextParts.size() == 1) {
printGraph(visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet);
boolean nextloop = false;
for (Loop l : loops) {
if (part.nextParts.get(0) == l.loopContinue) {
nextloop = true;
break;
}
if (part.nextParts.get(0) == l.loopPreContinue) {
nextloop = true;
break;
}
}
if (true)//if (nextloop || (part.nextParts.get(0).refs.size() == 1)) //not join node
{
printGraph(visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet);
}
}
}
if (isLoop) {
currentLoop.phase = 2;
LoopItem li = loopItem;
boolean loopTypeFound = false;
boolean hasContinue = false;
processIfs(loopItem.commands);
checkContinueAtTheEnd(loopItem.commands, currentLoop);
List<ContinueItem> continues = loopItem.getContinues();
for (ContinueItem c : continues) {
if (c.loopId == currentLoop.id) {
hasContinue = true;
break;
}
}
if (!hasContinue) {
if (currentLoop.loopPreContinue != null) {
List<GraphPart> stopContPart = new ArrayList<>();
stopContPart.add(currentLoop.loopContinue);
GraphPart precoBackup = currentLoop.loopPreContinue;
currentLoop.loopPreContinue = null;
loopItem.commands.addAll(printGraph(visited, localData, new Stack<GraphTargetItem>(), allParts, null, precoBackup, stopContPart, loops));
}
}
//Loop with condition at the beginning (While)
if (!loopTypeFound && (!loopItem.commands.isEmpty())) {
@@ -1545,6 +1817,7 @@ public class Graph {
List<GraphTargetItem> bodyBranch = null;
boolean inverted = false;
boolean breakpos2 = false;
if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) {
BreakItem bi = (BreakItem) ifi.onTrue.get(0);
if (bi.loopId == currentLoop.id) {
@@ -1556,6 +1829,12 @@ public class Graph {
if (bi.loopId == currentLoop.id) {
bodyBranch = ifi.onTrue;
}
} else if (loopItem.commands.size() == 2 && (loopItem.commands.get(1) instanceof BreakItem)) {
BreakItem bi = (BreakItem) loopItem.commands.get(1);
if (bi.loopId == currentLoop.id) {
bodyBranch = ifi.onTrue;
breakpos2 = true;
}
}
if (bodyBranch != null) {
int index = ret.indexOf(loopItem);
@@ -1573,6 +1852,9 @@ public class Graph {
List<GraphTargetItem> commands = new ArrayList<>();
commands.addAll(bodyBranch);
loopItem.commands.remove(0);
if (breakpos2) {
loopItem.commands.remove(0); //remove that break too
}
commands.addAll(loopItem.commands);
checkContinueAtTheEnd(commands, currentLoop);
List<GraphTargetItem> finalComm = new ArrayList<>();
@@ -1706,6 +1988,7 @@ public class Graph {
if (!loopTypeFound) {
checkContinueAtTheEnd(loopItem.commands, currentLoop);
}
currentLoop.phase = 2;
GraphTargetItem replaced = checkLoop(li, localData, loops);
if (replaced != li) {
@@ -1726,6 +2009,9 @@ public class Graph {
}
protected void checkGraph(List<GraphPart> allBlocks) {
}
private List<GraphPart> makeGraph(GraphSource code, List<GraphPart> allBlocks, List<Integer> alternateEntries) {
HashMap<Integer, List<Integer>> refs = code.visitCode(alternateEntries);
List<GraphPart> ret = new ArrayList<>();
@@ -1736,6 +2022,7 @@ public class Graph {
e1.path = new GraphPath("e");
ret.add(makeGraph(e1, new GraphPath("e"), code, pos, pos, allBlocks, refs, visited));
}
checkGraph(allBlocks);
return ret;
}
@@ -1972,4 +2259,48 @@ public class Graph {
public List<Object> prepareBranchLocalData(List<Object> localData) {
return localData;
}
protected List<GraphPart> checkPrecoNextParts(GraphPart part) {
return null;
}
protected GraphPart makeMultiPart(GraphPart part) {
List<GraphPart> parts = new ArrayList<>();
do {
parts.add(part);
if (part.nextParts.size() == 1 && part.nextParts.get(0).refs.size() == 1) {
part = part.nextParts.get(0);
} else {
part = null;
}
} while (part != null);
if (parts.size() > 1) {
return new GraphPartMulti(parts);
} else {
return parts.get(0);
}
}
protected List<GraphSourceItem> getPartItems(GraphPart part) {
List<GraphSourceItem> ret = new ArrayList<>();
do {
for (int i = 0; i < part.getHeight(); i++) {
if (part.getPosAt(i) < code.size()) {
if (part.getPosAt(i) < 0) {
continue;
}
GraphSourceItem s = code.get(part.getPosAt(i));
if (!s.isJump()) {
ret.add(s);
}
}
}
if (part.nextParts.size() == 1 && part.nextParts.get(0).refs.size() == 1) {
part = part.nextParts.get(0);
} else {
part = null;
}
} while (part != null);
return ret;
}
}

View File

@@ -39,8 +39,12 @@ public class GraphPart {
public int discoveredTime;
public int finishedTime;
public int order;
public List<GraphPart> throwParts = new ArrayList<>();
public int setTime(int time, List<GraphPart> ordered, List<GraphPart> visited) {
if (visited.contains(this)) {
return time;
}
discoveredTime = time;
visited.add(this);
for (GraphPart next : nextParts) {
@@ -97,6 +101,15 @@ public class GraphPart {
}
}
}
for (GraphPart p : throwParts) {
if (p == part) {
return true;
} else {
if (p.leadsTo(code, part, visited, loops)) {
return true;
}
}
}
return false;
}

View File

@@ -31,11 +31,10 @@ public class Loop {
public List<GraphPart> breakCandidates = new ArrayList<>();
public List<Integer> breakCandidatesLevels = new ArrayList<>();
public long id;
public boolean used = false;
public boolean finished = false;
public int leadsToMark;
public int reachableMark;
public int phase;
public int breakCandidatesLocked = 0;
public Loop(long id, GraphPart loopContinue, GraphPart loopBreak) {
this.loopContinue = loopContinue;