mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-01 04:41:43 +00:00
improved loop detection
fixed AS1/2 switch
This commit is contained in:
@@ -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<>();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user