try..catch..finally of SWFTools AS3Compile

This commit is contained in:
Jindra Petřík
2021-02-08 20:15:19 +01:00
parent 0a7f39b82c
commit 1a393854c0
14 changed files with 223 additions and 33 deletions
@@ -66,6 +66,13 @@ public class AVM2LocalData extends BaseLocalData {
*/
public Map<GraphPart, GraphPart> finallyJumps = new HashMap<>();
/**
* Mapping from source part (as in finallyJumps) to finally exception index
*/
public Map<GraphPart, Integer> finallyJumpsToFinallyIndex = new HashMap<>();
public Map<Integer, GraphPart> finallyIndexToDefaultGraphPart = new HashMap<>();
//exception index => switchPart
public Map<Integer, GraphPart> ignoredSwitches;
@@ -90,6 +97,8 @@ public class AVM2LocalData extends BaseLocalData {
public CodeStats codeStats;
public Set<Integer> finallyIndicesWithDoublePush = new HashSet<>();
public AVM2LocalData() {
}
@@ -127,6 +136,9 @@ public class AVM2LocalData extends BaseLocalData {
codeStats = localData.codeStats;
defaultWays = localData.defaultWays;
switchedRegs = localData.switchedRegs;
finallyIndicesWithDoublePush = localData.finallyIndicesWithDoublePush;
finallyJumpsToFinallyIndex = localData.finallyJumpsToFinallyIndex;
finallyIndexToDefaultGraphPart = localData.finallyIndexToDefaultGraphPart;
}
public AVM2ConstantPool getConstants() {
@@ -2447,6 +2447,9 @@ public class AVM2Code implements Cloneable {
// check stack=0
return true;
}
if (ins.definition instanceof ThrowIns) {
return true;
}
if (ins.definition instanceof JumpIns) {
try {
pos = adr2pos(ins.getTargetAddress());
@@ -2518,7 +2521,7 @@ public class AVM2Code implements Cloneable {
if (code.get(maxIp).definition instanceof JumpIns) {
nextIp = adr2pos(pos2adr(nextIp) + code.get(maxIp).operands[0]);
}
if (nextIp < stats.instructionStats.length) {
/*if (nextIp < stats.instructionStats.length) {
InstructionStats nextIpStat = stats.instructionStats[nextIp];
int origScopePos = nextIpStat.scopepos;
int origStackPos = nextIpStat.stackpos;
@@ -2528,12 +2531,12 @@ public class AVM2Code implements Cloneable {
stats.instructionStats[i].seen = false;
}
// Rerun rest with new scopePos, stackPos
if (!walkCode(stats, nextIp, origStackPos + 1/*magic!*/, scopePos - 1 /*magic!*/, abc, autoFill)) {
if (!walkCode(stats, nextIp, origStackPos + 1, scopePos - 1, abc, autoFill)) {
return null;
}
scopePos--;
}
}
}*/
prevStart = ex.start;
} catch (ConvertException ex1) {
// ignore
@@ -34,8 +34,11 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.LabelIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns;
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.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
@@ -73,6 +76,7 @@ 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.AnyItem;
import com.jpexs.decompiler.graph.model.BreakItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.ExitItem;
@@ -212,14 +216,40 @@ public class AVM2Graph extends Graph {
List<GraphPart> foundParts = new ArrayList<>();
int stackAfter = localData.codeStats.instructionStats[finallyTryTargetPart.end].stackpos_after;
//int stackAfter = localData.codeStats.instructionStats[finallyPart.start].stackpos;
//System.err.println("searching pops from stack size " + stackAfter);
findAllPops(localData, stackAfter, finallyPart, foundIps, foundParts, new HashSet<>());
int switchIp = -1;
loopFound:
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);
} else if (avm2code.code.get(ip).definition instanceof PopIns) {
//In swftools try..finally, there is dup before lookupswitch and pop in its branches
GraphPart popPart = searchPart(ip, allParts);
boolean isEmpty = true;
ip--;
loopEmpty:
while (isEmpty) {
for (int j = ip; j >= popPart.start; j--) {
if (avm2code.code.get(j).definition instanceof LookupSwitchIns) {
switchPart = searchPart(j, allParts);
localData.finallyIndicesWithDoublePush.add(e);
break loopFound;
} else if (avm2code.code.get(j).definition instanceof LabelIns) {
//okay
} else {
isEmpty = false;
break loopEmpty;
}
}
if (popPart.refs.size() == 1) {
popPart = popPart.refs.get(0);
ip = popPart.end;
} else {
break;
}
}
}
}
} else if (finallyKind == FINALLY_KIND_REGISTER_BASED) {
@@ -270,10 +300,11 @@ public class AVM2Graph extends Graph {
} else if (ins.definition instanceof PushByteIns) {
int val = ins.operands[0];
if (val < 0 || val > switchPart.nextParts.size() - 2) {
localData.finallyJumps.put(rr, switchPart.nextParts.get(0)); //default branch
localData.finallyJumps.put(rr, switchPart.nextParts.get(0)); //default branch
} else {
localData.finallyJumps.put(rr, switchPart.nextParts.get(1 + val));
}
localData.finallyJumpsToFinallyIndex.put(rr, e);
needsPrev = false;
break;
} else if ((ins.definition instanceof SetLocalTypeIns) && (((SetLocalTypeIns) ins.definition).getRegisterId(ins) == switchedReg)) {
@@ -310,6 +341,7 @@ public class AVM2Graph extends Graph {
for (GraphPart r : p.refs) {
if (r != switchPart) {
localData.finallyJumps.put(r, p);
localData.finallyJumpsToFinallyIndex.put(r, e);
}
}
}
@@ -553,7 +585,9 @@ public class AVM2Graph extends Graph {
return;
}
visited.add(part);
//System.err.println("walk part " + part);
for (int ip = part.start; ip <= part.end; ip++) {
//System.err.println("ip " + ip + ": " + avm2code.code.get(ip) + ": stackpos_after:" + localData.codeStats.instructionStats[ip].stackpos_after);
if (localData.codeStats.instructionStats[ip].stackpos_after == stackLevel - 1) {
foundIps.add(ip);
foundParts.add(part);
@@ -576,6 +610,9 @@ public class AVM2Graph extends Graph {
}
private GraphPart searchPart(int ip, Set<GraphPart> allParts) {
if (ip < 0) {
return null;
}
for (GraphPart p : allParts) {
if (ip >= p.start && ip <= p.end) {
return p;
@@ -670,6 +707,27 @@ public class AVM2Graph extends Graph {
}
}
}
if (defaultPushByte == null) {
if (getRealRefs(finallyEndPart).size() == 0) {
if (avm2code.code.get(finallyEndPart.start - 1).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(finallyEndPart.start - 1, allParts);
finallyEndPart = prevPart.nextParts.get(0);
if (finallyEndPart.nextParts.size() == 1 && finallyEndPart.nextParts.get(0).refs.size() > 1) {
for (int j = finallyEndPart.start; j <= finallyEndPart.end; j++) {
AVM2Instruction ins = avm2code.code.get(j);
if (ins.definition instanceof NopIns) {
} else if (ins.definition instanceof PushByteIns) {
defaultPushByte = ins.operands[0];
break;
} else {
break;
}
}
}
}
}
}
catchedExceptions.add(finallyException);
}
@@ -689,13 +747,17 @@ public class AVM2Graph extends Graph {
List<GraphTargetItem> finallyCommands = new ArrayList<>();
GraphPart afterPart = null;
for (GraphPart p : allParts) {
if (endIp >= p.start && endIp <= p.end) {
afterPart = p;
break;
GraphPart endIpPart = searchPart(endIp, allParts);
if (endIpPart != null && getRealRefs(endIpPart).isEmpty()) { //swftools - there is jump on previous ip
if (avm2code.code.get(endIpPart.start - 1).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(endIpPart.start - 1, allParts);
endIpPart = prevPart.nextParts.get(0);
}
}
afterPart = endIpPart;
stack.clear(); //If the original code (before check()) had "if" in it, there would be something on stack
if (switchedReg > -1) {
@@ -716,6 +778,10 @@ public class AVM2Graph extends Graph {
stopPart2.add(afterPart);
tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, stopPart2, loops, staticOperation, path);
}
boolean inlinedFinally = false;
List<GraphTargetItem> finallyTargetItems = new ArrayList<>();
GraphPart exAfterPart = afterPart;
GraphPart defaultPart = null;
if (finallyException != null) {
@@ -732,6 +798,8 @@ public class AVM2Graph extends Graph {
}
}
localData.finallyIndexToDefaultGraphPart.put(finallyIndex, defaultPart);
afterPart = null;
GraphPart finallyTryTargetPart = null;
int targetPos = avm2code.adr2pos(finallyException.target);
@@ -744,10 +812,55 @@ public class AVM2Graph extends Graph {
GraphPart finallyPart = finallyTryTargetPart.nextParts.isEmpty() ? null : finallyTryTargetPart.nextParts.get(0);
List<GraphPart> finallyTargetStopPart = new ArrayList<>(stopPart);
if (endIpPart != null) {
finallyTargetStopPart.add(endIpPart);
}
TranslateStack st2 = (TranslateStack) stack.clone();
st2.clear();
st2.add(new ExceptionAVM2Item(finallyException));
AVM2LocalData localData2 = new AVM2LocalData(localData);
localData2.scopeStack = new ScopeStack();
finallyTargetItems = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, finallyTryTargetPart, finallyTargetStopPart, loops, 0, path);
if (!finallyTargetItems.isEmpty() && (finallyTargetItems.get(finallyTargetItems.size() - 1) instanceof ThrowAVM2Item)) {
//ignore some usual commands at the beginning - these are ignored in ffdec later, but we need to check it's empty
boolean isEmpty = true;
for (int i = 0; i < finallyTargetItems.size(); i++) {
GraphTargetItem it = finallyTargetItems.get(i);
if (it instanceof SetLocalAVM2Item) {
if (it.value.getNotCoerced() instanceof ExceptionAVM2Item) {
//okay
} else {
isEmpty = false;
break;
}
} else if (it instanceof ThrowAVM2Item) {
} else if (it instanceof IntegerValueAVM2Item) {
} else {
isEmpty = false;
break;
}
}
//inlined finally
if (!isEmpty) { //there must be at least single command before Throw
inlinedFinally = true;
}
}
List<GraphPart> tryStopPart = new ArrayList<>(stopPart);
if (finallyPart != null) {
tryStopPart.add(finallyPart);
}
if (finallyPart == null) {
tryStopPart.add(endIpPart);
afterPart = endIpPart;
}
if (defaultPart != null) {
tryStopPart.add(defaultPart);
}
@@ -825,27 +938,40 @@ public class AVM2Graph extends Graph {
catchCommands.add(currentCatchCommands);
}
/*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()) {
if (!inlinedFinally && catchCommands.isEmpty() && finallyCommands.isEmpty() && tryCommands.isEmpty()) {
return null;
}
List<GraphTargetItem> ret = new ArrayList<>();
if (catchedExceptions.isEmpty() && finallyCommands.isEmpty()) {
if (!inlinedFinally && catchedExceptions.isEmpty() && finallyCommands.isEmpty()) {
ret.addAll(tryCommands);
return ret;
}
ret.add(new TryAVM2Item(tryCommands, catchedExceptions, catchCommands, finallyCommands, "TODO"));
TryAVM2Item tryItem = new TryAVM2Item(tryCommands, catchedExceptions, catchCommands, finallyCommands, "");
if (inlinedFinally) {
List<List<GraphTargetItem>> parentCatchCommands = new ArrayList<>();
parentCatchCommands.add(finallyTargetItems);
List<ABCException> parentCatchedExceptions = new ArrayList<>();
parentCatchedExceptions.add(finallyException);
List<GraphTargetItem> parentTryCommands = new ArrayList<>();
if (catchedExceptions.isEmpty() && finallyCommands.isEmpty()) {
parentTryCommands.addAll(tryCommands);
} else {
parentTryCommands.add(tryItem);
}
TryAVM2Item parentTryItem = new TryAVM2Item(parentTryCommands, parentCatchedExceptions, parentCatchCommands, new ArrayList<>(), "");
ret.add(parentTryItem);
} else {
ret.add(tryItem);
}
if (afterPart != null) {
if (finallyIndex > -1 && localData.finallyIndicesWithDoublePush.contains(finallyIndex)) {
stack.push(new AnyItem());
}
ret.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, afterPart, stopPart, loops, staticOperation, path));
}
return ret;
@@ -1024,6 +1150,15 @@ public class AVM2Graph extends Graph {
}
}
}
int finallyIndex = aLocalData.finallyJumpsToFinallyIndex.get(prev);
if (output != null && aLocalData.finallyIndicesWithDoublePush.contains(finallyIndex)) {
GraphPart defaultPart = aLocalData.finallyIndexToDefaultGraphPart.containsKey(finallyIndex) ? aLocalData.finallyIndexToDefaultGraphPart.get(finallyIndex) : null;
if (defaultPart == null) {
stack.push(new AnyItem());
} else if (defaultPart != aLocalData.finallyJumps.get(prev)) {
stack.push(new AnyItem());
}
}
if (output != null && switchedReg == -1 && !stack.isEmpty() && (stack.peek() instanceof IntegerValueAVM2Item)) {
stack.pop();
} else if (output != null && switchedReg == -1 && !output.isEmpty() && (output.get(output.size() - 1) instanceof IntegerValueAVM2Item)) {
@@ -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.instructions.stack;
import com.jpexs.decompiler.flash.abc.ABC;
@@ -24,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.MarkItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.AnyItem;
import java.util.List;
/**
@@ -45,9 +47,14 @@ public class PopIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem top = stack.pop();
if ((!(top instanceof MarkItem))) {
output.add(top);
if (top instanceof AnyItem) {
return;
}
if (top instanceof MarkItem) {
return;
}
output.add(top);
}
@Override
@@ -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.model.clauses;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
@@ -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.abc.avm2.AVM2Code;
@@ -39,6 +40,8 @@ public class ABCException implements Serializable, Cloneable {
public int name_index;
public static final String DEFAULT_EXCEPTION_NAME = "_loc_e_";
@Override
public String toString() {
return "Exception: startServer=" + Helper.formatAddress(start) + " end=" + Helper.formatAddress(end) + " target=" + target + " type_index=" + type_index + " name_index=" + name_index;
@@ -62,7 +65,7 @@ public class ABCException implements Serializable, Cloneable {
public String getVarName(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames) {
if (name_index == 0) {
return "";
return DEFAULT_EXCEPTION_NAME;
}
return constants.getMultiname(name_index).getName(constants, fullyQualifiedNames, false, true);
}
@@ -1595,13 +1595,13 @@ public class Graph {
parts = ((GraphPartMulti) part).parts;
} else {
parts.add(part);
while (getNextParts(localData, part).size() == 1 && getNextParts(localData, part).get(0).refs.size() == 1) {
/*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);
}
}*/
}
for (GraphPart p : parts) {
int end = p.end;
@@ -0,0 +1,28 @@
package com.jpexs.decompiler.graph.model;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
/**
*
* @author JPEXS
*/
public class AnyItem extends GraphTargetItem {
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
return writer.append("§§any()");
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
}
}