mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-23 22:47:36 +00:00
3324 lines
134 KiB
Java
3324 lines
134 KiB
Java
/*
|
||
* Copyright (C) 2010-2018 JPEXS, All rights reserved.
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 3.0 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library.
|
||
*/
|
||
package com.jpexs.decompiler.graph;
|
||
|
||
import com.jpexs.decompiler.flash.BaseLocalData;
|
||
import com.jpexs.decompiler.flash.FinalProcessLocalData;
|
||
import com.jpexs.decompiler.flash.action.Action;
|
||
import com.jpexs.decompiler.flash.action.model.FunctionActionItem;
|
||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||
import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
|
||
import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2;
|
||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||
import com.jpexs.decompiler.graph.model.AndItem;
|
||
import com.jpexs.decompiler.graph.model.BranchStackResistant;
|
||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||
import com.jpexs.decompiler.graph.model.DefaultItem;
|
||
import com.jpexs.decompiler.graph.model.DoWhileItem;
|
||
import com.jpexs.decompiler.graph.model.DuplicateItem;
|
||
import com.jpexs.decompiler.graph.model.ExitItem;
|
||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||
import com.jpexs.decompiler.graph.model.ForItem;
|
||
import com.jpexs.decompiler.graph.model.GotoItem;
|
||
import com.jpexs.decompiler.graph.model.IfItem;
|
||
import com.jpexs.decompiler.graph.model.IntegerValueItem;
|
||
import com.jpexs.decompiler.graph.model.IntegerValueTypeItem;
|
||
import com.jpexs.decompiler.graph.model.LabelItem;
|
||
import com.jpexs.decompiler.graph.model.LocalData;
|
||
import com.jpexs.decompiler.graph.model.LogicalOpItem;
|
||
import com.jpexs.decompiler.graph.model.LoopItem;
|
||
import com.jpexs.decompiler.graph.model.NotItem;
|
||
import com.jpexs.decompiler.graph.model.OrItem;
|
||
import com.jpexs.decompiler.graph.model.PopItem;
|
||
import com.jpexs.decompiler.graph.model.PushItem;
|
||
import com.jpexs.decompiler.graph.model.ScriptEndItem;
|
||
import com.jpexs.decompiler.graph.model.SwitchItem;
|
||
import com.jpexs.decompiler.graph.model.TernarOpItem;
|
||
import com.jpexs.decompiler.graph.model.TrueItem;
|
||
import com.jpexs.decompiler.graph.model.UniversalLoopItem;
|
||
import com.jpexs.decompiler.graph.model.WhileItem;
|
||
import com.jpexs.helpers.Reference;
|
||
import java.util.ArrayList;
|
||
import java.util.Collection;
|
||
import java.util.HashMap;
|
||
import java.util.HashSet;
|
||
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.logging.Logger;
|
||
|
||
/**
|
||
*
|
||
* @author JPEXS
|
||
*/
|
||
public class Graph {
|
||
|
||
public List<GraphPart> heads;
|
||
|
||
protected GraphSource code;
|
||
|
||
private final List<GraphException> exceptions;
|
||
|
||
public static final int SOP_USE_STATIC = 0;
|
||
|
||
public static final int SOP_SKIP_STATIC = 1;
|
||
|
||
public static final int SOP_REMOVE_STATIC = 2;
|
||
|
||
private boolean debugPrintAllParts = false;
|
||
private boolean debugPrintLoopList = false;
|
||
private boolean debugGetLoops = false;
|
||
private boolean debugPrintGraph = false;
|
||
|
||
private static Logger logger = Logger.getLogger(Graph.class.getName());
|
||
|
||
public GraphSource getGraphCode() {
|
||
return code;
|
||
}
|
||
|
||
public LinkedHashMap<String, Graph> getSubGraphs() {
|
||
return new LinkedHashMap<>();
|
||
}
|
||
|
||
/**
|
||
* Identify loop exits
|
||
*
|
||
* @param localData
|
||
* @param allParts All nodes
|
||
* @return
|
||
*/
|
||
public Map<GraphPart, List<GraphPart>> identifyLoopBreaks(BaseLocalData localData, Set<GraphPart> allParts) {
|
||
Map<GraphPart, List<GraphPart>> lb = new HashMap<>();
|
||
|
||
for (GraphPart b0 : allParts) {
|
||
List<GraphPart> np = new ArrayList<>(b0.nextParts);
|
||
np.addAll(b0.throwParts);
|
||
for (GraphPart b : np) {
|
||
GraphPart hdr = (b0.type == GraphPart.TYPE_LOOP_HEADER || b0.type == GraphPart.TYPE_REENTRY) ? b0 : b0.iloop_header;
|
||
|
||
if (hdr != null && b.iloop_header != hdr && b.iloop_header == hdr.iloop_header && b != hdr) {
|
||
if (!lb.containsKey(hdr)) {
|
||
lb.put(hdr, new ArrayList<>());
|
||
}
|
||
if (!lb.get(hdr).contains(b)) {
|
||
lb.get(hdr).add(b);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return lb;
|
||
}
|
||
|
||
/**
|
||
* Identifying loops. Based on http://lenx.100871.net/papers/loop-SAS.pdf
|
||
*
|
||
* @param localData
|
||
* @param loopContinues Result - list of loop headers
|
||
* @param heads Entries
|
||
* @param appParts All Nodes
|
||
*/
|
||
public void identifyLoops(BaseLocalData localData, List<GraphPart> loopContinues, List<GraphPart> heads, Set<GraphPart> appParts) {
|
||
for (GraphPart b : appParts) {
|
||
b.traversed = false;
|
||
b.DFSP_pos = 0;
|
||
b.irreducible = false;
|
||
b.type = GraphPart.TYPE_NONE;
|
||
//initialize b
|
||
}
|
||
for (GraphPart h0 : heads) {
|
||
trav_loops_DFS(localData, loopContinues, h0, 1);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Tag h as loop headr of b.
|
||
*
|
||
* @param b Block
|
||
* @param h Loop header
|
||
*/
|
||
protected void tag_lhead(GraphPart b, GraphPart h) {
|
||
if (b == h || h == null) {
|
||
return;
|
||
}
|
||
GraphPart cur1 = b;
|
||
GraphPart cur2 = h;
|
||
while (cur1.iloop_header != null) {
|
||
GraphPart ih = cur1.iloop_header;
|
||
if (ih == cur2) {
|
||
return;
|
||
}
|
||
if (ih.DFSP_pos < cur2.DFSP_pos) {
|
||
cur1.iloop_header = cur2;
|
||
cur1 = cur2;
|
||
cur2 = ih;
|
||
} else {
|
||
cur1 = h;
|
||
}
|
||
}
|
||
if (cur1 == cur2) {
|
||
return;
|
||
}
|
||
|
||
cur1.iloop_header = cur2;
|
||
}
|
||
|
||
protected List<GraphTargetItem> filter(List<GraphTargetItem> list) {
|
||
return new ArrayList<>(list);
|
||
}
|
||
|
||
/**
|
||
* Traverse loops deep first search
|
||
*
|
||
* @param localData
|
||
* @param loopHeaders Resulting loop headers
|
||
* @param b0 Current node
|
||
* @param DFSP_pos Position in DFSP
|
||
* @return innermost loop header of b0
|
||
*/
|
||
protected GraphPart trav_loops_DFS(BaseLocalData localData, List<GraphPart> loopHeaders, GraphPart b0, int DFSP_pos) {
|
||
|
||
List<GraphPart> folParts = new ArrayList<>(b0.nextParts);
|
||
folParts.addAll(b0.throwParts);
|
||
|
||
b0.traversed = true;
|
||
b0.DFSP_pos = DFSP_pos; //Mark b0’s position in DFSP
|
||
for (GraphPart b : folParts) {
|
||
b = checkPart(null, localData, b, null);
|
||
if (b == null) {
|
||
continue;
|
||
}
|
||
if (!b.traversed) {
|
||
//case (A), new
|
||
GraphPart nh = trav_loops_DFS(localData, loopHeaders, b, DFSP_pos + 1);
|
||
tag_lhead(b0, nh);
|
||
} else if (b.DFSP_pos > 0) { // b in DFSP(b0)
|
||
//case (B)
|
||
if (b.type != GraphPart.TYPE_LOOP_HEADER) {
|
||
b.type = GraphPart.TYPE_LOOP_HEADER;
|
||
loopHeaders.add(b);
|
||
}
|
||
tag_lhead(b0, b);
|
||
} else if (b.iloop_header == null) {
|
||
//case (C), do nothing
|
||
} else {
|
||
GraphPart h = b.iloop_header;
|
||
if (h.DFSP_pos > 0) { // h in DFSP(b0)
|
||
//case (D)
|
||
tag_lhead(b0, h);
|
||
} else { // h not in DFSP(b0)
|
||
//case (E), reentry
|
||
b.type = GraphPart.TYPE_REENTRY; //TODO:and b0,b ?
|
||
h.irreducible = true;
|
||
while (h.iloop_header != null) {
|
||
h = h.iloop_header;
|
||
if (h.DFSP_pos > 0) { //h in DFSP(b0)
|
||
tag_lhead(b0, h);
|
||
break;
|
||
}
|
||
h.irreducible = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
b0.DFSP_pos = 0; // clear b0’s DFSP position
|
||
return b0.iloop_header;
|
||
}
|
||
|
||
public Graph(GraphSource code, List<GraphException> exceptions) {
|
||
this.code = code;
|
||
this.exceptions = exceptions;
|
||
|
||
}
|
||
|
||
public void init(BaseLocalData localData) throws InterruptedException {
|
||
if (heads != null) {
|
||
return;
|
||
}
|
||
heads = makeGraph(code, new ArrayList<>(), exceptions);
|
||
int time = 1;
|
||
List<GraphPart> ordered = new ArrayList<>();
|
||
List<GraphPart> visited = new ArrayList<>();
|
||
for (GraphPart head : heads) {
|
||
time = head.setTime(time, ordered, visited);
|
||
}
|
||
}
|
||
|
||
protected static void populateParts(GraphPart part, Set<GraphPart> allParts) {
|
||
if (allParts.contains(part)) {
|
||
return;
|
||
}
|
||
allParts.add(part);
|
||
for (GraphPart p : part.nextParts) {
|
||
populateParts(p, allParts);
|
||
}
|
||
}
|
||
|
||
public GraphPart deepCopy(GraphPart part) {
|
||
return deepCopy(part, new HashMap<>());
|
||
}
|
||
|
||
private GraphPart deepCopy(GraphPart part, Map<GraphPart, GraphPart> copies) {
|
||
GraphPart copy = copies.get(part);
|
||
if (copy != null) {
|
||
return copy;
|
||
}
|
||
|
||
copy = new GraphPart(part.start, part.end);
|
||
copy.path = part.path;
|
||
copies.put(part, copy);
|
||
copy.nextParts = new ArrayList<>();
|
||
for (int i = 0; i < part.nextParts.size(); i++) {
|
||
copy.nextParts.add(deepCopy(part.nextParts.get(i), copies));
|
||
}
|
||
|
||
for (int i = 0; i < part.refs.size(); i++) {
|
||
copy.refs.add(deepCopy(part.refs.get(i), copies));
|
||
}
|
||
|
||
return copy;
|
||
}
|
||
|
||
public void resetGraph(GraphPart part, Set<GraphPart> visited) {
|
||
if (visited.contains(part)) {
|
||
return;
|
||
}
|
||
|
||
visited.add(part);
|
||
int pos = 0;
|
||
for (GraphPart p : part.nextParts) {
|
||
if (!visited.contains(p)) {
|
||
p.path = part.path.sub(pos, p.end);
|
||
}
|
||
|
||
resetGraph(p, visited);
|
||
pos++;
|
||
}
|
||
}
|
||
|
||
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops, List<GraphPartEdge> gotoParts) {
|
||
// use LinkedHashSet to preserve order
|
||
getReachableParts(part, ret, loops, true, gotoParts);
|
||
}
|
||
|
||
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops, boolean first, List<GraphPartEdge> gotoParts) {
|
||
// todo: honfika: why call with first = true parameter always?
|
||
Stack<GraphPartQueue> stack = new Stack<>();
|
||
GraphPartQueue queue = new GraphPartQueue();
|
||
queue.add(part);
|
||
stack.add(queue);
|
||
stacknext:
|
||
while (!stack.isEmpty()) {
|
||
|
||
queue = stack.peek();
|
||
if (!queue.isEmpty()) {
|
||
part = queue.remove();
|
||
} else if (queue.currentLoop != null) {
|
||
Loop cLoop = queue.currentLoop;
|
||
part = cLoop.loopBreak;
|
||
queue.currentLoop = null;
|
||
if (ret.contains(part)) {
|
||
continue;
|
||
}
|
||
|
||
ret.add(part);
|
||
cLoop.reachableMark = 2;
|
||
} else {
|
||
stack.pop();
|
||
continue;
|
||
}
|
||
|
||
for (Loop l : loops) {
|
||
l.reachableMark = 0;
|
||
}
|
||
|
||
Loop currentLoop = null;
|
||
for (Loop l : loops) {
|
||
if ((l.phase == 1) || (l.reachableMark == 1)) {
|
||
if (l.loopContinue == part) {
|
||
continue stacknext;
|
||
}
|
||
if (l.loopBreak == part) {
|
||
continue stacknext;
|
||
}
|
||
if (l.loopPreContinue == part) {
|
||
continue stacknext;
|
||
}
|
||
}
|
||
if (l.reachableMark == 0) {
|
||
if (l.loopContinue == part) {
|
||
l.reachableMark = 1;
|
||
currentLoop = l;
|
||
}
|
||
}
|
||
}
|
||
|
||
GraphPartQueue newParts = new GraphPartQueue();
|
||
loopnext:
|
||
for (GraphPart next : part.nextParts) {
|
||
if (gotoParts.contains(new GraphPartEdge(part, next))) {
|
||
continue;
|
||
}
|
||
for (Loop l : loops) {
|
||
if ((l.phase == 1) || (l.reachableMark == 1)) {
|
||
if (l.loopContinue == next) {
|
||
continue loopnext;
|
||
}
|
||
if (l.loopBreak == next) {
|
||
continue loopnext;
|
||
}
|
||
if (l.loopPreContinue == next) {
|
||
continue loopnext;
|
||
}
|
||
}
|
||
|
||
}
|
||
if (!ret.contains(next)) {
|
||
newParts.add(next);
|
||
}
|
||
}
|
||
|
||
ret.addAll(newParts);
|
||
if (currentLoop != null && currentLoop.loopBreak != null) {
|
||
newParts.currentLoop = currentLoop;
|
||
}
|
||
|
||
if (!newParts.isEmpty() || newParts.currentLoop != null) {
|
||
stack.add(newParts);
|
||
}
|
||
}
|
||
}
|
||
|
||
public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
|
||
return getCommonPart(localData, part.nextParts, loops, gotoParts);
|
||
}
|
||
|
||
//TODO: Make this faster!
|
||
public GraphPart getCommonPart(BaseLocalData localData, List<GraphPart> parts, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
|
||
if (parts.isEmpty()) {
|
||
return null;
|
||
}
|
||
|
||
List<GraphPart> loopContinues = new ArrayList<>();//getLoopsContinues(loops);
|
||
for (Loop l : loops) {
|
||
if (l.phase == 1) {
|
||
loopContinues.add(l.loopContinue);
|
||
}
|
||
}
|
||
|
||
for (GraphPart p : parts) {
|
||
if (loopContinues.contains(p)) {
|
||
break;
|
||
}
|
||
if (gotoParts.contains(p)) {
|
||
break;
|
||
}
|
||
boolean common = true;
|
||
for (GraphPart q : parts) {
|
||
if (q == p) {
|
||
continue;
|
||
}
|
||
if (!q.leadsTo(localData, this, code, p, loops, gotoParts)) {
|
||
common = false;
|
||
break;
|
||
}
|
||
}
|
||
if (common) {
|
||
return p;
|
||
}
|
||
}
|
||
List<Set<GraphPart>> reachable = new ArrayList<>();
|
||
for (GraphPart p : parts) {
|
||
LinkedHashSet<GraphPart> r1 = new LinkedHashSet<>();
|
||
getReachableParts(p, r1, loops, gotoParts);
|
||
r1.add(p);
|
||
reachable.add(r1);
|
||
}
|
||
Set<GraphPart> first = reachable.get(0);
|
||
for (GraphPart p : first) {
|
||
/*if (ignored.contains(p)) {
|
||
continue;
|
||
}*/
|
||
p = checkPart(null, localData, p, null);
|
||
if (p == null) {
|
||
continue;
|
||
}
|
||
boolean common = true;
|
||
for (Set<GraphPart> r : reachable) {
|
||
if (!r.contains(p)) {
|
||
common = false;
|
||
break;
|
||
}
|
||
}
|
||
if (common) {
|
||
return p;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public GraphPart getMostCommonPart(BaseLocalData localData, List<GraphPart> parts, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
|
||
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(localData, this, code, p, loops, gotoParts)) {
|
||
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(localData, this, code, parts.get(j), loops, gotoParts)) {
|
||
parts.remove(i);
|
||
i--;
|
||
continue loopi;
|
||
}
|
||
}
|
||
}
|
||
List<Set<GraphPart>> reachable = new ArrayList<>();
|
||
for (GraphPart p : parts) {
|
||
LinkedHashSet<GraphPart> r1 = new LinkedHashSet<>();
|
||
getReachableParts(p, r1, loops, gotoParts);
|
||
Set<GraphPart> r2 = new LinkedHashSet<>();
|
||
r2.add(p);
|
||
r2.addAll(r1);
|
||
reachable.add(r2);
|
||
}
|
||
///List<GraphPart> first = reachable.get(0);
|
||
int commonLevel;
|
||
Map<GraphPart, Integer> levelMap = new HashMap<>();
|
||
for (Set<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 (Set<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, BaseLocalData localData) {
|
||
while (code.get(part.start).isJump()) {
|
||
part = part.getSubParts().get(0).nextParts.get(0);
|
||
}
|
||
/*localData = prepareBranchLocalData(localData);
|
||
TranslateStack st = new TranslateStack();
|
||
List<GraphTargetItem> output=new ArrayList<>();
|
||
GraphPart startPart = part;
|
||
for (int i = part.start; i <= part.end; i++) {
|
||
GraphSourceItem src = code.get(i);
|
||
if (src.isJump()) {
|
||
part = part.nextParts.get(0);
|
||
if(st.isEmpty()){
|
||
startPart = part;
|
||
}
|
||
i = part.start - 1;
|
||
continue;
|
||
}
|
||
try{
|
||
src.translate(localData, st, output, SOP_USE_STATIC, "");
|
||
}catch(Exception ex){
|
||
return startPart;
|
||
}
|
||
if(!output.isEmpty()){
|
||
return startPart;
|
||
}
|
||
}*/
|
||
return part;
|
||
}
|
||
|
||
public static List<GraphTargetItem> translateViaGraph(BaseLocalData localData, String path, GraphSource code, List<GraphException> exceptions, int staticOperation) throws InterruptedException {
|
||
Graph g = new Graph(code, exceptions);
|
||
g.init(localData);
|
||
return g.translate(localData, staticOperation, path);
|
||
}
|
||
|
||
protected void afterPopupateAllParts(Set<GraphPart> allParts) {
|
||
|
||
}
|
||
|
||
public List<GraphTargetItem> translate(BaseLocalData localData, int staticOperation, String path) throws InterruptedException {
|
||
|
||
Set<GraphPart> allParts = new HashSet<>();
|
||
for (GraphPart head : heads) {
|
||
populateParts(head, allParts);
|
||
}
|
||
afterPopupateAllParts(allParts);
|
||
if (debugPrintAllParts) {
|
||
System.err.println("parts:");
|
||
for (GraphPart p : allParts) {
|
||
System.err.print(p);
|
||
if (!p.nextParts.isEmpty()) {
|
||
System.err.print(", next: ");
|
||
}
|
||
boolean first = true;
|
||
for (GraphPart n : p.nextParts) {
|
||
if (!first) {
|
||
System.err.print(",");
|
||
}
|
||
System.err.print(n);
|
||
first = false;
|
||
}
|
||
System.err.println("");
|
||
}
|
||
System.err.println("/parts");
|
||
}
|
||
TranslateStack stack = new TranslateStack(path);
|
||
List<Loop> loops = new ArrayList<>();
|
||
|
||
//TODO: Make this working. :-(
|
||
final boolean newLoopDetection = false;
|
||
|
||
if (!newLoopDetection) {
|
||
getLoops(localData, heads.get(0), loops, null);
|
||
} else {
|
||
List<GraphPart> loopHeads = new ArrayList<>();
|
||
identifyLoops(localData, loopHeads, heads, allParts);
|
||
Map<GraphPart, List<GraphPart>> loopBreaks = identifyLoopBreaks(localData, allParts);
|
||
|
||
List<Loop> loops2 = new ArrayList<>();
|
||
for (int i = 0; i < loopHeads.size(); i++) {
|
||
loops2.add(new Loop(loops2.size(), loopHeads.get(i), null));
|
||
}
|
||
for (int i = 0; i < loopHeads.size(); i++) {
|
||
if (loopBreaks.containsKey(loopHeads.get(i))) {
|
||
loops2.get(i).loopBreak = loopBreaks.get(loopHeads.get(i)).get(0);//getMostCommonPart(localData, loopBreaks.get(loopHeads.get(i)), loops2);
|
||
} else {
|
||
loops2.get(i).loopBreak = null;
|
||
}
|
||
}
|
||
|
||
loops = loops2;
|
||
}
|
||
|
||
if (debugPrintLoopList) {
|
||
System.err.println("<loops>");
|
||
for (Loop el : loops) {
|
||
System.err.println(el);
|
||
}
|
||
System.err.println("</loops>");
|
||
}
|
||
|
||
//TODO: Make getPrecontinues faster
|
||
getBackEdges(localData, loops, new ArrayList<>());
|
||
//getPrecontinues(path, localData, null, heads.get(0), allParts, loops, null);
|
||
//getPrecontinues2(path, localData, null, heads.get(0), allParts, loops, null);
|
||
List<GraphPartEdge> gotoTargets = new ArrayList<>();
|
||
|
||
findGotoTargets(path, heads.get(0), allParts, loops, gotoTargets);
|
||
|
||
/*System.err.println("<loopspre>");
|
||
for (Loop el : loops) {
|
||
System.err.println(el);
|
||
}
|
||
System.err.println("</loopspre>");//*/
|
||
List<GotoItem> gotos = new ArrayList<>();
|
||
List<GraphTargetItem> ret = printGraph(gotos, gotoTargets, new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
|
||
Map<String, Integer> usages = new HashMap<>();
|
||
Map<String, GotoItem> lastUsage = new HashMap<>();
|
||
for (GotoItem gi : gotos) {
|
||
if (!usages.containsKey(gi.labelName)) {
|
||
usages.put(gi.labelName, 0);
|
||
}
|
||
usages.put(gi.labelName, usages.get(gi.labelName) + 1);
|
||
lastUsage.put(gi.labelName, gi);
|
||
}
|
||
for (String labelName : usages.keySet()) {
|
||
if (usages.get(labelName) == 1) {
|
||
lastUsage.get(labelName).labelName = null;
|
||
}
|
||
}
|
||
expandGotos(ret);
|
||
processIfs(ret);
|
||
finalProcessStack(stack, ret, path);
|
||
finalProcessAll(ret, 0, new FinalProcessLocalData(loops), path);
|
||
return ret;
|
||
}
|
||
|
||
private List<GraphPart> getCommonPrefix(List<List<GraphPart>> listOfLists) {
|
||
List<GraphPart> result = new ArrayList<>();
|
||
if (listOfLists.isEmpty()) {
|
||
return result;
|
||
}
|
||
|
||
int maxlen = Integer.MAX_VALUE;
|
||
for (int j = 0; j < listOfLists.size(); j++) {
|
||
if (listOfLists.get(j).size() < maxlen) {
|
||
maxlen = listOfLists.get(j).size();
|
||
}
|
||
}
|
||
for (int i = 0; i < maxlen; i++) {
|
||
List<GraphPart> firstList = listOfLists.get(0);
|
||
for (int j = 1; j < listOfLists.size(); j++) {
|
||
if (!listOfLists.get(j).get(i).equals(firstList.get(i))) {
|
||
return result;
|
||
}
|
||
}
|
||
result.add(firstList.get(i));
|
||
}
|
||
return result;
|
||
}
|
||
|
||
private GraphPart getDominator(GraphPart graphStart, GraphPart targetPart, List<Loop> loops) {
|
||
Set<GraphPart> refs = new LinkedHashSet<>();
|
||
List<GraphPart> parts = targetPart.refs;
|
||
|
||
List<List<GraphPart>> allPredecessorsLists = new ArrayList<>();
|
||
for (GraphPart part : parts) {
|
||
List<GraphPart> allPredecessors = new ArrayList<>();
|
||
getAllPredecessors(part, allPredecessors, loops, null);
|
||
//allRefs.addAll(allPredecessors);
|
||
logger.info("predecessors of part " + part + " are: " + pathToString(allPredecessors));
|
||
allPredecessorsLists.add(allPredecessors);
|
||
}
|
||
List<GraphPart> firstList = allPredecessorsLists.get(0);
|
||
GraphPart commonPart = null;
|
||
looppart:
|
||
for (GraphPart part : firstList) {
|
||
for (int i = 1; i < allPredecessorsLists.size(); i++) {
|
||
if (!allPredecessorsLists.get(i).contains(part)) {
|
||
continue looppart;
|
||
}
|
||
}
|
||
logger.info("checking predeccessor " + part);
|
||
for (GraphPart part2 : parts) {
|
||
List<GraphPart> allPredecessors = new ArrayList<>();
|
||
getAllPredecessors(part2, allPredecessors, loops, part);
|
||
logger.info("predecessors of " + part2 + ": " + allPredecessors);
|
||
if (allPredecessors.contains(graphStart)) {
|
||
logger.info("graphstart(" + graphStart + ") found, " + part + " will not be correct");
|
||
continue looppart;
|
||
}
|
||
}
|
||
|
||
commonPart = part;
|
||
|
||
break;
|
||
}
|
||
|
||
return commonPart;
|
||
}
|
||
|
||
private void getAllPredecessors(GraphPart part, List<GraphPart> ret, List<Loop> loops, GraphPart ignored) {
|
||
List<GraphPart> toprocess = new ArrayList<>();
|
||
loopref:
|
||
for (GraphPart ref : part.refs) {
|
||
for (Loop el : loops) {
|
||
if (part.equals(el.loopContinue) && el.backEdges.contains(ref)) {
|
||
continue loopref;
|
||
}
|
||
}
|
||
if (ref == ignored) {
|
||
continue;
|
||
}
|
||
if (!ret.contains(ref)) {
|
||
ret.add(0, ref);
|
||
toprocess.add(ref);
|
||
}
|
||
}
|
||
for (GraphPart ref : toprocess) {
|
||
getAllPredecessors(ref, ret, loops, ignored);
|
||
}
|
||
}
|
||
|
||
private void findGotoTargetsWalk(Map<GraphPart, List<GraphPart>> partToNext, Map<GraphPart, List<GraphPart>> partToPrev, Reference<Integer> currentVirtualNum, List<GraphExceptionParts> openedExceptions, GraphPartEdge e,
|
||
Set<GraphPart> opened,
|
||
Set<GraphPart> closed,
|
||
Set<GraphPart> closedBranches,
|
||
Set<GraphPartEdge> exitEdges,
|
||
Set<GraphPartEdge> backEdges,
|
||
Set<GraphPartEdge> throwEdges,
|
||
Set<GraphPartEdge> allowedThrowEdges,
|
||
List<GraphExceptionParts> exceptionParts,
|
||
Map<GraphPartEdge, List<GraphPart>> edgeToBranches,
|
||
GraphPart start,
|
||
List<GraphPartEdge> gotoTargets) {
|
||
GraphPart p = e.to;
|
||
if (closed.contains(p)) {
|
||
logger.fine("part " + p + " is already closed, skipping");
|
||
return;
|
||
}
|
||
logger.fine("processing " + p);
|
||
if (!edgeToBranches.containsKey(e)) {
|
||
edgeToBranches.put(e, new ArrayList<>());
|
||
}
|
||
List<GraphPart> branches = edgeToBranches.get(e);
|
||
if (p != start) {
|
||
List<GraphPart> refs = getUnicatePartList(partToPrev.get(p));
|
||
|
||
List<List<GraphPart>> comparedPaths = new ArrayList<>();
|
||
List<GraphPartEdge> comparedPathsEdges = new ArrayList<>();
|
||
for (GraphPart r : refs) {
|
||
GraphPartEdge re = new GraphPartEdge(r, p);
|
||
/*if (throwEdges.contains(re) && !allowedThrowEdges.contains(re)) {
|
||
logger.fine("ref edge " + re + " is throwedge, ignored");
|
||
continue;
|
||
}*/
|
||
if (backEdges.contains(re)) {
|
||
logger.fine("ref edge " + re + " is backedge, ignored");
|
||
continue;
|
||
}
|
||
if (r.start == -1) {
|
||
logger.fine("ref edge " + re + " is alternatestart, ignored");
|
||
continue;
|
||
}
|
||
if (!edgeToBranches.containsKey(re)) {
|
||
//edge not yet processed
|
||
logger.fine("ref edge " + re + " NOT yet processed");
|
||
return;
|
||
} else {
|
||
logger.fine("ref edge " + re + " already processed");
|
||
}
|
||
comparedPaths.add(edgeToBranches.get(re));
|
||
comparedPathsEdges.add(re);
|
||
|
||
}
|
||
|
||
boolean isEndOfBlock = false;
|
||
|
||
loopi:
|
||
for (int i = 0; i < comparedPaths.size(); i++) {
|
||
for (int j = 0; j < comparedPaths.size(); j++) {
|
||
if (i == j) {
|
||
continue;
|
||
}
|
||
if (comparedPaths.get(i).equals(comparedPaths.get(j))) {
|
||
//logger.info("paths match: " + comparedPaths.get(i));
|
||
if (comparedPaths.get(i).isEmpty()) {
|
||
//logger.info("path isempty, removing it ");
|
||
comparedPaths.remove(i);
|
||
comparedPathsEdges.remove(i);
|
||
i--;
|
||
continue loopi;
|
||
}
|
||
logger.fine("merged paths:" + pathToString(comparedPaths.get(i)) + " of edge " + comparedPathsEdges.get(i));
|
||
|
||
GraphPart decision = comparedPaths.get(i).get(comparedPaths.get(i).size() - 1);
|
||
if (partToNext.get(decision).size() > 2) {
|
||
int removedCount = 0;
|
||
for (int k = comparedPaths.size() - 1; k >= 0; k--) {
|
||
if (k == i) {
|
||
continue;
|
||
}
|
||
if (comparedPaths.get(i).equals(comparedPaths.get(k))) {
|
||
comparedPaths.remove(k);
|
||
comparedPathsEdges.remove(k);
|
||
removedCount++;
|
||
}
|
||
if (removedCount == partToNext.get(decision).size() - 1) {
|
||
break;
|
||
}
|
||
}
|
||
comparedPaths.get(i).remove(comparedPaths.get(i).size() - 1);
|
||
} else {
|
||
//remove last path component
|
||
int last = i > j ? i : j;
|
||
int first = i < j ? i : j;
|
||
comparedPaths.get(first).remove(comparedPaths.get(first).size() - 1);
|
||
comparedPaths.remove(last);
|
||
comparedPathsEdges.remove(last);
|
||
}
|
||
//logger.fine("normal closing " + decision);
|
||
|
||
if (!closedBranches.contains(decision)) {
|
||
logger.fine("on part " + p);
|
||
logger.fine("normal closing branch " + decision);
|
||
closedBranches.add(decision);
|
||
} else {
|
||
logger.fine("branch already closed: " + decision);
|
||
isEndOfBlock = true;
|
||
}
|
||
closedBranches.add(decision);
|
||
i = -1;
|
||
continue loopi;
|
||
}
|
||
}
|
||
}
|
||
for (List<GraphPart> cp : comparedPaths) {
|
||
logger.fine("- branches:" + pathToString(cp));
|
||
}
|
||
|
||
if (comparedPaths.size() > 1) {
|
||
logger.fine("not a single path");
|
||
for (int i = 0; i < comparedPaths.size(); i++) {
|
||
|
||
}
|
||
List<GraphPart> prefix = getCommonPrefix(comparedPaths);
|
||
Set<GraphPart> partsToClose = new HashSet<>();
|
||
GraphPart decision = prefix.isEmpty() ? null : prefix.get(prefix.size() - 1);
|
||
|
||
for (int i = 0; i < comparedPaths.size(); i++) {
|
||
for (int j = prefix.size() - 1; j < comparedPaths.get(i).size(); j++) {
|
||
if (j < 0) {
|
||
continue;
|
||
}
|
||
GraphPart partToClose = comparedPaths.get(i).get(j);
|
||
GraphPartEdge edgeToClose = comparedPathsEdges.get(i);
|
||
if (!closedBranches.contains(partToClose)) {
|
||
logger.fine("on part " + p);
|
||
logger.fine("closing branch " + partToClose);
|
||
partsToClose.add(partToClose);
|
||
} else {
|
||
logger.fine("branch already closed: " + partToClose);
|
||
logger.fine("probably break edge: " + edgeToClose);
|
||
isEndOfBlock = true;
|
||
}
|
||
}
|
||
}
|
||
/*if (decision != null) {
|
||
logger.fine("closing branch 2: " + decision);
|
||
closedBranches.add(decision);
|
||
}*/
|
||
closedBranches.addAll(partsToClose);
|
||
branches = prefix;
|
||
if (!branches.isEmpty()) {
|
||
branches.remove(branches.size() - 1);
|
||
}
|
||
|
||
}
|
||
|
||
if (isEndOfBlock) {
|
||
//GraphPart blockStartPart = getDominator(startPart, p, loops);
|
||
//logger.info("found breaks to to " + p);
|
||
//System.err.println("found breaks to to " + p);
|
||
for (GraphPart r : p.refs) {
|
||
gotoTargets.add(new GraphPartEdge(r, p));
|
||
}
|
||
//gotoTargets.add(new GraphPartEdge(e.from, e.to));
|
||
}
|
||
|
||
}
|
||
|
||
List<GraphPart> nexts = new ArrayList<>();
|
||
|
||
boolean isExceptionStart = false;
|
||
GraphExceptionParts nearestEx = null;
|
||
List<GraphExceptionParts> currentExceptions = new ArrayList<>();
|
||
List<GraphPart> currentExceptionTargets = new ArrayList<>();
|
||
|
||
for (GraphExceptionParts ex : exceptionParts) {
|
||
if (openedExceptions.contains(ex)) {
|
||
continue;
|
||
}
|
||
if (p.equals(ex.start)) {
|
||
if (nearestEx != null && !ex.end.equals(nearestEx.end)) {
|
||
continue;
|
||
}
|
||
isExceptionStart = true;
|
||
currentExceptions.add(ex);
|
||
nearestEx = ex;
|
||
currentExceptionTargets.add(ex.target);
|
||
}
|
||
}
|
||
|
||
if (!currentExceptionTargets.isEmpty()) {
|
||
//openedExceptions = new ArrayList<>();
|
||
openedExceptions.addAll(currentExceptions);
|
||
List<GraphPart> virtualNexts = new ArrayList<>();
|
||
virtualNexts.add(p);
|
||
virtualNexts.addAll(currentExceptionTargets);
|
||
virtualNexts.add(nearestEx.end);
|
||
currentVirtualNum.setVal(currentVirtualNum.getVal() - 1);
|
||
GraphPart virtualPart = new GraphPart(currentVirtualNum.getVal(), currentVirtualNum.getVal());
|
||
partToNext.put(virtualPart, virtualNexts);
|
||
partToPrev.put(virtualPart, new ArrayList<>());
|
||
|
||
// connection from prevs of p to virtualPart
|
||
for (int k = 0; k < partToPrev.get(p).size(); k++) {
|
||
GraphPart pr = partToPrev.get(p).get(k);
|
||
List<GraphPart> prevNexts = partToNext.get(pr);
|
||
for (int j = 0; j < prevNexts.size(); j++) {
|
||
if (prevNexts.get(j).equals(p)) {
|
||
prevNexts.set(j, virtualPart);
|
||
}
|
||
}
|
||
partToPrev.get(virtualPart).add(pr);
|
||
}
|
||
for (GraphPart t : virtualNexts) {
|
||
if (t == nearestEx.end) {
|
||
partToPrev.get(t).add(virtualPart);
|
||
} else {
|
||
partToPrev.get(t).clear();
|
||
partToPrev.get(t).add(virtualPart);
|
||
}
|
||
}
|
||
p = virtualPart;
|
||
}
|
||
|
||
//filter out backedges
|
||
for (GraphPart n : partToNext.get(p)) {
|
||
GraphPartEdge ne = new GraphPartEdge(p, n);
|
||
if (!backEdges.contains(ne)) {
|
||
nexts.add(n);
|
||
} else {
|
||
logger.fine("next edge " + ne + " is backedge, ignored");
|
||
}
|
||
}
|
||
|
||
|
||
int sizeNextsNoThrow = nexts.size();
|
||
|
||
closed.add(p);
|
||
|
||
Stack<GraphPartEdge> walkStack = new Stack<>();
|
||
logger.fine("processing nextparts of " + p);
|
||
for (GraphPart n : nexts) {
|
||
GraphPartEdge ne = new GraphPartEdge(p, n);
|
||
List<GraphPart> subBranches = branches;
|
||
if (nexts.size() > 1) {
|
||
subBranches = new ArrayList<>(branches);
|
||
subBranches.add(p);
|
||
}
|
||
edgeToBranches.put(ne, subBranches);
|
||
walkStack.push(ne);
|
||
}
|
||
|
||
/*if (isTryBegin(p)) {
|
||
for (GraphPart t : p.throwParts) {
|
||
GraphPartEdge te = new GraphPartEdge(p, t);
|
||
if (backEdges.contains(te)) {
|
||
continue;
|
||
}
|
||
edgeToBranches.put(te, branches);
|
||
walkStack.push(te);
|
||
}
|
||
}*/
|
||
|
||
/*logger.fine("processing throwparts of " + p);
|
||
for (GraphPart n : p.throwParts) {
|
||
GraphPartEdge ne = new GraphPartEdge(p, n);
|
||
List<GraphPart> subBranches = new ArrayList<>(branches);
|
||
if (p.throwParts.size() > 1) {
|
||
subBranches = new ArrayList<>(branches);
|
||
subBranches.add(p);
|
||
}
|
||
edgeToBranches.put(ne, subBranches);
|
||
walkStack.push(ne);
|
||
}*/
|
||
while (!walkStack.isEmpty()) {
|
||
findGotoTargetsWalk(partToNext, partToPrev, currentVirtualNum, openedExceptions, walkStack.pop(), opened, closed, closedBranches, exitEdges, backEdges, throwEdges, allowedThrowEdges, exceptionParts, edgeToBranches, start, gotoTargets);
|
||
}
|
||
}
|
||
|
||
private void findGotoTargets(String path, GraphPart startPart, Set<GraphPart> allParts, List<Loop> loops, List<GraphPartEdge> gotoTargets) {
|
||
if (!path.endsWith(".run")) {
|
||
//return;
|
||
}
|
||
//logger.info("------ " + path);
|
||
//logger.info("GETTING precontinues of " + path + " =================");
|
||
Set<GraphPart> opened = new HashSet<>();
|
||
Set<GraphPart> closed = new HashSet<>();
|
||
Set<GraphPart> closedBranches = new HashSet<>();
|
||
Set<GraphPartEdge> exitEdges = new HashSet<>();
|
||
Set<GraphPartEdge> backEdges = new HashSet<>();
|
||
Set<GraphPartEdge> throwEdges = new HashSet<>();
|
||
Set<GraphPartEdge> allowedThrowEdges = new HashSet<>();
|
||
List<GraphExceptionParts> exceptionParts = new ArrayList<>();
|
||
Map<Integer, GraphPart> partByIp = new HashMap<>();
|
||
Map<GraphPart, List<GraphPart>> partToNext = new HashMap<>();
|
||
Map<GraphPart, List<GraphPart>> partToPrev = new HashMap<>();
|
||
for (GraphPart p : allParts) {
|
||
if (p.start == -1) {
|
||
continue;
|
||
}
|
||
//if (p.start >= 0) {
|
||
partByIp.put(p.start, p);
|
||
//}
|
||
partToNext.put(p, new ArrayList<>());
|
||
partToNext.get(p).addAll(p.nextParts);
|
||
partToPrev.put(p, new ArrayList<>());
|
||
|
||
for (GraphPart r : p.refs) {
|
||
if (r.start != -1) {
|
||
partToPrev.get(p).add(r);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (GraphException ex : exceptions) {
|
||
exceptionParts.add(new GraphExceptionParts(
|
||
partByIp.containsKey(ex.start) ? partByIp.get(ex.start) : null,
|
||
partByIp.containsKey(ex.end) ? partByIp.get(ex.end) : null,
|
||
partByIp.containsKey(ex.target) ? partByIp.get(ex.target) : null
|
||
));
|
||
}
|
||
|
||
for (GraphPart p : allParts) {
|
||
for (GraphPart tp : p.throwParts) {
|
||
GraphPartEdge e = new GraphPartEdge(p, tp);
|
||
if (!throwEdges.contains(e)) {
|
||
throwEdges.add(e);
|
||
logger.fine("throwpart " + e);
|
||
if (isTryBegin(p)) {
|
||
allowedThrowEdges.add(e);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (Loop el : loops) {
|
||
for (GraphPart g : el.backEdges) {
|
||
backEdges.add(new GraphPartEdge(g, el.loopContinue));
|
||
}
|
||
}
|
||
Map<GraphPartEdge, List<GraphPart>> edgeToBranches = new HashMap<>();
|
||
opened.add(startPart);
|
||
GraphPart start = startPart;
|
||
findGotoTargetsWalk(partToNext, partToPrev, new Reference<>(-2), new ArrayList<>(), new GraphPartEdge(startPart, startPart), opened, closed, closedBranches, exitEdges, backEdges, throwEdges, allowedThrowEdges, exceptionParts, edgeToBranches, start, gotoTargets);
|
||
}
|
||
|
||
private boolean isTryBegin(GraphPart part) {
|
||
for (GraphPart r : part.refs) {
|
||
if (r.start == -1) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private void getPrecontinues2(String path, BaseLocalData localData, GraphPart parent, GraphPart part, Set<GraphPart> allParts, List<Loop> loops, List<GraphPart> stopPart) throws InterruptedException {
|
||
for (Loop el : loops) {
|
||
if (el.backEdges.size() == 1) { //for statement has single real continue
|
||
GraphPart backEdge = (GraphPart) el.backEdges.toArray()[0];
|
||
|
||
GraphPart g = backEdge;
|
||
Set<GraphPart> openedParts = new HashSet<GraphPart>();
|
||
openedParts.addAll(g.nextParts);
|
||
List<GraphPart> level0Parts = new ArrayList<GraphPart>();
|
||
getPrecontinues2Walk(new HashMap<GraphPart, Integer>(), level0Parts, new HashMap<GraphPart, List<List<GraphPart>>>(), openedParts, g, loops, el, 0, new HashMap<GraphPart, List<GraphPart>>(), new ArrayList<>());
|
||
if (!level0Parts.isEmpty()) {
|
||
GraphPart lastPart = level0Parts.get(level0Parts.size() - 1);
|
||
el.loopPreContinue = lastPart;
|
||
logger.info("Found precontinue: " + lastPart);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
private String pathToString(Collection<GraphPart> list) {
|
||
List<String> strs = new ArrayList<>();
|
||
for (GraphPart p : list) {
|
||
strs.add(p.toString());
|
||
}
|
||
return "[" + String.join(", ", strs) + "]";
|
||
}
|
||
|
||
private List<GraphPart> getUnicatePartList(List<GraphPart> list) {
|
||
List<GraphPart> result = new ArrayList<>();
|
||
for (GraphPart p : list) {
|
||
if (!result.contains(p)) {
|
||
result.add(p);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
private List<GraphPart> getUnicateRefsNoThrow(GraphPart part, Set<GraphPartEdge> throwEdges) {
|
||
List<GraphPart> result = new ArrayList<>();
|
||
for (GraphPart r : part.refs) {
|
||
GraphPartEdge edge = new GraphPartEdge(r, part);
|
||
if (!throwEdges.contains(edge)) {
|
||
result.add(r);
|
||
}
|
||
}
|
||
|
||
return getUnicatePartList(result);
|
||
}
|
||
|
||
private List<GraphPart> getUsableRefs(GraphPart g, List<Loop> loops) {
|
||
List<GraphPart> ret = getUnicatePartList(g.refs);
|
||
for (Loop el : loops) {
|
||
for (GraphPart be : el.backEdges) {
|
||
if (ret.contains(be)) {
|
||
ret.remove(be);
|
||
}
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
private void getPrecontinues2Walk(Map<GraphPart, Integer> numRefsRemaining, List<GraphPart> level0Parts, Map<GraphPart, List<List<GraphPart>>> joinedPaths, Set<GraphPart> openedParts, GraphPart g, List<Loop> loops, Loop currentLoop, int partId, Map<GraphPart, List<GraphPart>> partPaths, List<GraphPart> path) {
|
||
logger.fine("start walk " + g);
|
||
if (g == currentLoop.loopContinue) {
|
||
return;
|
||
}
|
||
if (openedParts.contains(g)) {
|
||
logger.fine("- already walked - terminate");
|
||
return; //already walked
|
||
}
|
||
|
||
if (!joinedPaths.containsKey(g)) {
|
||
joinedPaths.put(g, new ArrayList<>());
|
||
}
|
||
joinedPaths.get(g).add(path);
|
||
|
||
boolean checkNext = true;
|
||
for (Loop el : loops) {
|
||
if (el.loopContinue == g) {
|
||
checkNext = false;
|
||
logger.fine("do not check next as current is loopcontinue");
|
||
break;
|
||
}
|
||
}
|
||
logger.fine("opened parts: " + pathToString(openedParts));
|
||
|
||
if (checkNext) {
|
||
//Do not proceed up before handling all descendants
|
||
for (GraphPart next : g.nextParts) {
|
||
if (!openedParts.contains(next)) {
|
||
logger.fine("- waiting for next descendats - terminate");
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
List<GraphPart> jp1 = joinedPaths.get(g).get(0);
|
||
for (List<GraphPart> jp : joinedPaths.get(g)) {
|
||
if (!jp.equals(jp1)) {
|
||
//paths in both branches do not match, do not continue up
|
||
logger.fine("- Paths mismatch - terminate");
|
||
logger.fine("path " + pathToString(jp) + " does not match " + pathToString(jp1));
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (!path.isEmpty() && g.nextParts.size() > 1) {
|
||
GraphPart lastPathComponent = path.get(path.size() - 1);
|
||
logger.fine("numrefs before = " + numRefsRemaining.get(lastPathComponent));
|
||
numRefsRemaining.put(lastPathComponent, numRefsRemaining.get(lastPathComponent) - 1);
|
||
logger.fine("numrefs = " + numRefsRemaining.get(lastPathComponent));
|
||
if (numRefsRemaining.get(lastPathComponent) == 1) {
|
||
logger.fine("numrefs is zero, removing last item of path " + pathToString(path));
|
||
path.remove(path.size() - 1);
|
||
}
|
||
}
|
||
if (path.isEmpty()) {
|
||
logger.fine("path is empty, adding current item");
|
||
level0Parts.add(g);
|
||
}
|
||
|
||
logger.fine("added to openedParts");
|
||
openedParts.add(g);
|
||
|
||
List<GraphPart> refs = getUsableRefs(g, loops);
|
||
numRefsRemaining.put(g, refs.size());
|
||
logger.fine("setting numrefs to " + refs.size());
|
||
logger.fine("all refs = " + pathToString(refs));
|
||
for (GraphPart ref : refs) {
|
||
logger.fine("going to ref " + ref + "...");
|
||
List<GraphPart> subPath = new ArrayList<GraphPart>(path);
|
||
if (refs.size() > 1) {
|
||
subPath.add(g);
|
||
}
|
||
getPrecontinues2Walk(numRefsRemaining, level0Parts, joinedPaths, openedParts, ref, loops, currentLoop, partId, partPaths, subPath);
|
||
}
|
||
logger.fine("/All refs of " + g + " processed");
|
||
}
|
||
|
||
/**/
|
||
//if (ref.nextParts)
|
||
private void getBackEdges(BaseLocalData localData, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
|
||
clearLoops(loops);
|
||
for (Loop el : loops) {
|
||
el.backEdges.clear();
|
||
Set<GraphPart> uniqueRefs = new HashSet<>(el.loopContinue.refs);
|
||
for (GraphPart r : uniqueRefs) {
|
||
if (el.loopContinue.leadsTo(localData, this, code, r, loops, gotoParts)) {
|
||
el.backEdges.add(r);
|
||
}
|
||
}
|
||
el.phase = 1;
|
||
}
|
||
clearLoops(loops);
|
||
}
|
||
|
||
public void finalProcessStack(TranslateStack stack, List<GraphTargetItem> output, String path) {
|
||
}
|
||
|
||
private void finalProcessAll(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
|
||
finalProcess(list, level, localData, path);
|
||
for (GraphTargetItem item : list) {
|
||
if (item instanceof Block) {
|
||
List<List<GraphTargetItem>> subs = ((Block) item).getSubs();
|
||
for (List<GraphTargetItem> sub : subs) {
|
||
finalProcessAll(sub, level + 1, localData, path);
|
||
}
|
||
}
|
||
}
|
||
finalProcessAfter(list, level, localData, path);
|
||
}
|
||
|
||
private boolean processSubBlk(Block b, GraphTargetItem replacement) {
|
||
boolean allSubPush = true;
|
||
boolean atleastOne = false;
|
||
for (List<GraphTargetItem> sub : b.getSubs()) {
|
||
if (!sub.isEmpty()) {
|
||
int lastPos = sub.size() - 1;
|
||
|
||
GraphTargetItem last = sub.get(sub.size() - 1);
|
||
GraphTargetItem br = null;
|
||
|
||
if ((last instanceof BreakItem) && (sub.size() >= 2)) {
|
||
br = last;
|
||
lastPos--;
|
||
last = sub.get(lastPos);
|
||
}
|
||
if (last instanceof Block) {
|
||
if (!processSubBlk((Block) last, replacement)) {
|
||
allSubPush = false;
|
||
} else {
|
||
atleastOne = true;
|
||
}
|
||
} else if (last instanceof PushItem) {
|
||
if (replacement != null) {
|
||
GraphTargetItem e2 = (((GraphTargetItem) replacement).clone());
|
||
e2.value = last.value;
|
||
sub.set(lastPos, e2);
|
||
if (br != null) {
|
||
sub.remove(sub.size() - 1);
|
||
}
|
||
}
|
||
atleastOne = true;
|
||
} else if (!(last instanceof ExitItem)) {
|
||
allSubPush = false;
|
||
}
|
||
}
|
||
}
|
||
return allSubPush && atleastOne;
|
||
}
|
||
|
||
protected void finalProcessAfter(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) {
|
||
if (list.size() >= 2) {
|
||
if (list.get(list.size() - 1) instanceof ExitItem) {
|
||
ExitItem e = (ExitItem) list.get(list.size() - 1);
|
||
if (list.get(list.size() - 1).value instanceof PopItem) {
|
||
if (list.get(list.size() - 2) instanceof Block) {
|
||
Block b = (Block) list.get(list.size() - 2);
|
||
if (processSubBlk(b, (GraphTargetItem) e)) {
|
||
list.remove(list.size() - 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
|
||
|
||
//For detection based on debug line information
|
||
boolean[] toDelete = new boolean[list.size()];
|
||
for (int i = 0; i < list.size(); i++) {
|
||
if (Thread.currentThread().isInterrupted()) {
|
||
throw new InterruptedException();
|
||
}
|
||
|
||
GraphTargetItem itemI = list.get(i);
|
||
if (itemI instanceof ForItem) {
|
||
ForItem fori = (ForItem) itemI;
|
||
int exprLine = fori.getLine();
|
||
if (exprLine > 0) {
|
||
List<GraphTargetItem> forFirstCommands = new ArrayList<>();
|
||
for (int j = i - 1; j >= 0; j--) {
|
||
if (list.get(j).getLine() == exprLine && !(list.get(j) instanceof LoopItem /*to avoid recursion and StackOverflow*/)) {
|
||
forFirstCommands.add(0, list.get(j));
|
||
toDelete[j] = true;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
fori.firstCommands.addAll(0, forFirstCommands);
|
||
}
|
||
}
|
||
|
||
if (itemI instanceof WhileItem) {
|
||
WhileItem whi = (WhileItem) itemI;
|
||
int whileExprLine = whi.getLine();
|
||
if (whileExprLine > 0) {
|
||
List<GraphTargetItem> forFirstCommands = new ArrayList<>();
|
||
List<GraphTargetItem> forFinalCommands = new ArrayList<>();
|
||
|
||
for (int j = i - 1; j >= 0; j--) {
|
||
GraphTargetItem itemJ = list.get(j);
|
||
if (itemJ.getLine() == whileExprLine && !(itemJ instanceof LoopItem /*to avoid recursion and StackOverflow*/)) {
|
||
forFirstCommands.add(0, itemJ);
|
||
toDelete[j] = true;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
for (int j = whi.commands.size() - 1; j >= 0; j--) {
|
||
if (whi.commands.get(j).getLine() == whileExprLine && !(whi.commands.get(j) instanceof LoopItem /*to avoid recursion and StackOverflow*/)) {
|
||
forFinalCommands.add(0, whi.commands.remove(j));
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
if (!forFirstCommands.isEmpty() || !forFinalCommands.isEmpty()) {
|
||
//Do not allow more than 2 first/final commands, since it can be obfuscated
|
||
if (forFirstCommands.size() > 2 || forFinalCommands.size() > 2) {
|
||
//put it back
|
||
for (int k = 0; k < forFirstCommands.size(); k++) {
|
||
toDelete[i - 1 - k] = false;
|
||
}
|
||
whi.commands.addAll(forFinalCommands); //put it back
|
||
} else if (whi.commands.isEmpty() && forFirstCommands.isEmpty()) {
|
||
//it would be for(;expr;commands) {} which looks better as while(expr){commands}
|
||
whi.commands.addAll(forFinalCommands); //put it back
|
||
} else {
|
||
GraphTargetItem lastExpr = whi.expression.remove(whi.expression.size() - 1);
|
||
forFirstCommands.addAll(whi.expression);
|
||
list.set(i, new ForItem(whi.getSrc(), whi.getLineStartItem(), whi.loop, forFirstCommands, lastExpr, forFinalCommands, whi.commands));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (int i = toDelete.length - 1; i >= 0; i--) {
|
||
if (toDelete[i]) {
|
||
list.remove(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void expandGotos(List<GraphTargetItem> list) {
|
||
if (!list.isEmpty() && (list.get(list.size() - 1) instanceof GotoItem)) {
|
||
GotoItem gi = (GotoItem) list.get(list.size() - 1);
|
||
if (gi.targetCommands != null) {
|
||
list.remove(gi);
|
||
if (gi.labelName != null) {
|
||
list.add(new LabelItem(null, gi.lineStartItem, gi.labelName));
|
||
}
|
||
list.addAll(gi.targetCommands);
|
||
}
|
||
}
|
||
for (int i = 0; i < list.size(); i++) {
|
||
GraphTargetItem item = list.get(i);
|
||
if (item instanceof Block) {
|
||
List<List<GraphTargetItem>> subs = ((Block) item).getSubs();
|
||
for (List<GraphTargetItem> sub : subs) {
|
||
expandGotos(sub);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void processIfs(List<GraphTargetItem> list) {
|
||
for (int i = 0; i < list.size(); i++) {
|
||
GraphTargetItem item = list.get(i);
|
||
if ((item instanceof LoopItem) && (item instanceof Block)) {
|
||
List<List<GraphTargetItem>> subs = ((Block) item).getSubs();
|
||
for (List<GraphTargetItem> sub : subs) {
|
||
processIfs(sub);
|
||
checkContinueAtTheEnd(sub, ((LoopItem) item).loop);
|
||
}
|
||
} else if (item instanceof Block) {
|
||
List<List<GraphTargetItem>> subs = ((Block) item).getSubs();
|
||
for (List<GraphTargetItem> sub : subs) {
|
||
processIfs(sub);
|
||
}
|
||
}
|
||
if (item instanceof IfItem) {
|
||
IfItem ifi = (IfItem) item;
|
||
List<GraphTargetItem> onTrue = ifi.onTrue;
|
||
List<GraphTargetItem> onFalse = ifi.onFalse;
|
||
if ((!onTrue.isEmpty()) && (!onFalse.isEmpty())) {
|
||
if (onTrue.get(onTrue.size() - 1) instanceof GotoItem) {
|
||
if (onFalse.get(onFalse.size() - 1) instanceof GotoItem) {
|
||
GotoItem gotoOnTrue = (GotoItem) onTrue.get(onTrue.size() - 1);
|
||
GotoItem gotoOnFalse = (GotoItem) onFalse.get(onFalse.size() - 1);
|
||
String labelOnTrue = gotoOnTrue.labelName;
|
||
String labelOnFalse = gotoOnFalse.labelName;
|
||
if (labelOnTrue != null && labelOnFalse != null) {
|
||
if (labelOnTrue.equals(labelOnFalse)) {
|
||
GotoItem gotoMerged = gotoOnTrue.targetCommands != null ? gotoOnTrue : gotoOnFalse;
|
||
|
||
onTrue.remove(onTrue.size() - 1);
|
||
onFalse.remove(onFalse.size() - 1);
|
||
list.add(i + 1, gotoMerged);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if ((!onTrue.isEmpty()) && (!onFalse.isEmpty())) {
|
||
if (onTrue.get(onTrue.size() - 1) instanceof ContinueItem) {
|
||
if (onFalse.get(onFalse.size() - 1) instanceof ContinueItem) {
|
||
if (((ContinueItem) onTrue.get(onTrue.size() - 1)).loopId == ((ContinueItem) onFalse.get(onFalse.size() - 1)).loopId) {
|
||
onTrue.remove(onTrue.size() - 1);
|
||
list.add(i + 1, onFalse.remove(onFalse.size() - 1));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((!onTrue.isEmpty()) && (!onFalse.isEmpty())) {
|
||
GraphTargetItem last = onTrue.get(onTrue.size() - 1);
|
||
if ((last instanceof ExitItem) || (last instanceof ContinueItem) || (last instanceof BreakItem)) {
|
||
list.addAll(i + 1, onFalse);
|
||
onFalse.clear();
|
||
}
|
||
}
|
||
|
||
if ((!onTrue.isEmpty()) && (!onFalse.isEmpty())) {
|
||
if (onFalse.get(onFalse.size() - 1) instanceof ExitItem) {
|
||
if (onTrue.get(onTrue.size() - 1) instanceof ContinueItem) {
|
||
list.add(i + 1, onTrue.remove(onTrue.size() - 1));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//Same continues in onTrue and onFalse gets continue on parent level
|
||
}
|
||
|
||
protected List<GraphPart> getLoopsContinuesPreAndBreaks(List<Loop> loops) {
|
||
List<GraphPart> ret = new ArrayList<>();
|
||
for (Loop l : loops) {
|
||
if (l.loopContinue != null) {
|
||
ret.add(l.loopContinue);
|
||
}
|
||
if (l.loopPreContinue != null) {
|
||
ret.add(l.loopPreContinue);
|
||
}
|
||
if (l.loopBreak != null) {
|
||
ret.add(l.loopBreak);
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
protected List<GraphPart> getLoopsContinuesAndPre(List<Loop> loops) {
|
||
List<GraphPart> ret = new ArrayList<>();
|
||
for (Loop l : loops) {
|
||
if (l.loopContinue != null) {
|
||
ret.add(l.loopContinue);
|
||
}
|
||
if (l.loopPreContinue != null) {
|
||
ret.add(l.loopPreContinue);
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
protected List<GraphPart> getLoopsContinues(List<Loop> loops) {
|
||
List<GraphPart> ret = new ArrayList<>();
|
||
for (Loop l : loops) {
|
||
if (l.loopContinue != null) {
|
||
ret.add(l.loopContinue);
|
||
}
|
||
/*if (l.loopPreContinue != null) {
|
||
ret.add(l.loopPreContinue);
|
||
}*/
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
protected GraphTargetItem checkLoop(GraphPart part, List<GraphPart> stopPart, List<Loop> loops) {
|
||
if (stopPart.contains(part)) {
|
||
return null;
|
||
}
|
||
|
||
GraphSourceItem firstIns = null;
|
||
if (part != null) {
|
||
if (part.start >= 0 && part.start < code.size()) {
|
||
firstIns = code.get(part.start);
|
||
}
|
||
}
|
||
|
||
for (Loop l : loops) {
|
||
if (l.loopContinue == part) {
|
||
return (new ContinueItem(null, firstIns, l.id));
|
||
}
|
||
if (l.loopBreak == part) {
|
||
return (new BreakItem(null, firstIns, l.id));
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
//TODO: Make this faster!!!
|
||
private void getPrecontinues(String path, BaseLocalData localData, GraphPart parent, GraphPart part, Set<GraphPart> allParts, List<Loop> loops, List<GraphPart> stopPart) throws InterruptedException {
|
||
try {
|
||
markLevels(path, localData, part, allParts, loops);
|
||
} catch (ThreadDeath | InterruptedException ex) {
|
||
throw ex;
|
||
} catch (Throwable ex) {
|
||
//It is unusual code so markLevels failed, nevermind, it can still work
|
||
}
|
||
//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.level == 0 && part != l.loopContinue) {
|
||
l.loopPreContinue = part;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/*clearLoops(loops);
|
||
getPrecontinues(parent, part, loops, stopPart, 0, new ArrayList<GraphPart>());
|
||
clearLoops(loops);*/
|
||
}
|
||
|
||
private void markLevels(String path, BaseLocalData localData, GraphPart part, Set<GraphPart> allParts, List<Loop> loops) throws InterruptedException {
|
||
clearLoops(loops);
|
||
markLevels(path, localData, part, allParts, loops, new ArrayList<>(), 1, new HashSet<>(), 0);
|
||
clearLoops(loops);
|
||
}
|
||
|
||
private void markLevels(String path, BaseLocalData localData, GraphPart part, Set<GraphPart> allParts, List<Loop> loops, List<GraphPart> stopPart, int level, Set<GraphPart> visited, int recursionLevel) throws InterruptedException {
|
||
if (stopPart == null) {
|
||
stopPart = new ArrayList<>();
|
||
}
|
||
if (recursionLevel > allParts.size() + 1) {
|
||
throw new RuntimeException(path + ": markLevels max recursion level reached");
|
||
}
|
||
|
||
if (stopPart.contains(part)) {
|
||
//System.err.println("/stopped part " + part);
|
||
return;
|
||
}
|
||
for (Loop el : loops) {
|
||
if ((el.phase == 2) && (el.loopContinue == part)) {
|
||
return;
|
||
}
|
||
if (el.phase != 1) {
|
||
continue;
|
||
}
|
||
if (el.loopContinue == part) {
|
||
return;
|
||
}
|
||
if (el.loopPreContinue == part) {
|
||
return;
|
||
}
|
||
if (el.loopBreak == part) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (visited.contains(part)) {
|
||
part.level = 0;
|
||
//System.err.println("set level " + part + " to zero");
|
||
} else {
|
||
visited.add(part);
|
||
part.level = level;
|
||
//System.err.println("set level " + part + " to " + level);
|
||
}
|
||
|
||
boolean isLoop = false;
|
||
Loop currentLoop = null;
|
||
for (Loop el : loops) {
|
||
if ((el.phase == 0) && (el.loopContinue == part)) {
|
||
isLoop = true;
|
||
currentLoop = el;
|
||
el.phase = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
List<GraphPart> nextParts = checkPrecoNextParts(part);
|
||
if (nextParts == null) {
|
||
nextParts = part.nextParts;
|
||
}
|
||
nextParts = new ArrayList<>(nextParts);
|
||
|
||
if (nextParts.size() == 2 && stopPart.contains(nextParts.get(1))) {
|
||
nextParts.remove(1);
|
||
}
|
||
if (nextParts.size() >= 1 && stopPart.contains(nextParts.get(0))) {
|
||
nextParts.remove(0);
|
||
}
|
||
|
||
if (nextParts.size() == 2) {
|
||
GraphPart next = getCommonPart(localData, nextParts, loops, new ArrayList<>());//part.getNextPartPath(new ArrayList<GraphPart>());
|
||
//System.err.println("- common part of " + nextParts.get(0) + " and " + nextParts.get(1) + " is " + next);
|
||
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 != nextParts.get(0)) {
|
||
// System.err.println("- going to branch 0 nextpart from " + part + " to " + nextParts.get(0));
|
||
markLevels(path, localData, nextParts.get(0), allParts, loops, next == null ? stopPart : stopParts2, level + 1, visited, recursionLevel + 1);
|
||
} else {
|
||
//System.err.println("- branch 0 of " + part + " is skipped (=next)");
|
||
}
|
||
|
||
if (next != nextParts.get(1)) {
|
||
//System.err.println("- going to branch 1 nextpart from " + part + " to " + nextParts.get(1));
|
||
markLevels(path, localData, nextParts.get(1), allParts, loops, next == null ? stopPart : stopParts2, level + 1, visited, recursionLevel + 1);
|
||
} else {
|
||
//System.err.println("- branch 1 of " + part + " is skipped (=next)");
|
||
}
|
||
if (next != null) {
|
||
//System.err.println("- going to next from " + part + " to " + next);
|
||
markLevels(path, localData, next, allParts, loops, stopPart, level, visited, recursionLevel + 1);
|
||
}
|
||
}
|
||
|
||
if (nextParts.size() > 2) {
|
||
GraphPart next = getMostCommonPart(localData, nextParts, loops, new ArrayList<>());
|
||
List<GraphPart> vis = new ArrayList<>();
|
||
for (GraphPart p : nextParts) {
|
||
if (vis.contains(p)) {
|
||
continue;
|
||
}
|
||
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 : nextParts) {
|
||
if (p2 == p) {
|
||
continue;
|
||
}
|
||
if (!stopPart2.contains(p2)) {
|
||
stopPart2.add(p2);
|
||
}
|
||
}
|
||
if (next != p) {
|
||
markLevels(path, localData, p, allParts, loops, stopPart2, level + 1, visited, recursionLevel + 1);
|
||
vis.add(p);
|
||
}
|
||
}
|
||
if (next != null) {
|
||
markLevels(path, localData, next, allParts, loops, stopPart, level, visited, recursionLevel + 1);
|
||
}
|
||
}
|
||
|
||
if (nextParts.size() == 1) {
|
||
//System.err.println("going to one nexpart from " + part + " to " + nextParts.get(0));
|
||
markLevels(path, localData, nextParts.get(0), allParts, loops, stopPart, level, visited, recursionLevel + 1);
|
||
}
|
||
|
||
for (GraphPart t : part.throwParts) {
|
||
if (!visited.contains(t)) {
|
||
List<GraphPart> stopPart2 = new ArrayList<>();
|
||
List<GraphPart> cmn = new ArrayList<>();
|
||
cmn.add(part);
|
||
cmn.add(t);
|
||
GraphPart next = getCommonPart(localData, cmn, loops, new ArrayList<>());
|
||
if (next != null) {
|
||
stopPart2.add(next);
|
||
} else {
|
||
stopPart2 = stopPart;
|
||
}
|
||
|
||
markLevels(path, localData, t, allParts, loops, stopPart2, level, visited, recursionLevel + 1);
|
||
}
|
||
}
|
||
|
||
if (isLoop) {
|
||
if (currentLoop != null && currentLoop.loopBreak != null) {
|
||
currentLoop.phase = 2;
|
||
//System.err.println("- going to break of loop " + currentLoop.loopBreak);
|
||
markLevels(path, localData, currentLoop.loopBreak, allParts, loops, stopPart, level, visited, recursionLevel + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void checkContinueAtTheEnd(List<GraphTargetItem> commands, Loop loop) {
|
||
if (!commands.isEmpty()) {
|
||
int i = commands.size() - 1;
|
||
for (; i >= 0; i--) {
|
||
if (commands.get(i) instanceof ContinueItem) {
|
||
continue;
|
||
}
|
||
if (commands.get(i) instanceof BreakItem) {
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
if (i < commands.size() - 1) {
|
||
for (int k = i + 2; k < commands.size(); k++) {
|
||
commands.remove(k);
|
||
}
|
||
}
|
||
if (commands.get(commands.size() - 1) instanceof ContinueItem) {
|
||
if (((ContinueItem) commands.get(commands.size() - 1)).loopId == loop.id) {
|
||
commands.remove(commands.size() - 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
protected boolean isEmpty(List<GraphTargetItem> output) {
|
||
if (output.isEmpty()) {
|
||
return true;
|
||
}
|
||
if (output.size() == 1) {
|
||
if (output.get(0) instanceof MarkItem) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
protected List<GraphTargetItem> check(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
|
||
return null;
|
||
}
|
||
|
||
protected GraphPart checkPart(TranslateStack stack, BaseLocalData localData, GraphPart part, Set<GraphPart> allParts) {
|
||
return part;
|
||
}
|
||
|
||
//@SuppressWarnings("unchecked")
|
||
protected GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation) throws InterruptedException {
|
||
stack = (TranslateStack) stack.clone();
|
||
translatePart(localData, part, stack, staticOperation, null);
|
||
return stack.pop();
|
||
}
|
||
|
||
protected List<GraphTargetItem> translatePart(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException {
|
||
List<GraphPart> sub = part.getSubParts();
|
||
List<GraphTargetItem> ret = new ArrayList<>();
|
||
int end;
|
||
for (GraphPart p : sub) {
|
||
if (p.end == -1) {
|
||
p.end = code.size() - 1;
|
||
}
|
||
if (p.start == code.size()) {
|
||
continue;
|
||
} else if (p.end == code.size()) {
|
||
p.end--;
|
||
}
|
||
end = p.end;
|
||
int start = p.start;
|
||
ret.addAll(code.translatePart(part, localData, stack, start, end, staticOperation, path));
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
private void markBranchEnd(List<GraphTargetItem> items) {
|
||
if (!items.isEmpty()) {
|
||
if (items.get(items.size() - 1) instanceof BreakItem) {
|
||
return;
|
||
}
|
||
if (items.get(items.size() - 1) instanceof ContinueItem) {
|
||
return;
|
||
}
|
||
if (items.get(items.size() - 1) instanceof ExitItem) {
|
||
return;
|
||
}
|
||
}
|
||
items.add(new MarkItem("finish"));
|
||
}
|
||
|
||
private static GraphTargetItem getLastNoEnd(List<GraphTargetItem> list) {
|
||
if (list.isEmpty()) {
|
||
return null;
|
||
}
|
||
if (list.get(list.size() - 1) instanceof ScriptEndItem) {
|
||
if (list.size() >= 2) {
|
||
return list.get(list.size() - 2);
|
||
}
|
||
return list.get(list.size() - 1);
|
||
}
|
||
return list.get(list.size() - 1);
|
||
}
|
||
|
||
private static void removeLastNoEnd(List<GraphTargetItem> list) {
|
||
if (list.isEmpty()) {
|
||
return;
|
||
}
|
||
if (list.get(list.size() - 1) instanceof ScriptEndItem) {
|
||
if (list.size() >= 2) {
|
||
list.remove(list.size() - 2);
|
||
}
|
||
return;
|
||
}
|
||
list.remove(list.size() - 1);
|
||
}
|
||
|
||
protected List<GraphTargetItem> printGraph(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, int staticOperation, String path) throws InterruptedException {
|
||
return printGraph(foundGotos, gotoTargets, partCodes, partCodePos, new HashSet<>(), localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0);
|
||
}
|
||
|
||
protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List<Loop> loops) {
|
||
return loopItem;
|
||
}
|
||
|
||
private void clearLoops(List<Loop> loops) {
|
||
for (Loop l : loops) {
|
||
l.phase = 0;
|
||
}
|
||
}
|
||
|
||
private void getLoops(BaseLocalData localData, GraphPart part, List<Loop> loops, List<GraphPart> stopPart) throws InterruptedException {
|
||
clearLoops(loops);
|
||
getLoops(localData, part, loops, stopPart, true, 1, new ArrayList<>());
|
||
clearLoops(loops);
|
||
}
|
||
|
||
protected boolean canBeBreakCandidate(GraphPart part) {
|
||
return true;
|
||
}
|
||
|
||
private void getLoops(BaseLocalData localData, GraphPart part, List<Loop> loops, List<GraphPart> stopPart, boolean first, int level, List<GraphPart> visited) throws InterruptedException {
|
||
|
||
if (part == null) {
|
||
return;
|
||
}
|
||
|
||
part = checkPart(null, localData, part, null);
|
||
if (part == null) {
|
||
return;
|
||
}
|
||
if (!visited.contains(part)) {
|
||
visited.add(part);
|
||
}
|
||
|
||
if (debugGetLoops) {
|
||
System.err.println("getloops: " + part);
|
||
}
|
||
//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.loopContinue != part) {
|
||
lastP1 = el;
|
||
|
||
} else {
|
||
lastP1 = null;
|
||
}
|
||
|
||
}
|
||
}
|
||
if (lastP1 != null && canBeBreakCandidate(part)) {
|
||
if (lastP1.breakCandidates.contains(part)) {
|
||
lastP1.breakCandidates.add(part);
|
||
lastP1.breakCandidatesLevels.add(level);
|
||
return;
|
||
} else {
|
||
//List<GraphPart> loopContinues2 = new ArrayList<>(loopContinues);
|
||
//loopContinues2.remove(lastP1.loopContinue);
|
||
List<Loop> loops2 = new ArrayList<>(loops);
|
||
loops2.remove(lastP1);
|
||
if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, new ArrayList<>())) {
|
||
if (lastP1.breakCandidatesLocked == 0) {
|
||
if (debugGetLoops) {
|
||
System.err.println("added breakCandidate " + part + " to " + lastP1);
|
||
}
|
||
|
||
lastP1.breakCandidates.add(part);
|
||
lastP1.breakCandidatesLevels.add(level);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (Loop el : loops) {
|
||
if (el.loopContinue == part) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (stopPart != null && stopPart.contains(part)) {
|
||
return;
|
||
}
|
||
part.level = level;
|
||
|
||
boolean isLoop = part.leadsTo(localData, this, code, part, loops, new ArrayList<>());
|
||
Loop currentLoop = null;
|
||
if (isLoop) {
|
||
currentLoop = new Loop(loops.size(), part, null);
|
||
currentLoop.phase = 1;
|
||
loops.add(currentLoop);
|
||
//loopContinues.add(part);
|
||
}
|
||
|
||
if (part.nextParts.size() == 2) {
|
||
|
||
List<GraphPart> nps;/* = new ArrayList<>(part.nextParts);
|
||
for(int i=0;i<nps.size();i++){
|
||
nps.set(i,getNextNoJump(nps.get(i),localData));
|
||
}
|
||
if(nps.get(0) == nps.get(1)){
|
||
nps = part.nextParts;
|
||
}*/
|
||
|
||
nps = part.nextParts;
|
||
GraphPart next = getCommonPart(localData, nps, loops, new ArrayList<>());//part.getNextPartPath(loopContinues);
|
||
List<GraphPart> stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart);
|
||
if (next != null) {
|
||
stopPart2.add(next);
|
||
}
|
||
if (next != nps.get(0)) {
|
||
getLoops(localData, nps.get(0), loops, stopPart2, false, level + 1, visited);
|
||
}
|
||
if (next != nps.get(1)) {
|
||
getLoops(localData, nps.get(1), loops, stopPart2, false, level + 1, visited);
|
||
}
|
||
if (next != null) {
|
||
getLoops(localData, next, loops, stopPart, false, level, visited);
|
||
}
|
||
} else if (part.nextParts.size() > 2) {
|
||
GraphPart next = getNextCommonPart(localData, part, loops, new ArrayList<>());
|
||
|
||
for (GraphPart p : part.nextParts) {
|
||
List<GraphPart> stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart);
|
||
if (next != null) {
|
||
stopPart2.add(next);
|
||
}
|
||
for (GraphPart p2 : part.nextParts) {
|
||
if (p2 == p) {
|
||
continue;
|
||
}
|
||
if (!stopPart2.contains(p2)) {
|
||
stopPart2.add(p2);
|
||
}
|
||
}
|
||
if (next != p) {
|
||
getLoops(localData, p, loops, stopPart2, false, level + 1, visited);
|
||
}
|
||
}
|
||
if (next != null) {
|
||
getLoops(localData, next, loops, stopPart, false, level, visited);
|
||
}
|
||
} else if (part.nextParts.size() == 1) {
|
||
getLoops(localData, 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(localData, t, loops, stopPart, false, level, visited);
|
||
}
|
||
}
|
||
for (Loop l : loops2) {
|
||
l.breakCandidatesLocked--;
|
||
}
|
||
|
||
if (isLoop && currentLoop != null) {
|
||
GraphPart found;
|
||
Map<GraphPart, Integer> removed = new HashMap<>();
|
||
do {
|
||
found = null;
|
||
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
|
||
GraphPart ch = checkPart(null, localData, currentLoop.breakCandidates.get(i), null);
|
||
if (ch == null) {
|
||
currentLoop.breakCandidates.remove(i);
|
||
i--;
|
||
}
|
||
}
|
||
loopcand:
|
||
for (GraphPart cand : currentLoop.breakCandidates) {
|
||
for (GraphPart cand2 : currentLoop.breakCandidates) {
|
||
if (cand == cand2) {
|
||
continue;
|
||
}
|
||
if (cand.leadsTo(localData, this, code, cand2, loops, new ArrayList<>())) {
|
||
int lev1 = Integer.MAX_VALUE;
|
||
int lev2 = Integer.MAX_VALUE;
|
||
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
|
||
if (currentLoop.breakCandidates.get(i) == cand) {
|
||
if (currentLoop.breakCandidatesLevels.get(i) < lev1) {
|
||
lev1 = currentLoop.breakCandidatesLevels.get(i);
|
||
}
|
||
}
|
||
if (currentLoop.breakCandidates.get(i) == cand2) {
|
||
if (currentLoop.breakCandidatesLevels.get(i) < lev2) {
|
||
lev2 = currentLoop.breakCandidatesLevels.get(i);
|
||
}
|
||
}
|
||
}
|
||
//
|
||
if (lev1 <= lev2) {
|
||
found = cand2;
|
||
} else {
|
||
found = cand;
|
||
}
|
||
break loopcand;
|
||
}
|
||
}
|
||
}
|
||
if (found != null) {
|
||
int maxlevel = 0;
|
||
while (currentLoop.breakCandidates.contains(found)) {
|
||
int ind = currentLoop.breakCandidates.indexOf(found);
|
||
currentLoop.breakCandidates.remove(ind);
|
||
int lev = currentLoop.breakCandidatesLevels.remove(ind);
|
||
if (lev > maxlevel) {
|
||
maxlevel = lev;
|
||
}
|
||
}
|
||
if (removed.containsKey(found)) {
|
||
if (removed.get(found) > maxlevel) {
|
||
maxlevel = removed.get(found);
|
||
}
|
||
}
|
||
removed.put(found, maxlevel);
|
||
}
|
||
} while ((found != null) && (currentLoop.breakCandidates.size() > 1));
|
||
|
||
Map<GraphPart, Integer> count = new HashMap<>();
|
||
GraphPart winner = null;
|
||
int winnerCount = 0;
|
||
for (GraphPart cand : currentLoop.breakCandidates) {
|
||
|
||
if (!count.containsKey(cand)) {
|
||
count.put(cand, 0);
|
||
}
|
||
count.put(cand, count.get(cand) + 1);
|
||
boolean otherBreakCandidate = false;
|
||
for (Loop el : loops) {
|
||
if (el == currentLoop) {
|
||
continue;
|
||
}
|
||
if (el.breakCandidates.contains(cand)) {
|
||
otherBreakCandidate = true;
|
||
break;
|
||
}
|
||
}
|
||
if (otherBreakCandidate) {
|
||
} else if (count.get(cand) > winnerCount) {
|
||
winnerCount = count.get(cand);
|
||
winner = cand;
|
||
} else if (count.get(cand) == winnerCount && winner != null) {
|
||
if (cand.path.length() < winner.path.length()) {
|
||
winner = cand;
|
||
}
|
||
}
|
||
}
|
||
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
|
||
GraphPart cand = currentLoop.breakCandidates.get(i);
|
||
if (cand != winner) {
|
||
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;
|
||
currentLoop.phase = 2;
|
||
boolean start = false;
|
||
for (int l = 0; l < loops.size(); l++) {
|
||
Loop el = loops.get(l);
|
||
if (start) {
|
||
el.phase = 1;
|
||
}
|
||
if (el == currentLoop) {
|
||
start = true;
|
||
}
|
||
}
|
||
List<GraphPart> removedVisited = new ArrayList<>();
|
||
for (GraphPart r : removed.keySet()) {
|
||
if (removedVisited.contains(r)) {
|
||
continue;
|
||
}
|
||
getLoops(localData, r, loops, stopPart, false, removed.get(r), visited);
|
||
removedVisited.add(r);
|
||
}
|
||
start = false;
|
||
for (int l = 0; l < loops.size(); l++) {
|
||
Loop el = loops.get(l);
|
||
if (el == currentLoop) {
|
||
start = true;
|
||
}
|
||
if (start) {
|
||
el.phase = 2;
|
||
}
|
||
}
|
||
getLoops(localData, currentLoop.loopBreak, loops, stopPart, false, level, visited);
|
||
}
|
||
}
|
||
|
||
protected List<GraphTargetItem> printGraph(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
|
||
if (Thread.currentThread().isInterrupted()) {
|
||
throw new InterruptedException();
|
||
}
|
||
if (stopPart == null) {
|
||
stopPart = new ArrayList<>();
|
||
}
|
||
if (recursionLevel > allParts.size() + 1) {
|
||
throw new TranslateException("printGraph max recursion level reached.");
|
||
}
|
||
|
||
if (ret == null) {
|
||
ret = new ArrayList<>();
|
||
}
|
||
//try {
|
||
|
||
if (debugPrintGraph) {
|
||
System.err.println("PART " + part + " nextsize:" + part.nextParts.size());
|
||
}
|
||
|
||
/*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;
|
||
}
|
||
GraphTargetItem lop = checkLoop(part.nextParts.get(0), stopPart, loops);
|
||
if (lop == null) {
|
||
part = part.nextParts.get(0);
|
||
} else {
|
||
break;
|
||
}
|
||
}*/
|
||
if (part == null) {
|
||
return ret;
|
||
}
|
||
part = checkPart(stack, localData, part, allParts);
|
||
if (part == null) {
|
||
return ret;
|
||
}
|
||
|
||
if (part.ignored) {
|
||
return ret;
|
||
}
|
||
|
||
//List<GraphPart> loopContinues = getLoopsContinues(loops);
|
||
boolean isLoop = false;
|
||
Loop currentLoop = null;
|
||
for (Loop el : loops) {
|
||
if ((el.loopContinue == part) && (el.phase == 0)) {
|
||
currentLoop = el;
|
||
currentLoop.phase = 1;
|
||
isLoop = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (debugPrintGraph) {
|
||
System.err.println("loopsize:" + loops.size());
|
||
}
|
||
for (int l = loops.size() - 1; l >= 0; l--) {
|
||
Loop el = loops.get(l);
|
||
if (el == currentLoop) {
|
||
if (debugPrintGraph) {
|
||
System.err.println("ignoring current loop " + el);
|
||
}
|
||
continue;
|
||
}
|
||
if (el.phase != 1) {
|
||
if (debugPrintGraph) {
|
||
System.err.println("ignoring loop " + el);
|
||
}
|
||
continue;
|
||
}
|
||
if (el.loopBreak == part) {
|
||
if (currentLoop != null) {
|
||
currentLoop.phase = 0;
|
||
}
|
||
if (debugPrintGraph) {
|
||
System.err.println("Adding break");
|
||
}
|
||
ret.add(new BreakItem(null, localData.lineStartInstruction, el.id));
|
||
return ret;
|
||
}
|
||
if (el.loopPreContinue == part) {
|
||
if (currentLoop != null) {
|
||
currentLoop.phase = 0;
|
||
}
|
||
if (debugPrintGraph) {
|
||
System.err.println("Adding precontinue");
|
||
}
|
||
ret.add(new ContinueItem(null, localData.lineStartInstruction, el.id));
|
||
return ret;
|
||
}
|
||
if (el.loopContinue == part) {
|
||
if (currentLoop != null) {
|
||
currentLoop.phase = 0;
|
||
}
|
||
if (debugPrintGraph) {
|
||
System.err.println("Adding continue");
|
||
}
|
||
ret.add(new ContinueItem(null, localData.lineStartInstruction, el.id));
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
if (debugPrintGraph) {
|
||
System.err.println("stopParts: " + pathToString(stopPart));
|
||
}
|
||
|
||
if (stopPart.contains(part)) {
|
||
if (currentLoop != null) {
|
||
currentLoop.phase = 0;
|
||
}
|
||
if (debugPrintGraph) {
|
||
System.err.println("Stopped on part " + part);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
if (code.size() <= part.start) {
|
||
ret.add(new ScriptEndItem());
|
||
return ret;
|
||
}
|
||
|
||
GraphPartEdge edge = new GraphPartEdge(parent, part);
|
||
if (gotoTargets.contains(edge)) {
|
||
if (debugPrintGraph) {
|
||
//System.err.println("Already visited part " + part + ", adding goto");
|
||
}
|
||
String labelName = "addr" + part.start;
|
||
GotoItem gi = new GotoItem(null, localData.lineStartInstruction, labelName);
|
||
boolean targetCommandsFound = false;
|
||
for (int r = foundGotos.size() - 1; r >= 0; r--) {
|
||
GotoItem gi2 = foundGotos.get(r);
|
||
if (labelName.equals(gi2.labelName)) {
|
||
gi.targetCommands = gi2.targetCommands;
|
||
gi2.targetCommands = null;
|
||
targetCommandsFound = true;
|
||
break;
|
||
}
|
||
}
|
||
makeAllCommands(ret, stack);
|
||
if (!targetCommandsFound) {
|
||
List<GraphPartEdge> newGotoTargets = new ArrayList<>(gotoTargets);
|
||
removeEdgeToFromList(newGotoTargets, part);
|
||
gi.targetCommands = printGraph(foundGotos, newGotoTargets, partCodes, partCodePos, localData, stack, allParts, parent, part, stopPart, loops, staticOperation, path);
|
||
processIfs(gi.targetCommands);
|
||
if (!gi.targetCommands.isEmpty() && (gi.targetCommands.get(gi.targetCommands.size() - 1) instanceof ContinueItem)) {
|
||
ContinueItem cnt = (ContinueItem) gi.targetCommands.get(gi.targetCommands.size() - 1);
|
||
for (Loop l : loops) {
|
||
if (l.id == cnt.loopId && l.backEdges.size() == 1) {
|
||
gi.targetCommands.remove(cnt);
|
||
l.precontinueCommands = gi.targetCommands;
|
||
l.loopPreContinue = part;
|
||
removeEdgeToFromList(gotoTargets, part);
|
||
ret.add(cnt);
|
||
return ret;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
foundGotos.add(gi);
|
||
ret.add(gi);
|
||
|
||
return ret;
|
||
} else if (visited.contains(part)) {
|
||
String labelName = "addr" + part.start;
|
||
List<GraphTargetItem> firstCode = partCodes.get(part);
|
||
int firstCodePos = partCodePos.get(part);
|
||
if (firstCodePos > firstCode.size()) {
|
||
firstCodePos = firstCode.size();
|
||
}
|
||
if (firstCode.size() > firstCodePos && (firstCode.get(firstCodePos) instanceof LabelItem)) {
|
||
labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName;
|
||
} else {
|
||
firstCode.add(firstCodePos, new LabelItem(null, localData.lineStartInstruction, labelName));
|
||
}
|
||
ret.add(new GotoItem(null, localData.lineStartInstruction, labelName));
|
||
return ret;
|
||
} else {
|
||
visited.add(part);
|
||
partCodes.put(part, ret);
|
||
partCodePos.put(part, ret.size());
|
||
}
|
||
List<GraphTargetItem> currentRet = ret;
|
||
UniversalLoopItem loopItem = null;
|
||
TranslateStack sPreLoop = stack;
|
||
if (isLoop) {
|
||
//makeAllCommands(currentRet, stack);
|
||
stack = (TranslateStack) stack.clone();
|
||
|
||
//hack for as1/2 for..in to get enumeration through
|
||
GraphTargetItem topBsr = !stack.isEmpty() && (stack.peek() instanceof BranchStackResistant) ? stack.peek() : null;
|
||
stack.clear();
|
||
if (topBsr != null) {
|
||
stack.push(topBsr);
|
||
}
|
||
loopItem = new UniversalLoopItem(null, localData.lineStartInstruction, currentLoop, new ArrayList<>());
|
||
//loopItem.commands=printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops);
|
||
currentRet.add(loopItem);
|
||
currentRet = loopItem.commands;
|
||
//return ret;
|
||
}
|
||
|
||
boolean parseNext = true;
|
||
|
||
//****************************DECOMPILING PART*************
|
||
List<GraphTargetItem> output = new ArrayList<>();
|
||
|
||
List<GraphPart> parts = new ArrayList<>();
|
||
if (part instanceof GraphPartMulti) {
|
||
parts = ((GraphPartMulti) part).parts;
|
||
} else {
|
||
parts.add(part);
|
||
}
|
||
for (GraphPart p : parts) {
|
||
int end = p.end;
|
||
int start = p.start;
|
||
|
||
output.addAll(code.translatePart(p, localData, stack, start, end, staticOperation, path));
|
||
if ((end >= code.size() - 1) && p.nextParts.isEmpty()) {
|
||
output.add(new ScriptEndItem());
|
||
}
|
||
}
|
||
|
||
if (parseNext) {
|
||
List<GraphTargetItem> retCheck = check(foundGotos, gotoTargets, partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path);
|
||
if (retCheck != null) {
|
||
if (!retCheck.isEmpty()) {
|
||
currentRet.addAll(retCheck);
|
||
}
|
||
parseNext = false;
|
||
//return ret;
|
||
} else {
|
||
currentRet.addAll(output);
|
||
}
|
||
}
|
||
//********************************END PART DECOMPILING
|
||
if (parseNext) {
|
||
|
||
if (part.nextParts.size() > 2) {
|
||
GraphPart next = getMostCommonPart(localData, part.nextParts, loops, new ArrayList<>());
|
||
List<GraphPart> vis = new ArrayList<>();
|
||
GraphTargetItem switchedItem = stack.pop();
|
||
makeAllCommands(currentRet, stack);
|
||
|
||
List<GraphTargetItem> caseValues = new ArrayList<>();
|
||
List<List<GraphTargetItem>> caseCommands = new ArrayList<>();
|
||
List<Integer> valueMappings = new ArrayList<>();
|
||
Loop swLoop = new Loop(loops.size(), null, next);
|
||
gotoTargets.remove(next);
|
||
swLoop.phase = 1;
|
||
loops.add(swLoop);
|
||
boolean first = false;
|
||
int pos;
|
||
|
||
Map<Integer, GraphTargetItem> caseExpressions = new HashMap<>();
|
||
Map<Integer, GraphTargetItem> caseExpressionLeftSides = new HashMap<>();
|
||
Map<Integer, GraphTargetItem> caseExpressionRightSides = new HashMap<>();
|
||
GraphTargetItem it = switchedItem;
|
||
int defaultBranch = 0;
|
||
boolean hasExpr = false;
|
||
|
||
while (it instanceof TernarOpItem) {
|
||
TernarOpItem to = (TernarOpItem) it;
|
||
if (to.expression instanceof EqualsTypeItem) {
|
||
if (to.onTrue instanceof IntegerValueTypeItem) {
|
||
int cpos = ((IntegerValueTypeItem) to.onTrue).intValue();
|
||
caseExpressionLeftSides.put(cpos, ((EqualsTypeItem) to.expression).getLeftSide());
|
||
caseExpressionRightSides.put(cpos, ((EqualsTypeItem) to.expression).getRightSide());
|
||
it = to.onFalse;
|
||
} else {
|
||
break;
|
||
}
|
||
} else if (to.expression instanceof FalseItem) {
|
||
it = to.onFalse;
|
||
} else if (to.expression instanceof TrueItem) {
|
||
it = to.onTrue;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
//int ignoredBranch = -1;
|
||
if (it instanceof IntegerValueTypeItem) {
|
||
defaultBranch = ((IntegerValueTypeItem) it).intValue();
|
||
}
|
||
|
||
if (!caseExpressionRightSides.isEmpty()) {
|
||
GraphTargetItem firstItem;
|
||
firstItem = (GraphTargetItem) caseExpressionRightSides.values().toArray()[0];
|
||
boolean sameRight = true;
|
||
for (GraphTargetItem cit : caseExpressionRightSides.values()) {
|
||
if (!cit.equals(firstItem)) {
|
||
sameRight = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (sameRight) {
|
||
caseExpressions = caseExpressionLeftSides;
|
||
switchedItem = firstItem;
|
||
hasExpr = true;
|
||
} else {
|
||
firstItem = (GraphTargetItem) caseExpressionLeftSides.values().toArray()[0];
|
||
|
||
boolean sameLeft = true;
|
||
for (GraphTargetItem cit : caseExpressionLeftSides.values()) {
|
||
if (!cit.equals(firstItem)) {
|
||
sameLeft = false;
|
||
break;
|
||
}
|
||
}
|
||
if (sameLeft) {
|
||
caseExpressions = caseExpressionRightSides;
|
||
switchedItem = firstItem;
|
||
hasExpr = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
first = true;
|
||
pos = 0;
|
||
//This is tied to AS3 switch implementation which has nextparts switched from index 1. TODO: Make more universal
|
||
|
||
GraphPart defaultPart = hasExpr ? part.nextParts.get(1 + defaultBranch) : part.nextParts.get(0);
|
||
//int defaultNum = hasExpr ? 1 + defaultBranch : 0;
|
||
|
||
for (int i = 1; i < part.nextParts.size(); i++) {
|
||
if (caseExpressions.containsKey(pos)) {
|
||
caseValues.add(caseExpressions.get(pos));
|
||
} else if (part.nextParts.get(i) == defaultPart) {
|
||
caseValues.add(new DefaultItem());
|
||
} else {
|
||
caseValues.add(new IntegerValueItem(null, localData.lineStartInstruction, pos));
|
||
}
|
||
pos++;
|
||
}
|
||
|
||
first = true;
|
||
pos = 0;
|
||
List<GraphTargetItem> nextCommands = new ArrayList<>();
|
||
for (int i = 1; i < part.nextParts.size(); i++) {
|
||
gotoTargets.remove(part.nextParts.get(i));
|
||
}
|
||
for (int i = 1; i < part.nextParts.size(); i++) {
|
||
GraphPart p = part.nextParts.get(i);
|
||
|
||
/*if (pos == ignoredBranch) {
|
||
pos++;
|
||
continue;
|
||
}*/
|
||
//if (p != defaultPart)
|
||
{
|
||
if (vis.contains(p)) {
|
||
valueMappings.add(caseCommands.size() - 1);
|
||
continue;
|
||
}
|
||
valueMappings.add(caseCommands.size());
|
||
}
|
||
List<GraphPart> stopPart2 = new ArrayList<>();
|
||
if (next != null) {
|
||
stopPart2.add(next);
|
||
} else if (!stopPart.isEmpty()) {
|
||
stopPart2.add(stopPart.get(stopPart.size() - 1));
|
||
}
|
||
for (GraphPart p2 : part.nextParts) {
|
||
if (p2 == p) {
|
||
continue;
|
||
}
|
||
if (!stopPart2.contains(p2)) {
|
||
stopPart2.add(p2);
|
||
}
|
||
}
|
||
if (next != p) {
|
||
//if (p == defaultPart && !defaultCommands.isEmpty()) {
|
||
//ignore
|
||
//} else
|
||
{
|
||
TranslateStack s2 = (TranslateStack) stack.clone();
|
||
s2.clear();
|
||
nextCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
|
||
makeAllCommands(nextCommands, s2);
|
||
caseCommands.add(nextCommands);
|
||
vis.add(p);
|
||
}
|
||
} else {
|
||
caseCommands.add(nextCommands);
|
||
}
|
||
first = false;
|
||
pos++;
|
||
}
|
||
|
||
//If the lastone is default empty and alone, remove it
|
||
if (!caseCommands.isEmpty()) {
|
||
List<GraphTargetItem> lastc = caseCommands.get(caseCommands.size() - 1);
|
||
if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1);
|
||
if (bi.loopId == swLoop.id) {
|
||
lastc.remove(lastc.size() - 1);
|
||
}
|
||
}
|
||
if (lastc.isEmpty()) {
|
||
int cnt = 0;
|
||
if (caseValues.get(caseValues.size() - 1) instanceof DefaultItem) {
|
||
for (int i = valueMappings.size() - 1; i >= 0; i--) {
|
||
if (valueMappings.get(i) == caseCommands.size() - 1) {
|
||
cnt++;
|
||
}
|
||
}
|
||
if (cnt == 1) {
|
||
caseValues.remove(caseValues.size() - 1);
|
||
valueMappings.remove(valueMappings.size() - 1);
|
||
caseCommands.remove(lastc);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//remove last break from last section
|
||
if (!caseCommands.isEmpty()) {
|
||
List<GraphTargetItem> lastc = caseCommands.get(caseCommands.size() - 1);
|
||
if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1);
|
||
if (bi.loopId == swLoop.id) {
|
||
lastc.remove(lastc.size() - 1);
|
||
}
|
||
}
|
||
}
|
||
SwitchItem sw = new SwitchItem(null, localData.lineStartInstruction, swLoop, switchedItem, caseValues, caseCommands, valueMappings);
|
||
currentRet.add(sw);
|
||
swLoop.phase = 2;
|
||
if (next != null) {
|
||
currentRet.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
|
||
}
|
||
pos++;
|
||
} //else
|
||
GraphPart nextOnePart = null;
|
||
if (part.nextParts.size() == 2) {
|
||
GraphTargetItem expr = stack.pop();
|
||
/*if (expr instanceof LogicalOpItem) {
|
||
expr = ((LogicalOpItem) expr).invert();
|
||
} else {
|
||
expr = new NotItem(null, expr);
|
||
}*/
|
||
if (nextOnePart == null) {
|
||
|
||
List<GraphPart> nps;
|
||
nps = part.nextParts;
|
||
boolean isEmpty = nps.get(0) == nps.get(1);
|
||
|
||
GraphPart next = getCommonPart(localData, nps, loops, gotoTargets);
|
||
//System.err.println("on part " + part + ", next: " + next);
|
||
TranslateStack trueStack = (TranslateStack) stack.clone();
|
||
TranslateStack falseStack = (TranslateStack) stack.clone();
|
||
|
||
//hack for as1/2 for..in to get enumeration through
|
||
GraphTargetItem topBsr = !stack.isEmpty() && (stack.peek() instanceof BranchStackResistant) ? stack.peek() : null;
|
||
trueStack.clear();
|
||
falseStack.clear();
|
||
if (topBsr != null) {
|
||
trueStack.add(topBsr);
|
||
falseStack.add(topBsr);
|
||
}
|
||
if (isEmpty) {
|
||
next = nps.get(0);
|
||
}
|
||
boolean hasOntrue = nps.get(1) != next;
|
||
boolean hasOnFalse = nps.get(0) != next;
|
||
|
||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||
|
||
if ((!isEmpty) && (next != null)) {
|
||
stopPart2.add(next);
|
||
}
|
||
|
||
List<GraphTargetItem> onTrue = new ArrayList<>();
|
||
if (!isEmpty && hasOntrue) {
|
||
onTrue = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
|
||
}
|
||
List<GraphTargetItem> onFalse = new ArrayList<>();
|
||
|
||
if (!isEmpty && hasOnFalse) {
|
||
onFalse = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
|
||
}
|
||
//List<GraphTargetItem> out2 = new ArrayList<>();
|
||
//makeAllCommands(out2, stack);
|
||
makeAllCommands(onTrue, trueStack);
|
||
makeAllCommands(onFalse, falseStack);
|
||
|
||
List<GraphTargetItem> filteredOnTrue = filter(onTrue);
|
||
List<GraphTargetItem> filteredOnFalse = filter(onFalse);
|
||
|
||
if (!isEmpty(filteredOnTrue) && !isEmpty(filteredOnFalse) && filteredOnTrue.size() == 1 && filteredOnFalse.size() == 1 && (filteredOnTrue.get(0) instanceof PushItem) && (filteredOnFalse.get(0) instanceof PushItem)) {
|
||
stack.push(new TernarOpItem(null, localData.lineStartInstruction, expr.invert(null), ((PushItem) filteredOnTrue.get(0)).value, ((PushItem) filteredOnFalse.get(0)).value));
|
||
} else {
|
||
boolean isIf = true;
|
||
//If the ontrue is empty, switch ontrue and onfalse
|
||
if (filteredOnTrue.isEmpty() && !filteredOnFalse.isEmpty()) {
|
||
expr = expr.invert(null);
|
||
List<GraphTargetItem> tmp = onTrue;
|
||
onTrue = onFalse;
|
||
onFalse = tmp;
|
||
//tmp = filteredOnTrue;
|
||
filteredOnTrue = filteredOnFalse;
|
||
//filteredOnFalse = tmp;
|
||
}
|
||
if (!stack.isEmpty() && ((filteredOnTrue.size() == 1 && (filteredOnTrue.get(0) instanceof PopItem)) || ((filteredOnTrue.size() >= 2) && (filteredOnTrue.get(0) instanceof PopItem) && (filteredOnTrue.get(filteredOnTrue.size() - 1) instanceof PushItem)))) {
|
||
if (filteredOnTrue.size() > 1) {
|
||
GraphTargetItem rightSide = ((PushItem) filteredOnTrue.get(filteredOnTrue.size() - 1)).value;
|
||
GraphTargetItem prevExpr = stack.pop();
|
||
GraphTargetItem leftSide = expr.getNotCoercedNoDup();
|
||
|
||
if (leftSide instanceof DuplicateItem) {
|
||
isIf = false;
|
||
stack.push(new OrItem(null, localData.lineStartInstruction, prevExpr, rightSide));
|
||
} else if (leftSide.invert(null).getNotCoercedNoDup() instanceof DuplicateItem) {
|
||
isIf = false;
|
||
stack.push(new AndItem(null, localData.lineStartInstruction, prevExpr, rightSide));
|
||
} else if (prevExpr instanceof FalseItem) {
|
||
isIf = false;
|
||
leftSide = leftSide.invert(null);
|
||
stack.push(new AndItem(null, localData.lineStartInstruction, leftSide, rightSide));
|
||
} else if (prevExpr instanceof TrueItem) {
|
||
isIf = false;
|
||
stack.push(new OrItem(null, localData.lineStartInstruction, leftSide, rightSide));
|
||
} else {
|
||
stack.push(prevExpr); //push it back
|
||
//Still unstructured
|
||
}
|
||
} else {
|
||
isIf = false;
|
||
}
|
||
}
|
||
|
||
if (isIf) {
|
||
makeAllCommands(currentRet, stack);
|
||
IfItem b = new IfItem(null, localData.lineStartInstruction, expr.invert(null), onTrue, onFalse);
|
||
currentRet.add(b);
|
||
if (processSubBlk(b, null)) {
|
||
stack.push(new PopItem(null, localData.lineStartInstruction));
|
||
}
|
||
}
|
||
}
|
||
//currentRet.addAll(out2);
|
||
if (next != null) {
|
||
printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
|
||
//currentRet.addAll();
|
||
}
|
||
}
|
||
} //else
|
||
if (part.nextParts.size() == 1) {
|
||
nextOnePart = part.nextParts.get(0);
|
||
}
|
||
if (nextOnePart != null) {
|
||
printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
|
||
}
|
||
|
||
}
|
||
if (isLoop && loopItem != null && currentLoop != null) {
|
||
|
||
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(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1));
|
||
}
|
||
}
|
||
|
||
//Loop with condition at the beginning (While)
|
||
if (!loopTypeFound && (!loopItem.commands.isEmpty())) {
|
||
if (loopItem.commands.get(0) instanceof IfItem) {
|
||
IfItem ifi = (IfItem) loopItem.commands.get(0);
|
||
|
||
List<GraphTargetItem> bodyBranch = null;
|
||
boolean inverted = false;
|
||
boolean breakpos2 = false;
|
||
BreakItem addBreakItem = null;
|
||
if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) ifi.onTrue.get(0);
|
||
if (bi.loopId == currentLoop.id) {
|
||
bodyBranch = ifi.onFalse;
|
||
inverted = true;
|
||
}
|
||
} else if ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) ifi.onFalse.get(0);
|
||
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 (ifi.onTrue.isEmpty()) {
|
||
inverted = true;
|
||
}
|
||
bodyBranch = inverted ? ifi.onFalse : ifi.onTrue;
|
||
breakpos2 = true;
|
||
if (bi.loopId != currentLoop.id) { //it's break of another parent loop
|
||
addBreakItem = bi; //we must add it after the loop
|
||
}
|
||
}
|
||
if (bodyBranch != null) {
|
||
int index = ret.indexOf(loopItem);
|
||
ret.remove(index);
|
||
List<GraphTargetItem> exprList = new ArrayList<>();
|
||
GraphTargetItem expr = ifi.expression;
|
||
if (inverted) {
|
||
if (expr instanceof LogicalOpItem) {
|
||
expr = ((LogicalOpItem) expr).invert(null);
|
||
} else {
|
||
expr = new NotItem(null, expr.getLineStartItem(), expr);
|
||
}
|
||
}
|
||
exprList.add(expr);
|
||
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<>();
|
||
|
||
//findGotoTargets - comment this out:
|
||
/*if (currentLoop.loopPreContinue != null) {
|
||
GraphPart backup = currentLoop.loopPreContinue;
|
||
currentLoop.loopPreContinue = null;
|
||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||
stopPart2.add(currentLoop.loopContinue);
|
||
finalComm = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
|
||
currentLoop.loopPreContinue = backup;
|
||
checkContinueAtTheEnd(finalComm, currentLoop);
|
||
}*/
|
||
if (currentLoop.precontinueCommands != null) {
|
||
finalComm.addAll(currentLoop.precontinueCommands);
|
||
}
|
||
if (!finalComm.isEmpty()) {
|
||
ret.add(index, li = new ForItem(expr.getSrc(), expr.getLineStartItem(), currentLoop, new ArrayList<>(), exprList.get(exprList.size() - 1), finalComm, commands));
|
||
} else {
|
||
ret.add(index, li = new WhileItem(expr.getSrc(), expr.getLineStartItem(), currentLoop, exprList, commands));
|
||
}
|
||
if (addBreakItem != null) {
|
||
ret.add(index + 1, addBreakItem);
|
||
}
|
||
|
||
loopTypeFound = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
//Loop with condition at the end (Do..While)
|
||
if (!loopTypeFound && (!loopItem.commands.isEmpty())) {
|
||
if (loopItem.commands.get(loopItem.commands.size() - 1) instanceof IfItem) {
|
||
IfItem ifi = (IfItem) loopItem.commands.get(loopItem.commands.size() - 1);
|
||
List<GraphTargetItem> bodyBranch = null;
|
||
boolean inverted = false;
|
||
if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) ifi.onTrue.get(0);
|
||
if (bi.loopId == currentLoop.id) {
|
||
bodyBranch = ifi.onFalse;
|
||
inverted = true;
|
||
}
|
||
} else if ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem)) {
|
||
BreakItem bi = (BreakItem) ifi.onFalse.get(0);
|
||
if (bi.loopId == currentLoop.id) {
|
||
bodyBranch = ifi.onTrue;
|
||
}
|
||
}
|
||
if (bodyBranch != null) {
|
||
//Condition at the beginning
|
||
int index = ret.indexOf(loopItem);
|
||
ret.remove(index);
|
||
List<GraphTargetItem> exprList = new ArrayList<>();
|
||
GraphTargetItem expr = ifi.expression;
|
||
if (inverted) {
|
||
expr = expr.invert(null);
|
||
}
|
||
|
||
checkContinueAtTheEnd(bodyBranch, currentLoop);
|
||
|
||
List<GraphTargetItem> commands = new ArrayList<>();
|
||
|
||
if (!bodyBranch.isEmpty()) {
|
||
ret.add(index, loopItem);
|
||
} else {
|
||
loopItem.commands.remove(loopItem.commands.size() - 1);
|
||
commands.addAll(loopItem.commands);
|
||
commands.addAll(bodyBranch);
|
||
exprList.add(expr);
|
||
checkContinueAtTheEnd(commands, currentLoop);
|
||
ret.add(index, li = new DoWhileItem(null, exprList.get(0).getLineStartItem(), currentLoop, commands, exprList));
|
||
}
|
||
|
||
loopTypeFound = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!loopTypeFound) {
|
||
if (currentLoop.loopPreContinue != null) {
|
||
loopTypeFound = true;
|
||
GraphPart backup = currentLoop.loopPreContinue;
|
||
currentLoop.loopPreContinue = null;
|
||
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
|
||
stopPart2.add(currentLoop.loopContinue);
|
||
List<GraphTargetItem> finalComm = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
|
||
currentLoop.loopPreContinue = backup;
|
||
checkContinueAtTheEnd(finalComm, currentLoop);
|
||
|
||
if (!finalComm.isEmpty()) {
|
||
if (finalComm.get(finalComm.size() - 1) instanceof IfItem) {
|
||
IfItem ifi = (IfItem) finalComm.get(finalComm.size() - 1);
|
||
boolean ok = false;
|
||
boolean invert = false;
|
||
if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem) && (((BreakItem) ifi.onTrue.get(0)).loopId == currentLoop.id))
|
||
&& ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) {
|
||
ok = true;
|
||
invert = true;
|
||
}
|
||
if (((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof ContinueItem) && (((ContinueItem) ifi.onTrue.get(0)).loopId == currentLoop.id))
|
||
&& ((ifi.onFalse.size() == 1) && (ifi.onFalse.get(0) instanceof BreakItem) && (((BreakItem) ifi.onFalse.get(0)).loopId == currentLoop.id))) {
|
||
ok = true;
|
||
}
|
||
if (ok) {
|
||
finalComm.remove(finalComm.size() - 1);
|
||
int index = ret.indexOf(loopItem);
|
||
ret.remove(index);
|
||
List<GraphTargetItem> exprList = new ArrayList<>(finalComm);
|
||
GraphTargetItem expr = ifi.expression;
|
||
if (invert) {
|
||
expr = expr.invert(null);
|
||
}
|
||
exprList.add(expr);
|
||
ret.add(index, li = new DoWhileItem(null, expr.getLineStartItem(), currentLoop, loopItem.commands, exprList));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!loopTypeFound) {
|
||
checkContinueAtTheEnd(loopItem.commands, currentLoop);
|
||
}
|
||
currentLoop.phase = 2;
|
||
|
||
GraphTargetItem replaced = checkLoop(li, localData, loops);
|
||
if (replaced != li) {
|
||
int index = ret.indexOf(li);
|
||
ret.remove(index);
|
||
if (replaced != null) {
|
||
ret.add(index, replaced);
|
||
}
|
||
}
|
||
|
||
if (currentLoop.loopBreak != null) {
|
||
ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
protected void checkGraph(List<GraphPart> allBlocks) {
|
||
}
|
||
|
||
public List<GraphPart> makeGraph(GraphSource code, List<GraphPart> allBlocks, List<GraphException> exceptions) throws InterruptedException {
|
||
List<Integer> alternateEntries = new ArrayList<>();
|
||
for (GraphException ex : exceptions) {
|
||
alternateEntries.add(ex.start);
|
||
alternateEntries.add(ex.end);
|
||
alternateEntries.add(ex.target);
|
||
}
|
||
HashMap<Integer, List<Integer>> refs = code.visitCode(alternateEntries);
|
||
List<GraphPart> ret = new ArrayList<>();
|
||
boolean[] visited = new boolean[code.size()];
|
||
ret.add(makeGraph(null, new GraphPath(), code, 0, 0, allBlocks, refs, visited));
|
||
for (int pos : alternateEntries) {
|
||
GraphPart e1 = new GraphPart(-1, -1);
|
||
e1.path = new GraphPath("e");
|
||
ret.add(makeGraph(e1, new GraphPath("e"), code, pos, pos, allBlocks, refs, visited));
|
||
}
|
||
checkGraph(allBlocks);
|
||
return ret;
|
||
}
|
||
|
||
protected int checkIp(int ip) {
|
||
return ip;
|
||
}
|
||
|
||
private GraphPart makeGraph(GraphPart parent, GraphPath path, GraphSource code, int startip, int lastIp, List<GraphPart> allBlocks, HashMap<Integer, List<Integer>> refs, boolean[] visited2) throws InterruptedException {
|
||
if (Thread.currentThread().isInterrupted()) {
|
||
throw new InterruptedException();
|
||
}
|
||
|
||
int ip = startip;
|
||
for (GraphPart p : allBlocks) {
|
||
if (p.start == ip) {
|
||
p.refs.add(parent);
|
||
return p;
|
||
}
|
||
}
|
||
GraphPart g;
|
||
GraphPart ret = new GraphPart(ip, -1);
|
||
ret.path = path;
|
||
GraphPart part = ret;
|
||
while (ip < code.size()) {
|
||
ip = checkIp(ip);
|
||
if (ip >= code.size()) {
|
||
break;
|
||
}
|
||
if (visited2[ip] || ((ip != startip) && (refs.get(ip).size() > 1))) {
|
||
part.end = lastIp;
|
||
GraphPart found = null;
|
||
for (GraphPart p : allBlocks) {
|
||
if (p.start == ip) {
|
||
found = p;
|
||
break;
|
||
}
|
||
}
|
||
|
||
allBlocks.add(part);
|
||
|
||
if (found != null) {
|
||
part.nextParts.add(found);
|
||
found.refs.add(part);
|
||
break;
|
||
} else {
|
||
GraphPart gp = new GraphPart(ip, -1);
|
||
gp.path = path;
|
||
part.nextParts.add(gp);
|
||
gp.refs.add(part);
|
||
part = gp;
|
||
}
|
||
}
|
||
lastIp = ip;
|
||
GraphSourceItem ins = code.get(ip);
|
||
if (ins.isIgnored()) {
|
||
ip++;
|
||
continue;
|
||
}
|
||
if (ins instanceof GraphSourceItemContainer) {
|
||
GraphSourceItemContainer cnt = (GraphSourceItemContainer) ins;
|
||
if (ins instanceof Action) { //TODO: Remove dependency of AVM1
|
||
long endAddr = ((Action) ins).getAddress() + cnt.getHeaderSize();
|
||
for (long size : cnt.getContainerSizes()) {
|
||
endAddr += size;
|
||
}
|
||
ip = code.adr2pos(endAddr);
|
||
|
||
if ((ins instanceof ActionDefineFunction) || (ins instanceof ActionDefineFunction2)) {
|
||
part.end = lastIp;
|
||
allBlocks.add(part);
|
||
GraphPart gp = new GraphPart(ip, -1);
|
||
gp.path = path;
|
||
part.nextParts.add(gp);
|
||
gp.refs.add(part);
|
||
part = gp;
|
||
}
|
||
}
|
||
|
||
continue;
|
||
} else if (ins.isExit()) {
|
||
part.end = ip;
|
||
allBlocks.add(part);
|
||
break;
|
||
} else if (ins.isJump()) {
|
||
part.end = ip;
|
||
allBlocks.add(part);
|
||
ip = ins.getBranches(code).get(0);
|
||
part.nextParts.add(g = makeGraph(part, path, code, ip, lastIp, allBlocks, refs, visited2));
|
||
g.refs.add(part);
|
||
break;
|
||
} else if (ins.isBranch()) {
|
||
part.end = ip;
|
||
|
||
allBlocks.add(part);
|
||
List<Integer> branches = ins.getBranches(code);
|
||
for (int i = 0; i < branches.size(); i++) {
|
||
part.nextParts.add(g = makeGraph(part, path.sub(i, ip), code, branches.get(i), ip, allBlocks, refs, visited2));
|
||
g.refs.add(part);
|
||
}
|
||
break;
|
||
}
|
||
ip++;
|
||
}
|
||
if ((part.end == -1) && (ip >= code.size())) {
|
||
if (part.start == code.size()) {
|
||
part.end = code.size();
|
||
allBlocks.add(part);
|
||
} else {
|
||
part.end = ip - 1;
|
||
for (GraphPart p : allBlocks) {
|
||
if (p.start == ip) {
|
||
p.refs.add(part);
|
||
part.nextParts.add(p);
|
||
allBlocks.add(part);
|
||
return ret;
|
||
}
|
||
}
|
||
GraphPart gp = new GraphPart(ip, ip);
|
||
allBlocks.add(gp);
|
||
gp.refs.add(part);
|
||
part.nextParts.add(gp);
|
||
allBlocks.add(part);
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* String used to indent line when converting to string
|
||
*/
|
||
public static final String INDENTOPEN = "INDENTOPEN";
|
||
|
||
/**
|
||
* String used to unindent line when converting to string
|
||
*/
|
||
public static final String INDENTCLOSE = "INDENTCLOSE";
|
||
|
||
/**
|
||
* Converts list of TreeItems to string
|
||
*
|
||
* @param tree List of TreeItem
|
||
* @param writer
|
||
* @param localData
|
||
* @return String
|
||
* @throws java.lang.InterruptedException
|
||
*/
|
||
public static GraphTextWriter graphToString(List<GraphTargetItem> tree, GraphTextWriter writer, LocalData localData) throws InterruptedException {
|
||
for (GraphTargetItem ti : tree) {
|
||
if (!ti.isEmpty()) {
|
||
ti.toStringSemicoloned(writer, localData).newLine();
|
||
}
|
||
}
|
||
return writer;
|
||
}
|
||
|
||
public BaseLocalData prepareBranchLocalData(BaseLocalData 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) {
|
||
GraphPartMulti ret = new GraphPartMulti(parts);
|
||
ret.refs.addAll(parts.get(0).refs);
|
||
ret.nextParts.addAll(parts.get(parts.size() - 1).nextParts);
|
||
return ret;
|
||
} 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;
|
||
}
|
||
|
||
protected static void makeAllStack(List<GraphTargetItem> commands, TranslateStack stack) {
|
||
int pcnt = 0;
|
||
for (int i = commands.size() - 1; i >= 0; i--) {
|
||
if (commands.get(i) instanceof PushItem) {
|
||
pcnt++;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
for (int i = commands.size() - pcnt; i < commands.size(); i++) {
|
||
stack.push(commands.remove(i).value);
|
||
i--;
|
||
}
|
||
}
|
||
|
||
protected static void makeAllCommands(List<GraphTargetItem> commands, TranslateStack stack) {
|
||
int clen = commands.size();
|
||
if (clen > 0) {
|
||
if (commands.get(clen - 1) instanceof ScriptEndItem) {
|
||
clen--;
|
||
}
|
||
}
|
||
if (clen > 0) {
|
||
if (commands.get(clen - 1) instanceof ExitItem) {
|
||
clen--;
|
||
}
|
||
}
|
||
if (clen > 0) {
|
||
if (commands.get(clen - 1) instanceof BreakItem) {
|
||
clen--;
|
||
}
|
||
}
|
||
if (clen > 0) {
|
||
if (commands.get(clen - 1) instanceof ContinueItem) {
|
||
clen--;
|
||
}
|
||
}
|
||
while (stack.size() > 0) {
|
||
GraphTargetItem p = stack.pop();
|
||
if (p instanceof BranchStackResistant) {
|
||
continue;
|
||
}
|
||
if (!(p instanceof PopItem)) {
|
||
if (p instanceof FunctionActionItem) {
|
||
commands.add(clen, p);
|
||
} else {
|
||
commands.add(clen, new PushItem(p));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
protected void removeEdgeToFromList(List<GraphPartEdge> edges, GraphPart to) {
|
||
for (int i = edges.size() - 1; i >= 0; i--) {
|
||
if (edges.get(i).to.equals(to)) {
|
||
edges.remove(i);
|
||
}
|
||
}
|
||
}
|
||
}
|