better try..catch..finally detection

This commit is contained in:
Jindra Petřík
2021-01-31 09:13:36 +01:00
parent b2b9b51301
commit a1bb35ba1c
49 changed files with 1481 additions and 452 deletions

View File

@@ -0,0 +1,60 @@
digraph try_finally_asc2 {
label = "Try..Finally clause in ASC2";
node[shape=rect];
start->before;
before->finally_init->in_try;
try_f_begin->in_try;
try_c_begin->in_try;
in_try->finally;
try_c_end->finally;
in_catch->finally;
try_c_target->in_catch;
try_f_end->finally;
try_f_target->catch_f->finally:ne;
finally->lookupswitch;
lookupswitch->after;
lookupswitch->finally_throw[label="X"];
after->end;
finally_init[label="loc_N=0;"];
catch_f[label="loc_E = exception;\lloc_N = X;\l"];
finally_throw[label="throw loc_E;"];
try_c_target[shape=ellipse];
try_c_begin[shape=ellipse];
try_c_end[shape=ellipse];
try_f_target[shape=ellipse];
try_f_begin[shape=ellipse];
try_f_end[shape=ellipse];
start[shape=ellipse];
end[shape=ellipse];
lookupswitch[label="lookupswitch(loc_N)"]
in_try->in_try_ret[label=return];
in_try_ret[label="loc_R = returnedValue;\lloc_N = Y;\l"]
in_try_ret->finally;
lookupswitch->finally_return[label="Y"];
finally_return[label="return loc_R;"];
in_try->in_try_continue[label=continue];
in_try_continue[label="loc_N = Z;"]
in_try_continue->finally;
lookupswitch->finally_continue[label="Z"];
finally_continue[label="continue label;"];
/*
All ways go through finally clause. There is also lookupswitch with getlocal.
Local register is set before entering in_try block.
For every return/continue, there is local register set to specific value.
Lookupswitch then decides what will happen.
*/
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -0,0 +1,60 @@
digraph try_finally_flex {
label = "Try..Finally clause in Adobe Flex";
node[shape=rect];
start->before;
before->in_try;
try_f_begin->in_try;
try_c_begin->in_try;
in_try->pushbyteminusone;
try_c_end->pushbyteminusone;
in_catch->pushbyteminusone;
pushbyteminusone->finally;
try_c_target->in_catch;
try_f_end->finally;
try_f_target->catch_f->finally:ne;
finally->lookupswitch;
lookupswitch->after;
lookupswitch->finally_throw[label="X"];
after->end;
pushbyteminusone[label="pushbyte -1"];
catch_f[label="loc_E = exception;\lpushbyte X;\l"];
finally_throw[label="throw loc_E;"];
try_c_target[shape=ellipse];
try_c_begin[shape=ellipse];
try_c_end[shape=ellipse];
try_f_target[shape=ellipse];
try_f_begin[shape=ellipse];
try_f_end[shape=ellipse];
start[shape=ellipse];
end[shape=ellipse];
lookupswitch[label="lookupswitch(§§pop())"]
in_try->in_try_ret[label=return];
in_try_ret[label="loc_R = returnedValue;\lpushbyte Y;\l"]
in_try_ret->finally;
lookupswitch->finally_return[label="Y"];
finally_return[label="return loc_R;"];
in_try->in_try_continue[label=continue];
in_try_continue[label="pushbyte Z;"]
in_try_continue->finally;
lookupswitch->finally_continue[label="Z"];
finally_continue[label="continue label;"];
/*
All ways go through finally clause. There is also lookupswitch which uses value on stack..
Value -1 is pushed on stack after in_try and after catch bodys.
For every return/continue, there is also specific value pushed to stack.
Lookupswitch then decides what will happen.
*/
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -0,0 +1,44 @@
digraph try_finally_swftools {
label = "Try..Finally clause in swftools";
node[shape=rect];
start->before;
before->in_try;
try_f_begin->in_try;
try_c_begin->in_try;
in_try->finally;
try_c_end->finally;
in_catch->finally;
try_c_target->in_catch;
try_f_end->finally;
try_f_target->catch_f;
finally->after;
after->end;
catch_f[label="finally;\lthrow exception;\l"];
try_c_target[shape=ellipse];
try_c_begin[shape=ellipse];
try_c_end[shape=ellipse];
try_f_target[shape=ellipse];
try_f_begin[shape=ellipse];
try_f_end[shape=ellipse];
start[shape=ellipse];
end[shape=ellipse];
in_try->in_try_ret[label=return];
in_try_ret[label="§§push(returnedValue);\lfinally;\lreturn §§pop();\l"]
in_try->in_try_continue[label=continue];
in_try_continue[label="finally;\lcontinue label;\l"];
/*
Finally is inlined in every its usage.
In try_f_target there is finnally alone with throw - we can take it from there.
*/
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -12,18 +12,21 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.MethodInfo;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import java.util.ArrayList;
@@ -57,11 +60,17 @@ public class AVM2LocalData extends BaseLocalData {
public ArrayList<ABCException> parsedExceptions;
//public Map<Integer, List<Integer>> finallyJumps;
/**
* Mapped jumps from pushbyte xx part to apropriate lookupswitch branch
*/
public Map<GraphPart, GraphPart> finallyJumps = new HashMap<>();
//public Map<Integer, Integer> ignoredSwitches;
//exception index => switchPart
public Map<Integer, GraphPart> ignoredSwitches;
//public List<Integer> ignoredSwitches2;
public Integer scriptIndex;
@@ -77,6 +86,8 @@ public class AVM2LocalData extends BaseLocalData {
public Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new HashMap<>();
public CodeStats codeStats;
public AVM2LocalData() {
}
@@ -103,7 +114,7 @@ public class AVM2LocalData extends BaseLocalData {
parsedExceptions = localData.parsedExceptions;
finallyJumps = localData.finallyJumps;
ignoredSwitches = localData.ignoredSwitches;
ignoredSwitches = localData.ignoredSwitches;
//ignoredSwitches2 = localData.ignoredSwitches2;
scriptIndex = localData.scriptIndex;
localRegAssignmentIps = localData.localRegAssignmentIps;
ip = localData.ip;
@@ -111,6 +122,7 @@ public class AVM2LocalData extends BaseLocalData {
code = localData.code;
thisHasDefaultToPrimitive = localData.thisHasDefaultToPrimitive;
setLocalPosToGetLocalPos = localData.setLocalPosToGetLocalPos;
codeStats = localData.codeStats;
}
public AVM2ConstantPool getConstants() {

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.EndOfStreamException;
@@ -1493,21 +1494,30 @@ public class AVM2Code implements Cloneable {
}
}
public int getIpThroughJumpAndDebugLine(int ip) {
if (code.isEmpty()) {
return ip;
}
if (ip >= code.size()) {
return code.size() - 1;
}
}
while (code.get(ip).definition instanceof DebugLineIns) {
while (ip < code.size()) {
if (code.get(ip).definition instanceof DebugLineIns) {
ip++;
} else if (code.get(ip).definition instanceof JumpIns) {
ip = adr2pos(pos2adr(ip + 1) + code.get(ip).operands[0]);
} else {
break;
}
}
if (ip >= code.size()) {
return code.size() - 1;
}
return ip;
}
public long fixAddrAfterDebugLine(long addr) throws ConvertException {
public long getAddrThroughJumpAndDebugLine(long addr) throws ConvertException {
return pos2adr(getIpThroughJumpAndDebugLine(adr2pos(addr, true)));
}
public ConvertOutput toSourceOutput(Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference<GraphSourceItem> lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssigmentIps, HashMap<Integer, List<Integer>> refs) throws ConvertException, InterruptedException {
@@ -2373,7 +2383,7 @@ public class AVM2Code implements Cloneable {
}
}
private boolean walkCode(CodeStats stats, int pos, int stack, int scope, ABC abc, boolean autoFill) {
while (pos < code.size()) {
AVM2Instruction ins = code.get(pos);
if (stats.instructionStats[pos].seen) {
@@ -2383,7 +2393,9 @@ public class AVM2Code implements Cloneable {
if (ins.definition instanceof NewFunctionIns) {
MethodBody innerBody = abc.findBody(ins.operands[0]);
MethodBody innerBody = abc.findBody(ins.operands[0]);
if (autoFill) {
innerBody.autoFillStats(abc, stats.initscope + (stats.has_activation ? 1 : 0), false);
}
}
stats.instructionStats[pos].seen = true;
@@ -2445,7 +2457,7 @@ public class AVM2Code implements Cloneable {
} else if (ins.definition instanceof IfTypeIns) {
try {
int newpos = adr2pos(ins.getTargetAddress());
int newpos = adr2pos(ins.getTargetAddress());
walkCode(stats, newpos, stack, scope, abc, autoFill);
} catch (ConvertException ex) {
return false;
}
@@ -2457,7 +2469,7 @@ public class AVM2Code implements Cloneable {
}
try {
int newpos = adr2pos(pos2adr(pos) + ins.operands[i]);
int newpos = adr2pos(pos2adr(pos) + ins.operands[i]);
if (!walkCode(stats, newpos, stack, scope, abc, autoFill)) {
return false;
}
} catch (ConvertException ex) {
@@ -2470,10 +2482,10 @@ public class AVM2Code implements Cloneable {
return true;
}
public CodeStats getStats(ABC abc, MethodBody body, int initScope, boolean autoFill) {
CodeStats stats = new CodeStats(this);
stats.initscope = initScope;
stats.initscope = initScope;
if (!walkCode(stats, 0, 0, initScope, abc, autoFill)) {
return null;
}
int scopePos = -1;
@@ -2490,7 +2502,7 @@ public class AVM2Code implements Cloneable {
visited.add(i);
}
}
}
if (!walkCode(stats, adr2pos(ex.target), 1, scopePos, abc, autoFill)) {
return null;
}
int maxIp = 0;
@@ -2516,7 +2528,7 @@ public class AVM2Code implements Cloneable {
stats.instructionStats[i].seen = false;
}
// Rerun rest with new scopePos, stackPos
// Rerun rest with new scopePos, stackPos
if (!walkCode(stats, nextIp, origStackPos + 1/*magic!*/, scopePos - 1 /*magic!*/, abc, autoFill)) {
return null;
}
scopePos--;

View File

@@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIn
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecLocalPIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncLocalPIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
@@ -70,6 +71,8 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.BreakItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.ExitItem;
import com.jpexs.decompiler.graph.model.GotoItem;
import com.jpexs.decompiler.graph.model.IfItem;
@@ -138,56 +141,119 @@ public class AVM2Graph extends Graph {
}
@Override
protected void beforePrintGraph(BaseLocalData localData, String path, Set<GraphPart> allParts, List<Loop> loops) {
Map<Integer, Integer> ignoredSwitches = getIgnoredSwitches(allParts);
Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = calculateLocalRegsUsage(new HashSet<Integer>(ignoredSwitches.values()), path, allParts);
protected void beforePrintGraph(BaseLocalData localData, String path, Set<GraphPart> allParts, List<Loop> loops) throws InterruptedException {
AVM2LocalData avm2LocalData = ((AVM2LocalData) localData);
avm2LocalData.codeStats = avm2LocalData.code.getStats(avm2LocalData.abc, avm2LocalData.methodBody, avm2LocalData.methodBody.init_scope_depth, false);
getIgnoredSwitches((AVM2LocalData) localData, allParts);
Set<Integer> integerSwitchesIps = new HashSet<>();
for (GraphPart p : ((AVM2LocalData) localData).ignoredSwitches.values()) {
integerSwitchesIps.add(p.end);
}
Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = calculateLocalRegsUsage(integerSwitchesIps, path, allParts);
avm2LocalData.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos;
}
private Map<Integer, Integer> getIgnoredSwitches(Set<GraphPart> allParts) {
Map<Integer, Integer> ignoredSwitches = new HashMap<>();
int finStart;
private void getIgnoredSwitches(AVM2LocalData localData, Set<GraphPart> allParts) throws InterruptedException {
for (int e = 0; e < body.exceptions.length; e++) {
if (body.exceptions[e].isFinally()) {
{
{
AVM2Instruction jmpIns = avm2code.code.get(code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end)));
ABCException ex = body.exceptions[e];
if (!ex.isFinally()) {
continue;
}
if (jmpIns.definition instanceof JumpIns) {
finStart = code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]);
GraphPart fpart = null;
for (GraphPart p : allParts) {
if (p.start == finStart) {
fpart = p;
break;
}
}
int swPos = -1;
for (int f = finStart; f < avm2code.code.size(); f++) {
if (avm2code.code.get(f).definition instanceof LookupSwitchIns) {
AVM2Instruction swins = avm2code.code.get(f);
if (swins.operands.length >= 3) {
if (swins.operands[0] == swins.getBytesLength()) {
if (code.adr2pos(code.pos2adr(f) + swins.operands[2]) < finStart) {
swPos = f;
break;
}
}
}
}
}
ignoredSwitches.put(e, swPos);
break;
}
}
GraphPart finallyTryTargetPart = null;
int targetIp = code.adr2pos(ex.target);
for (GraphPart p : allParts) {
if (targetIp >= p.start && targetIp <= p.end) {
finallyTryTargetPart = p;
break;
}
}
GraphPart finallyPart = finallyTryTargetPart.nextParts.size() > 0 ? finallyTryTargetPart.nextParts.get(0) : null;
TranslateStack finallyTryTargetStack = (TranslateStack) new TranslateStack("try_target");
AVM2LocalData localData2 = new AVM2LocalData(localData);
localData2.scopeStack = new ScopeStack();
List<GraphTargetItem> targetOutput = translatePart(localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target");
final int FINALLY_KIND_STACK_BASED = 0;
final int FINALLY_KIND_REGISTER_BASED = 1;
final int FINALLY_KIND_INLINED = 2;
final int FINALLY_KIND_UNKNOWN = -1;
int switchedReg = -1;
int finallyKind = FINALLY_KIND_UNKNOWN;
if (finallyTryTargetStack.size() == 1) {
finallyKind = FINALLY_KIND_STACK_BASED;
} else if (targetOutput.size() >= 2
&& (targetOutput.get(targetOutput.size() - 1) instanceof SetLocalAVM2Item)
&& (targetOutput.get(targetOutput.size() - 2) instanceof SetLocalAVM2Item)) {
switchedReg = ((SetLocalAVM2Item) targetOutput.get(targetOutput.size() - 1)).regIndex;
finallyKind = FINALLY_KIND_REGISTER_BASED;
} else if (!targetOutput.isEmpty() && (targetOutput.get(targetOutput.size() - 1) instanceof ThrowAVM2Item)) {
//inlined to single part
//TODO: maybe replace all instances of exit nodes of try block
finallyKind = FINALLY_KIND_INLINED;
} else {
//probably inlined code in more parts, cannot do :-(
}
if (finallyKind == FINALLY_KIND_STACK_BASED) {
/*
Search for a lookupswitch which first pops from the stack
*/
List<Integer> foundIps = new ArrayList<>();
List<GraphPart> foundParts = new ArrayList<>();
int stackAfter = localData.codeStats.instructionStats[finallyTryTargetPart.end].stackpos_after;
//int stackAfter = localData.codeStats.instructionStats[finallyPart.start].stackpos;
findAllPops(localData, stackAfter, finallyPart, foundIps, foundParts, new HashSet<>());
int switchIp = -1;
GraphPart switchPart = null;
for (int i = 0; i < foundIps.size(); i++) {
int ip = foundIps.get(i);
if (avm2code.code.get(ip).definition instanceof LookupSwitchIns) {
switchIp = ip;
switchPart = foundParts.get(i);
}
}
if (switchIp > -1 && switchPart != null) {
for (GraphPart r : finallyPart.refs) {
for (int ip = r.end; ip >= r.start; ip--) {
AVM2Instruction ins = avm2code.code.get(ip);
if (ins.definition instanceof JumpIns) {
continue;
} else if (ins.definition instanceof PushByteIns) {
int val = ins.operands[0];
if (val < 0 || val > switchPart.nextParts.size() - 2) {
localData.finallyJumps.put(r, switchPart.nextParts.get(0)); //default branch
} else {
localData.finallyJumps.put(r, switchPart.nextParts.get(1 + val));
}
}
}
}
//return in finally block is joined after switch decision
for (GraphPart p : switchPart.nextParts) {
for (GraphPart r : p.refs) {
if (r != switchPart) {
localData.finallyJumps.put(r, p);
}
}
}
localData.ignoredSwitches.put(e, switchPart);
} else {
//there is probably return in all branches and no other way outside finally
}
}
}
return ignoredSwitches;
}
public Map<Integer, Set<Integer>> calculateLocalRegsUsage(Set<Integer> ignoredSwitches, String path, Set<GraphPart> allParts) {
@@ -345,315 +411,231 @@ public class AVM2Graph extends Graph {
for (GraphPart p : allBlocks) {
if (avm2code.pos2adr(p.start) >= ex.start && avm2code.pos2adr(p.end) <= ex.end && target != null) {
//Logger.getLogger(Graph.class.getName()).fine("ADDING throwpart " + target + " to " + p);
p.throwParts.add(target);
target.refs.add(p);
//p.throwParts.add(target);
//target.refs.add(p);
}
}
}
}
private void findNearestPartOutsideTry(AVM2LocalData localData, GraphPart part, int tryEndIp, Set<GraphPart> visited, Set<GraphPart> result) {
if (visited.contains(part)) {
return;
}
if (part.start >= tryEndIp || part.end >= tryEndIp) {
result.add(part);
return;
}
if (localData.finallyJumps.containsKey(part)) {
GraphPart afterSwitchPart = localData.finallyJumps.get(part);
GraphPart switchPart = null;
for (GraphPart r : afterSwitchPart.refs) {
if (localData.ignoredSwitches.containsValue(r)) {
switchPart = r;
}
}
if (switchPart != null) {
return;
}
}
for (GraphPart n : part.nextParts) {
findNearestPartOutsideTry(localData, n, tryEndIp, visited, result);
}
}
private Set<GraphPart> findNearestPartOutsideTry(AVM2LocalData localData, GraphPart start, int tryEndIp) {
Set<GraphPart> result = new HashSet<>();
findNearestPartOutsideTry(localData, start, tryEndIp, new HashSet<>(), result);
return result;
}
private void findAllPops(AVM2LocalData localData, int stackLevel, GraphPart part, List<Integer> foundIps, List<GraphPart> foundParts, Set<GraphPart> visited) {
if (visited.contains(part)) {
return;
}
visited.add(part);
for (int ip = part.start; ip <= part.end; ip++) {
if (localData.codeStats.instructionStats[ip].stackpos_after == stackLevel - 1) {
foundIps.add(ip);
foundParts.add(part);
return;
}
}
for (GraphPart n : part.nextParts) {
findAllPops(localData, stackLevel, n, foundIps, foundParts, visited);
}
}
private List<GraphTargetItem> checkTry(List<GraphTargetItem> output, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, AVM2LocalData localData, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, Set<GraphPart> allParts, TranslateStack stack, int staticOperation, String path) throws InterruptedException {
if (localData.parsedExceptions == null) {
localData.parsedExceptions = new ArrayList<>();
}
List<ABCException> parsedExceptions = localData.parsedExceptions;
if (localData.finallyJumps == null) {
localData.finallyJumps = new HashMap<>();
}
if (localData.ignoredSwitches == null) {
localData.ignoredSwitches = new HashMap<>();
}
long addr = avm2code.getAddrThroughJumpAndDebugLine(avm2code.pos2adr(part.start));
long maxEndAddr = -1;
List<ABCException> catchedExceptions = new ArrayList<>();
ABCException finallyException = null;
int endIp = -1;
int finallyIndex = -1;
for (int e = 0; e < body.exceptions.length; e++) {
if (addr == avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].start)) {
if (!parsedExceptions.contains(body.exceptions[e])) {
long endAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
if (endAddr > maxEndAddr) {
catchedExceptions.clear();
finallyException = null;
finallyIndex = -1;
maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
endIp = avm2code.adr2pos(maxEndAddr);
catchedExceptions.add(body.exceptions[e]);
} else if (endAddr == maxEndAddr) {
catchedExceptions.add(body.exceptions[e]);
}
if (body.exceptions[e].isFinally()) {
finallyException = body.exceptions[e];
finallyIndex = e;
}
}
}
}
if (catchedExceptions.size() > 0) {
parsedExceptions.addAll(catchedExceptions);
if (finallyException != null) {
catchedExceptions.remove(finallyException);
}
List<GraphTargetItem> tryCommands = new ArrayList<>();
List<List<GraphTargetItem>> catchCommands = new ArrayList<>();
List<GraphTargetItem> finallyCommands = new ArrayList<>();
GraphPart afterPart = null;
for (GraphPart p : allParts) {
if (endIp >= p.start && endIp <= p.end) {
afterPart = p;
break;
}
}
stack.clear(); //If the original code (before check()) had "if" in it, there would be something on stack
for (ABCException ex : catchedExceptions) {
TranslateStack st2 = (TranslateStack) stack.clone();
st2.clear();
st2.add(new ExceptionAVM2Item(ex));
GraphPart catchPart = null;
for (GraphPart p : allParts) {
if (p.start == avm2code.adr2pos(ex.target)) {
catchPart = p;
break;
}
}
AVM2LocalData localData2 = new AVM2LocalData(localData);
localData2.scopeStack = new ScopeStack();
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(afterPart);
List<GraphTargetItem> currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, catchPart, stopPart2, loops, staticOperation, path);
if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(0) instanceof SetLocalAVM2Item)) {
if (currentCatchCommands.get(0).value.getNotCoerced() instanceof ExceptionAVM2Item) {
currentCatchCommands.remove(0);
}
}
catchCommands.add(currentCatchCommands);
}
if (finallyException == null) {
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(afterPart);
tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, stopPart2, loops, staticOperation, path);
}
if (finallyException != null) {
afterPart = null;
GraphPart finallyTryTargetPart = null;
int targetPos = avm2code.adr2pos(finallyException.target);
for (GraphPart p : allParts) {
if (p.start == targetPos) {
finallyTryTargetPart = p;
break;
}
}
GraphPart finallyPart = finallyTryTargetPart.nextParts.isEmpty() ? null : finallyTryTargetPart.nextParts.get(0);
List<GraphPart> tryStopPart = new ArrayList<>(stopPart);
if (finallyPart != null) {
tryStopPart.add(finallyPart);
}
tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, tryStopPart, loops, staticOperation, path);
makeAllCommands(tryCommands, stack);
processIfs(tryCommands);
//there should be §§push(-1) left
if (!tryCommands.isEmpty()
&& (tryCommands.get(tryCommands.size() - 1) instanceof PushItem)
&& (tryCommands.get(tryCommands.size() - 1).value instanceof IntegerValueAVM2Item)) {
tryCommands.remove(tryCommands.size() - 1);
}
List<GraphPart> finallyStopPart = new ArrayList<>(stopPart);
GraphPart switchPart = localData.ignoredSwitches.containsKey(finallyIndex) ? localData.ignoredSwitches.get(finallyIndex) : null;
if (switchPart != null) {
finallyStopPart.add(switchPart);
}
if (finallyPart != null) {
finallyCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, finallyPart, finallyStopPart, loops, staticOperation, path);
}
if (switchPart != null) {
finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path));
afterPart = switchPart.nextParts.get(0); //take the default branch
}
stack.pop();
if (tryCommands.size() == 1
&& (tryCommands.get(0) instanceof TryAVM2Item)
&& catchCommands.isEmpty()
&& ((TryAVM2Item) tryCommands.get(0)).finallyCommands.isEmpty()) {
catchCommands = ((TryAVM2Item) tryCommands.get(0)).catchCommands;
catchedExceptions = ((TryAVM2Item) tryCommands.get(0)).catchExceptions;
tryCommands = ((TryAVM2Item) tryCommands.get(0)).tryCommands;
}
}
if (catchCommands.isEmpty() && finallyCommands.isEmpty() && tryCommands.isEmpty()) {
return null;
}
List<GraphTargetItem> ret = new ArrayList<>();
ret.add(new TryAVM2Item(tryCommands, catchedExceptions, catchCommands, finallyCommands, "TODO"));
if (afterPart != null) {
ret.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, afterPart, stopPart, loops, staticOperation, path));
}
return ret;
}
return null;
}
@Override
protected List<GraphTargetItem> check(List<GotoItem> foundGotos, 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 {
List<GraphTargetItem> ret = null;
AVM2LocalData aLocalData = (AVM2LocalData) localData;
if (aLocalData.parsedExceptions == null) {
aLocalData.parsedExceptions = new ArrayList<>();
}
List<ABCException> parsedExceptions = aLocalData.parsedExceptions;
if (aLocalData.finallyJumps == null) {
aLocalData.finallyJumps = new HashMap<>();
}
Map<Integer, List<Integer>> finallyJumps = aLocalData.finallyJumps;
if (aLocalData.ignoredSwitches == null) {
aLocalData.ignoredSwitches = new HashMap<>();
}
Map<Integer, Integer> ignoredSwitches = aLocalData.ignoredSwitches;
if (aLocalData.ignoredSwitches2 == null) {
aLocalData.ignoredSwitches2 = new ArrayList<>();
}
List<Integer> ignoredSwitches2 = aLocalData.ignoredSwitches2;
int ip = part.start;
long addr = avm2code.fixAddrAfterDebugLine(avm2code.pos2adr(part.start));
long maxend = -1;
List<Integer> catchedFinallys = new ArrayList<>();
List<ABCException> catchedExceptions = new ArrayList<>();
for (int e = 0; e < body.exceptions.length; e++) {
if (addr == avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
//Add finally only when the list is empty
if (!body.exceptions[e].isFinally() || catchedExceptions.isEmpty()) {
if (!parsedExceptions.contains(body.exceptions[e])) {
if (((body.exceptions[e].end) > maxend)) {
catchedExceptions.clear();
catchedFinallys.clear();
maxend = avm2code.fixAddrAfterDebugLine(body.exceptions[e].end);
catchedExceptions.add(body.exceptions[e]);
} else if (avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) == maxend) {
catchedExceptions.add(body.exceptions[e]);
}
catchedFinallys.add(e);
}
} else if (body.exceptions[e].isFinally()) {
parsedExceptions.add(body.exceptions[e]);
}
}
}
if (catchedExceptions.size() > 0) {
parsedExceptions.addAll(catchedExceptions);
int endpos = code.adr2pos(avm2code.fixAddrAfterDebugLine(catchedExceptions.get(0).end));
int endposStartBlock = code.adr2pos(catchedExceptions.get(0).end);
String finCatchName = "";
List<List<GraphTargetItem>> catchedCommands = new ArrayList<>();
if (avm2code.code.get(endpos).definition instanceof JumpIns) {
long afterCatchAddr = avm2code.pos2adr(endpos + 1) + avm2code.code.get(endpos).operands[0];
int afterCatchPos = avm2code.adr2pos(afterCatchAddr);
final AVM2Graph t = this;
Collections.sort(catchedExceptions, new Comparator<ABCException>() {
@Override
public int compare(ABCException o1, ABCException o2) {
return (int) (t.avm2code.fixAddrAfterDebugLine(o1.target) - t.avm2code.fixAddrAfterDebugLine(o2.target));
}
});
List<GraphTargetItem> finallyCommands = new ArrayList<>();
boolean hasFinally = false;
int returnPos = afterCatchPos;
int finStart;
for (int e = 0; e < body.exceptions.length; e++) {
if (body.exceptions[e].isFinally()) {
if (addr == avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
if (afterCatchPos + 1 == code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end))) {
catchedFinallys.add(e);
AVM2Instruction jmpIns = avm2code.code.get(code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end)));
if (jmpIns.definition instanceof JumpIns) {
finStart = code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]);
GraphPart fpart = null;
for (GraphPart p : allParts) {
if (p.start == finStart) {
fpart = p;
break;
}
}
TranslateStack st = (TranslateStack) stack.clone();
st.clear();
int swPos = -1;
for (int f = finStart; f < avm2code.code.size(); f++) {
if (avm2code.code.get(f).definition instanceof LookupSwitchIns) {
AVM2Instruction swins = avm2code.code.get(f);
if (swins.operands.length >= 3) {
if (swins.operands[0] == swins.getBytesLength()) {
if (code.adr2pos(code.pos2adr(f) + swins.operands[2]) < finStart) {
//st.push(new ExceptionAVM2Item(body.exceptions[e]));
GraphPart fepart = null;
for (GraphPart p : allParts) {
if (p.start == f + 1) {
fepart = p;
break;
}
}
//this.code.code.get(f).ignored = true;
//ignoredSwitches.add(f);
swPos = f;
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(fepart);
//finallyCommands = printGraph(new ArrayList<GraphPart>(), localData, stack, allParts, parent, fpart, stopPart2, loops, staticOperation, path);
returnPos = f + 1;
break;
}
}
}
}
}
//ignoredSwitches.add(-1);
//int igs_size=ignoredSwitches.size();
Map<Integer, List<Integer>> oldFinallyJumps = new HashMap<>(finallyJumps);
finallyJumps.clear();
ignoredSwitches.put(e, swPos);
st.push(new PopItem(null, aLocalData.lineStartInstruction));
finallyCommands = printGraph(foundGotos, partCodes, partCodePos, localData, st, allParts, parent, fpart, null, loops, staticOperation, path);
//ignoredSwitches.remove(igs_size-1);
finallyJumps.putAll(oldFinallyJumps);
if (!finallyJumps.containsKey(e)) {
finallyJumps.put(e, new ArrayList<>());
}
finallyJumps.get(e).add(finStart);
hasFinally = true;
break;
}
}
}
}
}
GraphPart retPart = null;
for (GraphPart p : allParts) {
if (p.start == returnPos) {
retPart = p;
break;
}
}
List<GraphPart> catchParts = new ArrayList<>();
for (int e = 0; e < catchedExceptions.size(); e++) {
int eendpos;
if (e < catchedExceptions.size() - 1) {
eendpos = code.adr2pos(avm2code.fixAddrAfterDebugLine(catchedExceptions.get(e + 1).target)) - 2;
} else {
eendpos = afterCatchPos - 1;
}
GraphPart npart = null;
int findpos = code.adr2pos(catchedExceptions.get(e).target);
for (GraphPart p : allParts) {
if (p.start == findpos) {
npart = p;
catchParts.add(p);
break;
}
}
GraphPart nepart = null;
for (GraphPart p : allParts) {
if (p.start == eendpos + 1) {
nepart = p;
break;
}
}
TranslateStack st2 = (TranslateStack) stack.clone();
st2.clear();
st2.add(new ExceptionAVM2Item(catchedExceptions.get(e)));
AVM2LocalData localData2 = new AVM2LocalData(aLocalData);
localData2.scopeStack = new ScopeStack(localData2.scriptIndex);
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(nepart);
if (retPart != null) {
stopPart2.add(retPart);
}
List<GraphTargetItem> ncatchedCommands = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path);
//hack for findGotos - FIXME
if (hasFinally && !ncatchedCommands.isEmpty()) {
for (int k = 0; k < ncatchedCommands.size(); k++) {
if (ncatchedCommands.get(k) instanceof GotoItem) {
GotoItem gi = (GotoItem) ncatchedCommands.get(k);
for (GotoItem g : foundGotos) {
if (gi.labelName.equals(g.labelName) && g.targetCommands != null) {
if (!g.targetCommands.isEmpty()) {
if (g.targetCommands.get(0) instanceof PushItem) {
if (g.targetCommands.get(0).value instanceof IntegerValueAVM2Item) {
if (((IntegerValueAVM2Item) g.targetCommands.get(0).value).value == -1) {
ncatchedCommands.remove(gi);
}
}
}
}
break;
}
}
}
}
}
if (catchedExceptions.get(e).isFinally() && (catchedExceptions.size() > 1 || hasFinally)) {
catchedExceptions.remove(e);
e--;
} else {
catchedCommands.add(ncatchedCommands);
if (retPart != null && avm2code.code.get(retPart.start).isExit() && !(!ncatchedCommands.isEmpty() && (ncatchedCommands.get(ncatchedCommands.size() - 1) instanceof ExitItem))) {
avm2code.code.get(retPart.start).translate(localData, st2, ncatchedCommands, staticOperation, path);
}
if (catchedExceptions.get(e).isFinally()) {
//endposStartBlock = -1;
if (!ncatchedCommands.isEmpty() && (ncatchedCommands.get(0) instanceof SetLocalAVM2Item)) {
SetLocalAVM2Item sl = (SetLocalAVM2Item) ncatchedCommands.get(0);
if (sl.value.getNotCoerced() instanceof ExceptionAVM2Item) {
finCatchName = AVM2Item.localRegName(new HashMap<>(), sl.regIndex);
}
}
} else {
//No kill ins
if (!ncatchedCommands.isEmpty() && (ncatchedCommands.get(0) instanceof SetLocalAVM2Item)) {
SetLocalAVM2Item sl = (SetLocalAVM2Item) ncatchedCommands.get(0);
if (sl.value.getThroughDuplicate().getNotCoerced() instanceof ExceptionAVM2Item) {
ncatchedCommands.remove(0);
}
}
}
}
}
GraphPart nepart = null;
for (GraphPart p : allParts) {
if (p.start == endposStartBlock) {
nepart = p;
break;
}
}
List<GraphPart> stopPart2 = new ArrayList<>();//stopPart);
if (nepart != null) {
stopPart2.add(nepart);
}
stopPart2.addAll(catchParts);
if (retPart != null) {
stopPart2.add(retPart);
}
TranslateStack st = (TranslateStack) stack.clone();
st.clear();
List<GraphTargetItem> tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path);
if (retPart != null && avm2code.code.get(retPart.start).isExit() && !(!tryCommands.isEmpty() && (tryCommands.get(tryCommands.size() - 1) instanceof ExitItem))) {
avm2code.code.get(retPart.start).translate(localData, st, tryCommands, staticOperation, path);
}
output.clear();
stack.clear();
makeAllCommands(tryCommands, st);
output.add(new TryAVM2Item(tryCommands, catchedExceptions, catchedCommands, finallyCommands, finCatchName));
for (int fin_e : catchedFinallys) {
if (finallyJumps.containsKey(fin_e)) {
finallyJumps.get(fin_e).clear();
}
//.remove((Integer) finStart);
}
ip = returnPos;
}
}
if (ip != part.start) {
part = null;
for (GraphPart p : allParts) {
List<GraphPart> ps = p.getSubParts();
for (GraphPart p2 : ps) {
if (p2.start == ip) {
part = p2;
break;
}
}
}
ret = new ArrayList<>();
ret.addAll(output);
GraphTargetItem lop = checkLoop(new ArrayList<GraphTargetItem>(), part, stopPart, loops);
if (lop == null) {
TranslateStack st = (TranslateStack) stack.clone();
st.clear();
ret.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, st, allParts, null, part, stopPart, loops, staticOperation, path));
} else {
ret.add(lop);
}
ret = checkTry(output, foundGotos, partCodes, partCodePos, aLocalData, part, stopPart, loops, allParts, stack, staticOperation, path);
if (ret != null) {
return ret;
}
if ((avm2code.code.get(part.end).definition instanceof LookupSwitchIns) && (ignoredSwitches.containsValue(part.end) || ignoredSwitches2.contains(part.end))) {
ret = new ArrayList<>();
ret.addAll(output);
return ret;
}
//Detect switch
if ((part.nextParts.size() == 2) && (!stack.isEmpty()) && (stack.peek() instanceof StrictEqAVM2Item)) {
GraphSourceItem switchStartItem = code.get(part.start);
@@ -737,7 +719,6 @@ public class AVM2Graph extends Graph {
defaultPart = defaultPart.nextParts.get(0);
}
ret = new ArrayList<>();
ret.addAll(output);
Reference<GraphPart> nextRef = new Reference<>(null);
@@ -758,13 +739,37 @@ public class AVM2Graph extends Graph {
return ret;
}
@Override
protected List<GraphPart> getNextParts(BaseLocalData localData, GraphPart part) {
AVM2LocalData aLocalData = (AVM2LocalData) localData;
/*if (aLocalData.finallyJumps.containsKey(part)) {
List<GraphPart> ret = new ArrayList<>();
ret.add(aLocalData.finallyJumps.get(part));
return ret;
}*/
return super.getNextParts(localData, part);
}
@Override
protected GraphPart checkPart(TranslateStack stack, BaseLocalData localData, GraphPart prev, GraphPart next, Set<GraphPart> allParts) {
AVM2LocalData aLocalData = (AVM2LocalData) localData;
if (aLocalData.finallyJumps == null) {
aLocalData.finallyJumps = new HashMap<>();
}
Map<Integer, List<Integer>> finallyJumps = aLocalData.finallyJumps;
if (aLocalData.ignoredSwitches == null) {
aLocalData.ignoredSwitches = new HashMap<>();
}
if (prev != null) {
if (aLocalData.ignoredSwitches.containsValue(prev)) {
return null;
}
if (aLocalData.finallyJumps.containsKey(prev)) {
return aLocalData.finallyJumps.get(prev);
}
}
/*Map<Integer, List<Integer>> finallyJumps = aLocalData.finallyJumps;
if (aLocalData.ignoredSwitches == null) {
aLocalData.ignoredSwitches = new HashMap<>();
}
@@ -786,7 +791,7 @@ public class AVM2Graph extends Graph {
nip = branches.get(1 + val);
}
for (GraphPart p : allParts) {
if (avm2code.fixIPAfterDebugLine(p.start) == avm2code.fixIPAfterDebugLine(nip)) {
if (avm2code.getIpThroughJumpAndDebugLine(p.start) == avm2code.getIpThroughJumpAndDebugLine(nip)) {
return p;
}
}
@@ -801,14 +806,14 @@ public class AVM2Graph extends Graph {
}
int pos = next.start;
long addr = avm2code.fixAddrAfterDebugLine(avm2code.pos2adr(pos));
long addr = avm2code.getAddrThroughJumpAndDebugLine(avm2code.pos2adr(pos));
for (int e = 0; e < body.exceptions.length; e++) {
if (body.exceptions[e].isFinally()) {
if (addr == avm2code.fixAddrAfterDebugLine(body.exceptions[e].start)) {
if (addr == avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].start)) {
if (true) { //afterCatchPos + 1 == code.adr2pos(this.code.fixAddrAfterDebugLine(body.exceptions[e].end))) {
AVM2Instruction jmpIns = avm2code.code.get(avm2code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end)));
AVM2Instruction jmpIns = avm2code.code.get(avm2code.adr2pos(avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end)));
if (jmpIns.definition instanceof JumpIns) {
int finStart = avm2code.adr2pos(avm2code.fixAddrAfterDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]);
int finStart = avm2code.adr2pos(avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end) + jmpIns.getBytesLength() + jmpIns.operands[0]);
if (!finallyJumps.containsKey(e)) {
finallyJumps.put(e, new ArrayList<>());
}
@@ -832,8 +837,7 @@ public class AVM2Graph extends Graph {
}
}
}
}
}*/
return next;
}
@@ -1050,6 +1054,7 @@ public class AVM2Graph extends Graph {
}
return false;
}
@Override
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
@@ -1061,13 +1066,6 @@ public class AVM2Graph extends Graph {
}
}
/*for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof WhileItem) {
WhileItem w = (WhileItem) list.get(i);
}
}*/
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof SetLocalAVM2Item) {
SetLocalAVM2Item ri = (SetLocalAVM2Item) list.get(i);
@@ -1105,30 +1103,42 @@ public class AVM2Graph extends Graph {
}
}
if (i + 2 < list.size()) {
if (isIntegerOrPopInteger(list.get(i + 1)) && (list.get(i + 2) instanceof ReturnValueAVM2Item)
&& (list.get(i + 2).value instanceof LocalRegAVM2Item)
&& (((LocalRegAVM2Item) list.get(i + 2).value).regIndex == ri.regIndex)) {
ReturnValueAVM2Item r = (ReturnValueAVM2Item) list.get(i + 2);
r.value = ri.value;
list.remove(i + 1);
list.remove(i);
i--;
continue;
}
if (isIntegerOrPopInteger(list.get(i + 1)) && (list.get(i + 2) instanceof ThrowAVM2Item)
&& (list.get(i + 2).value instanceof LocalRegAVM2Item)
&& (((LocalRegAVM2Item) list.get(i + 2).value).regIndex == ri.regIndex)) {
ThrowAVM2Item t = (ThrowAVM2Item) list.get(i + 2);
t.value = ri.value;
list.remove(i + 1);
list.remove(i);
i--;
continue;
}
} else if (i + 1 < list.size() && usages.isEmpty()) {
if (isIntegerOrPopInteger(list.get(i + 1))) {
list.remove(i + 1);
//§§push(int) in every return/throw in try..finally block
//there may be multiple pushes as finnaly clauses may be nested
int numPushes = 0;
while (i + 1 + numPushes < list.size() && isIntegerOrPopInteger(list.get(i + 1 + numPushes))) {
numPushes++;
}
if (numPushes > 0) {
if (i + 1 + numPushes < list.size()) {
if (numPushes > 0 && (list.get(i + 1 + numPushes) instanceof ReturnValueAVM2Item)
&& (list.get(i + 1 + numPushes).value instanceof LocalRegAVM2Item)
&& (((LocalRegAVM2Item) list.get(i + 1 + numPushes).value).regIndex == ri.regIndex)) {
ReturnValueAVM2Item r = (ReturnValueAVM2Item) list.get(i + 1 + numPushes);
r.value = ri.value;
for (int n = 0; n < numPushes; n++) {
list.remove(i + 1);
}
list.remove(i);
i--;
continue;
}
if (numPushes > 0 && (list.get(i + 1 + numPushes) instanceof ThrowAVM2Item)
&& (list.get(i + 1 + numPushes).value instanceof LocalRegAVM2Item)
&& (((LocalRegAVM2Item) list.get(i + 1 + numPushes).value).regIndex == ri.regIndex)) {
ThrowAVM2Item t = (ThrowAVM2Item) list.get(i + 1 + numPushes);
t.value = ri.value;
for (int n = 0; n < numPushes; n++) {
list.remove(i + 1);
}
list.remove(i);
i--;
continue;
}
} else if (i + numPushes < list.size() && usages.isEmpty()) {
for (int n = 0; n < numPushes; n++) {
list.remove(i + 1);
}
list.remove(i);
i--;
continue;
@@ -1136,6 +1146,20 @@ public class AVM2Graph extends Graph {
}
}
}
//§§push(int) before every continue/returnvoid in try..finally block
//there may be multiple pushes as finnaly clauses may be nested
//TODO: handle this better - actually remove only really needed
if ((list.get(i) instanceof ContinueItem) || (list.get(i) instanceof BreakItem) || (list.get(i) instanceof ReturnVoidAVM2Item)) {
for (int j = i - 1; j >= 0; j--) {
if (isIntegerOrPopInteger(list.get(j))) {
list.remove(j);
i--;
} else {
break;
}
}
}
}
List<GraphTargetItem> ret = list;
@@ -1241,4 +1265,12 @@ public class AVM2Graph extends Graph {
switchItem.switchedObject = setLocal.value;
}
}
@Override
protected boolean partIsSwitch(GraphPart part) {
if (part.end < 0) {
return false;
}
return avm2code.code.get(part.end).definition instanceof LookupSwitchIns;
}
}

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.abc.types;
import com.jpexs.decompiler.flash.SWFInputStream;
@@ -445,7 +446,7 @@ public final class MethodBody implements Cloneable {
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {
//System.out.println("--------------");
//System.out.println("--------------");
CodeStats stats = getCode().getStats(abc, this, initScope, true);
if (stats == null) {
return false;
}

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -53,6 +54,7 @@ import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.DefaultItem;
import com.jpexs.decompiler.graph.model.GotoItem;
import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.ScriptEndItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.WhileItem;
import com.jpexs.helpers.Helper;
@@ -159,6 +161,21 @@ public class ActionGraph extends Graph {
@Override
protected void finalProcess(List<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
if (level == 0) {
List<GraphTargetItem> removed = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) instanceof ScriptEndItem) {
continue;
}
if (list.get(i) instanceof FunctionActionItem) {
removed.add(0, list.remove(i));
} else {
break;
}
}
list.addAll(0, removed);
}
if (insideDoInitAction) {
ActionScript2ClassDetector detector = new ActionScript2ClassDetector();
detector.checkClass(list, path);

View File

@@ -238,7 +238,7 @@ public class Graph {
GraphPartQueue newParts = new GraphPartQueue();
loopnext:
for (GraphPart nextRaw : part.nextParts) {
for (GraphPart nextRaw : getNextParts(localData, part)) {
GraphPart next = checkPart(null, localData, part, nextRaw, null);
if (next == null) {
@@ -276,7 +276,7 @@ public class Graph {
}
public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List<Loop> loops) throws InterruptedException {
return getCommonPart(localData, part, part.nextParts, loops);
return getCommonPart(localData, part, getNextParts(localData, part), loops);
}
//TODO: Make this faster!
@@ -374,7 +374,7 @@ public class Graph {
}
}
loopi:
/*loopi:
for (int i = 0; i < parts.size(); i++) {
for (int j = 0; j < parts.size(); j++) {
if (j == i) {
@@ -386,7 +386,7 @@ public class Graph {
continue loopi;
}
}
}
}*/
List<Set<GraphPart>> reachable = new ArrayList<>();
Set<GraphPart> allReachable = new LinkedHashSet<>();
for (GraphPart p : parts) {
@@ -410,7 +410,7 @@ public class Graph {
continue;
}
visited.add(p);
int commonLevel = 1;
int commonLevel = 0;
for (Set<GraphPart> r : reachable) {
if (r.contains(p)) {
commonLevel++;
@@ -426,6 +426,9 @@ public class Graph {
//System.err.println("maxclevel = " + maxCommonLevel);
//System.err.println("maxclevelpart = " + maxCommonLevelPart);
if (maxCommonLevel <= 1) {
return null;
}
return maxCommonLevelPart;
}
@@ -440,7 +443,7 @@ public class Graph {
for (int i = part.start; i <= part.end; i++) {
GraphSourceItem src = code.get(i);
if (src.isJump()) {
part = part.nextParts.get(0);
part = getNextParts(localData, part).get(0);
if(st.isEmpty()){
startPart = part;
}
@@ -480,11 +483,11 @@ public class Graph {
System.err.println("parts:");
for (GraphPart p : allParts) {
System.err.print(p);
if (!p.nextParts.isEmpty()) {
if (!getNextParts(localData, p).isEmpty()) {
System.err.print(", next: ");
}
boolean first = true;
for (GraphPart n : p.nextParts) {
for (GraphPart n : getNextParts(localData, p)) {
if (!first) {
System.err.print(",");
}
@@ -552,7 +555,7 @@ public class Graph {
return new FinalProcessLocalData(loops);
}
protected void beforePrintGraph(BaseLocalData localData, String path, Set<GraphPart> allParts, List<Loop> loops) {
protected void beforePrintGraph(BaseLocalData localData, String path, Set<GraphPart> allParts, List<Loop> loops) throws InterruptedException {
}
@@ -604,7 +607,7 @@ public class Graph {
/**/
//if (ref.nextParts)
//if (getNextParts(localData, ref))
private void getBackEdges(BaseLocalData localData, List<Loop> loops) throws InterruptedException {
clearLoops(loops);
for (Loop el : loops) {
@@ -843,7 +846,7 @@ public class Graph {
}
}
private void processIfs(List<GraphTargetItem> list) {
protected 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)) {
@@ -1192,7 +1195,7 @@ public class Graph {
//loopContinues.add(part);
}
if (part.nextParts.size() == 2) {
if (part.nextParts.size() == 2 && !partIsSwitch(part)) {
List<GraphPart> nps;/* = new ArrayList<>(part.nextParts);
for(int i=0;i<nps.size();i++){
@@ -1217,7 +1220,7 @@ public class Graph {
if (next != null) {
getLoops(localData, next, loops, stopPart, false, level, visited);
}
} else if (part.nextParts.size() > 2) {
} else if (part.nextParts.size() > 2 || partIsSwitch(part)) {
GraphPart next = getNextCommonPart(localData, part, loops);
for (GraphPart p : part.nextParts) {
@@ -1411,6 +1414,10 @@ public class Graph {
}
}
protected List<GraphPart> getNextParts(BaseLocalData localData, GraphPart part) {
return part.nextParts;
}
protected List<GraphTargetItem> printGraph(List<GotoItem> foundGotos, 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();
@@ -1428,7 +1435,7 @@ public class Graph {
//try {
if (debugPrintGraph) {
System.err.println("PART " + part + " nextsize:" + part.nextParts.size());
System.err.println("PART " + part + " nextsize:" + getNextParts(localData, part).size());
}
/*while (((part != null) && (part.getHeight() == 1)) && (code.size() > part.start) && (code.get(part.start).isJump())) { //Parts with only jump in it gets ignored
@@ -1436,9 +1443,9 @@ public class Graph {
if (part == stopPart) {
return ret;
}
GraphTargetItem lop = checkLoop(part.nextParts.get(0), stopPart, loops);
GraphTargetItem lop = checkLoop(getNextParts(localData, part).get(0), stopPart, loops);
if (lop == null) {
part = part.nextParts.get(0);
part = getNextParts(localData, part).get(0);
} else {
break;
}
@@ -1584,8 +1591,11 @@ public class Graph {
parts = ((GraphPartMulti) part).parts;
} else {
parts.add(part);
while (part.nextParts.size() == 1 && part.nextParts.get(0).refs.size() == 1) {
part = part.nextParts.get(0);
while (getNextParts(localData, part).size() == 1 && getNextParts(localData, part).get(0).refs.size() == 1) {
if (stopPart.contains(getNextParts(localData, part).get(0))) { //it might be referenced with try statement
break;
}
part = getNextParts(localData, part).get(0);
parts.add(part);
}
}
@@ -1594,7 +1604,7 @@ public class Graph {
int start = p.start;
output.addAll(code.translatePart(p, localData, stack, start, end, staticOperation, path));
if ((end >= code.size() - 1) && p.nextParts.isEmpty()) {
if ((end >= code.size() - 1) && getNextParts(localData, p).isEmpty()) {
output.add(new ScriptEndItem());
}
}
@@ -1614,7 +1624,7 @@ public class Graph {
//********************************END PART DECOMPILING
if (parseNext) {
if (part.nextParts.size() > 2) {
if (getNextParts(localData, part).size() > 2 || partIsSwitch(part)) {
GraphTargetItem originalSwitchedItem = stack.pop();
makeAllCommands(currentRet, stack);
GraphTargetItem switchedItem = originalSwitchedItem;
@@ -1742,11 +1752,11 @@ public class Graph {
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);
GraphPart defaultPart = hasExpr ? getNextParts(localData, part).get(1 + defaultBranch) : getNextParts(localData, part).get(0);
List<GraphPart> caseBodyParts = new ArrayList<>();
for (int i = 1; i < part.nextParts.size(); i++) {
for (int i = 1; i < getNextParts(localData, part).size(); i++) {
if (!hasExpr) {
if (part.nextParts.get(i) == defaultPart) {
if (getNextParts(localData, part).get(i) == defaultPart) {
pos++;
continue;
}
@@ -1763,7 +1773,7 @@ public class Graph {
pos++;
continue;
}
caseBodyParts.add(part.nextParts.get(i));
caseBodyParts.add(getNextParts(localData, part).get(i));
pos++;
}
Reference<GraphPart> nextRef = new Reference<>(null);
@@ -1783,7 +1793,7 @@ public class Graph {
pos++;
} //else
GraphPart nextOnePart = null;
if (part.nextParts.size() == 2) {
if (getNextParts(localData, part).size() == 2 && !partIsSwitch(part)) {
GraphTargetItem expr = stack.pop();
/*if (expr instanceof LogicalOpItem) {
expr = ((LogicalOpItem) expr).invert();
@@ -1793,7 +1803,7 @@ public class Graph {
if (nextOnePart == null) {
List<GraphPart> nps;
nps = part.nextParts;
nps = getNextParts(localData, part);
boolean isEmpty = nps.get(0) == nps.get(1);
GraphPart next = getCommonPart(localData, part, nps, loops);
@@ -1896,11 +1906,16 @@ public class Graph {
}
}
} //else
if (part.nextParts.size() == 1) {
nextOnePart = part.nextParts.get(0);
if (getNextParts(localData, part).size() == 1) {
nextOnePart = getNextParts(localData, part).get(0);
}
if (getNextParts(localData, part).isEmpty()) {
makeAllCommands(currentRet, stack);
}
if (nextOnePart != null) {
printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, getNextParts(localData, part).get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
}
}
@@ -2415,29 +2430,17 @@ public class Graph {
if (p instanceof FunctionActionItem) {
commands.add(clen, p);
} else {
if (isExit) {
/*if (isExit) {
//ASC2 leaves some function calls unpopped on stack before returning from a method
commands.add(clen, p);
} else {
} 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);
}
}
while (isPartEmpty(to) && !to.nextParts.isEmpty()) {
to = to.nextParts.get(0);
removeEdgeToFromList(edges, to);
}
}
protected SwitchItem handleSwitch(GraphTargetItem switchedObject,
GraphSourceItem switchStartItem, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> allParts, TranslateStack stack, List<GraphPart> stopPart, List<Loop> loops, BaseLocalData localData, int staticOperation, String path,
List<GraphTargetItem> caseValuesMap, GraphPart defaultPart, List<GraphPart> caseBodyParts, Reference<GraphPart> nextRef, Reference<GraphTargetItem> tiRef) throws InterruptedException {
@@ -2570,16 +2573,12 @@ public class Graph {
for (int i = 0; i < caseBodies.size(); i++) {
List<GraphTargetItem> currentCaseCommands = new ArrayList<>();
GraphPart nextCase = next;
if (next != null) {
if (i < caseBodies.size() - 1) {
if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops)) {
currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id));
} else {
nextCase = caseBodies.get(i + 1);
}
if (i < caseBodies.size() - 1) {
if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops)) {
currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id));
}
}
List<GraphPart> stopPart2x = new ArrayList<>(stopPart);
for (GraphPart b : caseBodies) {
if (b != caseBodies.get(i)) {
@@ -2638,4 +2637,8 @@ public class Graph {
return new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping);
}
protected boolean partIsSwitch(GraphPart part) {
return false;
}
}

View File

@@ -2006,6 +2006,8 @@ public class ActionScript2Test extends ActionScript2TestBase {
+ "case \"C\":\r\n"
+ "trace(\"Ret 5\");\r\n"
+ "return 5;\r\n"
+ "default:\r\n"
+ "continue;\r\n"
+ "}\r\n"
+ "}\r\n"
+ "trace(\"Final\");\r\n"

View File

@@ -1415,6 +1415,7 @@ public class ActionScript3Test extends ActionScriptTestBase {
+ "{\r\n"
+ "trace(\"a\");\r\n"
+ "}\r\n"
+ "continue;\r\n"
+ "}\r\n"
+ "catch(e:EOFError)\r\n"
+ "{\r\n"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>asc2</title>
<meta name="description" content="" />
<script src="js/swfobject.js"></script>
<script>
var flashvars = {
};
var params = {
menu: "false",
scale: "noScale",
allowFullscreen: "true",
allowScriptAccess: "always",
bgcolor: "",
wmode: "direct" // can cause issues with FP settings & webcam
};
var attributes = {
id:"asc2"
};
swfobject.embedSWF(
"asc2.swf",
"altContent", "100%", "100%", "10.0.0",
"expressInstall.swf",
flashvars, params, attributes);
</script>
<style>
html, body { height:100%; overflow:hidden; }
body { margin:0; }
</style>
</head>
<body>
<div id="altContent">
<h1>asc2</h1>
<p><a href="http://www.adobe.com/go/getflashplayer">Get Adobe Flash player</a></p>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
@echo off
set COMPILERKIND=air
call c:\air\bin\mxmlc.bat -warnings=false -debug=true -output bin/Main.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1

View File

@@ -0,0 +1,6 @@
@echo off
call build_air_debug.bat
call build_flex_debug.bat
call build_flex_apache_debug.bat
call build_swftools_debug.bat
pause

View File

@@ -0,0 +1,3 @@
@echo off
set COMPILERKIND=flex_apache
call c:\flex_apache\bin\mxmlc.bat -warnings=false -debug=true -output bin/Main.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1

View File

@@ -0,0 +1,3 @@
@echo off
set COMPILERKIND=flex
c:\flex\bin\mxmlc.exe -warnings=false -debug=true -output bin/Main.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1

View File

@@ -0,0 +1,19 @@
@echo off
set ISDEBUG=false
if "%1" == "debug" goto blockset
goto block2
:blockset
set ISDEBUG=true
:block2
set COMPILERPATH=%2
set COMPILERKIND=%3
rem if not exist %COMPILERPATH% goto notex
%COMPILERPATH% -warnings=false -debug=%ISDEBUG% -output bin/Main.%COMPILERKIND%.swf src/Main.as > buildlog.%COMPILERKIND%.txt
if errorlevel==1 goto failed
goto end
:notex
echo Flex/AIR SDK not found. Download and unpack Flex/AIR SDK into some directory and add it to PATH variable
goto end
:failed
pause
:end

View File

@@ -0,0 +1,4 @@
@echo off
set COMPILERKIND=swftools
cd src
c:\swftools\as3compile.exe Main.as -o ..\bin\Main.%COMPILERKIND%.swf 1> ../buildlog.%COMPILERKIND%.txt 2>&1

View File

@@ -0,0 +1,3 @@
Loading configuration: c:\air\frameworks\flex-config.xml
2753 bytes written to C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\bin\Main.air.swf in 0,459 seconds

View File

@@ -0,0 +1,2 @@
Loading configuration file C:\flex\frameworks\flex-config.xml
C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\asc2\bin\Main.flex.swf (1083 bytes)

View File

@@ -0,0 +1,2 @@
Loading configuration file C:\flex_apache\frameworks\flex-config.xml
C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\bin\Main.flex_apache.swf (3617 bytes)

View File

@@ -0,0 +1,4 @@
Stack mismatch at pos 61
Should be: 1:1, is: 0:1
Stack mismatch at pos 61
Should be: 1:1, is: 0:1

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<project version="2">
<!-- Output SWF options -->
<output>
<movie outputType="Application" />
<movie input="" />
<movie path="bin\Main.flex.swf" />
<movie fps="30" />
<movie width="800" />
<movie height="600" />
<movie version="25" />
<movie minorVersion="0" />
<movie platform="Flash Player" />
<movie background="#FFFFFF" />
</output>
<!-- Other classes to be compiled into your SWF -->
<classpaths>
<class path="src" />
</classpaths>
<!-- Build options -->
<build>
<option accessible="False" />
<option advancedTelemetry="False" />
<option allowSourcePathOverlap="False" />
<option benchmark="False" />
<option es="False" />
<option inline="False" />
<option locale="" />
<option loadConfig="" />
<option optimize="True" />
<option omitTraces="True" />
<option showActionScriptWarnings="True" />
<option showBindingWarnings="True" />
<option showInvalidCSS="True" />
<option showDeprecationWarnings="True" />
<option showUnusedTypeSelectorWarnings="True" />
<option strict="True" />
<option useNetwork="True" />
<option useResourceBundleMetadata="True" />
<option warnings="True" />
<option verboseStackTraces="False" />
<option linkReport="" />
<option loadExterns="" />
<option staticLinkRSL="True" />
<option additional="" />
<option compilerConstants="" />
<option minorVersion="" />
</build>
<!-- SWC Include Libraries -->
<includeLibraries>
<!-- example: <element path="..." /> -->
</includeLibraries>
<!-- SWC Libraries -->
<libraryPaths>
<!-- example: <element path="..." /> -->
</libraryPaths>
<!-- External Libraries -->
<externalLibraryPaths>
<!-- example: <element path="..." /> -->
</externalLibraryPaths>
<!-- Runtime Shared Libraries -->
<rslPaths>
<!-- example: <element path="..." /> -->
</rslPaths>
<!-- Intrinsic Libraries -->
<intrinsics>
<!-- example: <element path="..." /> -->
</intrinsics>
<!-- Assets to embed into the output SWF -->
<library>
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
</library>
<!-- Class files to compile (other referenced classes will automatically be included) -->
<compileTargets>
<compile path="src\Main.as" />
</compileTargets>
<!-- Paths to exclude from the Project Explorer tree -->
<hiddenPaths>
<hidden path="obj" />
</hiddenPaths>
<!-- Executed before build -->
<preBuildCommand />
<!-- Executed after build -->
<postBuildCommand alwaysRun="False">build_air_debug.bat
build_flex_apache_debug.bat
build_swftools_debug.bat</postBuildCommand>
<!-- Other project options -->
<options>
<option showHiddenPaths="False" />
<option testMovie="Default" />
<option testMovieCommand="" />
</options>
<!-- Plugin storage -->
<storage />
</project>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--This Adobe Flex compiler configuration file was generated by a tool.-->
<!--Any modifications you make may be lost.-->
<flex-config>
<target-player>25.0</target-player>
<benchmark>false</benchmark>
<static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
<compiler>
<define append="true">
<name>CONFIG::debug</name>
<value>true</value>
</define>
<define append="true">
<name>CONFIG::release</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::timeStamp</name>
<value>'31.01.2021'</value>
</define>
<define append="true">
<name>CONFIG::air</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::mobile</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::desktop</name>
<value>false</value>
</define>
<verbose-stacktraces>true</verbose-stacktraces>
<source-path append="true">
<path-element>C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\src</path-element>
<path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
</source-path>
</compiler>
<file-specs>
<path-element>C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\src\Main.as</path-element>
</file-specs>
<default-background-color>#FFFFFF</default-background-color>
<default-frame-rate>30</default-frame-rate>
<default-size>
<width>800</width>
<height>600</height>
</default-size>
</flex-config>

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--This Adobe Flex compiler configuration file was generated by a tool.-->
<!--Any modifications you make may be lost.-->
<flex-config>
<target-player>25.0</target-player>
<benchmark>false</benchmark>
<static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
<compiler>
<define append="true">
<name>CONFIG::debug</name>
<value>true</value>
</define>
<define append="true">
<name>CONFIG::release</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::timeStamp</name>
<value>'31.01.2021'</value>
</define>
<define append="true">
<name>CONFIG::air</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::mobile</name>
<value>false</value>
</define>
<define append="true">
<name>CONFIG::desktop</name>
<value>false</value>
</define>
<verbose-stacktraces>true</verbose-stacktraces>
<source-path append="true">
<path-element>C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\src</path-element>
<path-element>C:\Program Files (x86)\FlashDevelop\Library\AS3\classes</path-element>
</source-path>
</compiler>
<file-specs>
<path-element>C:\Dropbox\Programovani\JavaSE\FFDec\libsrc\ffdec_lib\testdata\cross_compile\src\Main.as</path-element>
</file-specs>
<default-background-color>#FFFFFF</default-background-color>
<default-frame-rate>30</default-frame-rate>
<default-size>
<width>800</width>
<height>600</height>
</default-size>
</flex-config>

View File

@@ -0,0 +1,34 @@
package
{
import flash.display.MovieClip;
import flash.events.Event;
import tests.*;
/**
* ...
* @author JPEXS
*/
public class Main extends MovieClip
{
TestTryCatch;
TestTryCatchIfInTry;
TestTryCatchLoop;
TestTryCatchExceptionUsage
TestTryFinally;
TestTryFinallyDirectReturnInFinally;
TestTryFinallyLoop;
TestTryFinallyLoopInFinally;
TestTryFinallyMultipleCatch;
TestTryFinallyReturn;
TestTryFinallyReturnInFinally;
TestTryFinallyReturnNested;
TestTryFinallyReturnVoid;
public function Main()
{
}
}
}

View File

@@ -0,0 +1,26 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryCatch
{
public function run() : void
{
trace("before try");
try
{
trace("in try");
}
catch (e:Error)
{
trace("in catch");
}
trace("after");
}
}
}

View File

@@ -0,0 +1,26 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryCatchExceptionUsage
{
public function run() : void
{
trace("before try");
try
{
trace("in try");
}
catch (e:Error)
{
trace("catched exception: "+e.message);
}
trace("after");
}
}
}

View File

@@ -0,0 +1,32 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryCatchIfInTry
{
public function run() : void
{
var a:Boolean = true;
trace("before");
try
{
if (a)
{
trace("ret");
return;
}
trace("in try");
}
catch (e:Error)
{
trace("in catch");
}
trace("after");
}
}
}

View File

@@ -0,0 +1,39 @@
package tests
{
import flash.errors.EOFError;
/**
* ...
* @author JPEXS
*/
public class TestTryCatchLoop
{
public function run() : void
{
var j:* = undefined;
for (var i:* = 0; i < 100; i++)
{
try
{
for (j = 0; j < 20; j++)
{
trace("a");
}
}
catch (e:EOFError)
{
continue;
}
catch (e:Error)
{
continue;
}
trace("after_try");
}
trace("end");
}
}
}

View File

@@ -0,0 +1,30 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinally
{
public function run() : void
{
trace("before try");
try
{
trace("in try");
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally");
}
trace("after");
}
}
}

View File

@@ -0,0 +1,34 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyDirectReturnInFinally
{
public function run() : String
{
var str:String = "xxx";
try
{
}
catch (e:Error)
{
trace("error");
}
finally
{
trace("hi ");
if (5 == 4)
{
return str;
}
return "hu" + str;
}
}
}
}

View File

@@ -0,0 +1,38 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyLoop
{
public function run() : void
{
for (var i:int = 0; i < 10; i++)
{
trace("before try");
try
{
trace("in try");
if (i == 5)
{
trace("continue for");
continue;
}
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally");
}
trace("after");
}
}
}
}

View File

@@ -0,0 +1,38 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyLoopInFinally
{
public function run() : void
{
for (var i:int = 0; i < 10; i++)
{
trace("before try");
try
{
trace("in try");
}
catch (e:Error)
{
trace("in catch");
}
finally
{
if (i == 5)
{
trace("continue for");
continue;
}
trace("in finally");
}
trace("after");
}
}
}
}

View File

@@ -0,0 +1,35 @@
package tests
{
import flash.errors.EOFError;
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyMultipleCatch
{
public function run() : void
{
trace("before try");
try
{
trace("in try");
}
catch (e:Error)
{
trace("in catch Error");
}
catch (e:EOFError)
{
trace("in catch EOFError");
}
finally
{
trace("in finally");
}
trace("after");
}
}
}

View File

@@ -0,0 +1,42 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyReturn
{
public function run() : String
{
trace("before try");
try
{
trace("in try");
var a:int = 5;
if (a > 4)
{
return "RET";
}
trace("between");
if (a < 3)
{
return "RE2";
}
trace("in try2");
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally");
}
trace("after");
return "RETFINAL";
}
}
}

View File

@@ -0,0 +1,44 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyReturnInFinally
{
public function run() : String
{
trace("before try");
try
{
trace("in try");
var a:int = 5;
if (a > 4)
{
return "RET";
}
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally");
if (a > 6){
return "FINRET1";
}
trace("xx");
if (a > 5){
return "FINRET2";
}
trace("nofinret");
}
trace("after");
return "RETEXIT";
}
}
}

View File

@@ -0,0 +1,43 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyReturnNested
{
public function run() : String
{
try
{
trace("before try2");
try
{
trace("in try2");
var a:int = 5;
if (a > 4)
{
return "RET";
}
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally2");
}
trace("after");
}
finally
{
trace("in finally1");
}
return "RETFINAL";
}
}
}

View File

@@ -0,0 +1,36 @@
package tests
{
/**
* ...
* @author JPEXS
*/
public class TestTryFinallyReturnVoid
{
public function run() : void
{
trace("before try");
try
{
trace("in try");
var a:int = 5;
if (a > 4)
{
return;
}
trace("in try2");
}
catch (e:Error)
{
trace("in catch");
}
finally
{
trace("in finally");
}
trace("after");
}
}
}

View File

@@ -249,6 +249,10 @@
<label>core.lexers</label>
<location>libsrc/ffdec_lib/lexers</location>
</source-folder>
<source-folder style="packages">
<label>core.graphviz</label>
<location>libsrc/ffdec_lib/graphviz</location>
</source-folder>
<source-file>
<location>build.xml</location>
</source-file>