Fix swaps

This commit is contained in:
Jindra Petřík
2025-08-09 10:41:51 +02:00
parent a804987067
commit 77d96e8e43
23 changed files with 540 additions and 43 deletions

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.helpers.Reference;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -55,6 +56,11 @@ public abstract class BaseLocalData {
*/
public Set<String> usedDeobfuscations = new LinkedHashSet<>();
/**
* Max temp index
*/
public Reference<Integer> maxTempIndex = new Reference<>(0);
/**
* Constructor.
*/

View File

@@ -3823,7 +3823,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
break;
}
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
ins.translate(localData, stack, output, staticOperation, path);
if (ins.isExit()) {
break;

View File

@@ -298,6 +298,7 @@ public class AVM2LocalData extends BaseLocalData {
bottomSetLocals = localData.bottomSetLocals;
swfVersion = localData.swfVersion;
usedDeobfuscations = localData.usedDeobfuscations;
maxTempIndex = localData.maxTempIndex;
}
/**

View File

@@ -1826,6 +1826,7 @@ public class AVM2Code implements Cloneable {
/**
* Converts to source output.
*
* @param maxTempIndex Max temp index
* @param output Output
* @param swfVersion SWF version
* @param switchParts Switch parts
@@ -1857,7 +1858,7 @@ public class AVM2Code implements Cloneable {
* @throws ConvertException On convert error
* @throws InterruptedException On interrupt
*/
public void toSourceOutput(List<GraphTargetItem> output, int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, 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, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssignmentIps, LinkedIdentityHashSet<SetLocalAVM2Item> bottomStackSetLocals, Set<String> usedDeobfuscations) throws ConvertException, InterruptedException {
public void toSourceOutput(Reference<Integer> maxTempIndex, List<GraphTargetItem> output, int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, 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, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssignmentIps, LinkedIdentityHashSet<SetLocalAVM2Item> bottomStackSetLocals, Set<String> usedDeobfuscations) throws ConvertException, InterruptedException {
boolean debugMode = DEBUG_MODE;
if (debugMode) {
System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
@@ -1976,7 +1977,7 @@ public class AVM2Code implements Cloneable {
} else
*/
if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) {
ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
//ip = end + 1;
break;
} else if (ins.definition instanceof NewFunctionIns) {
@@ -2012,13 +2013,13 @@ public class AVM2Code implements Cloneable {
}
}
// What to do when hasDup is false?
ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek();
nft.functionName = functionName;
ip++;
} else {
try {
ins.definition.translate(usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
ins.definition.translate(maxTempIndex, usedDeobfuscations, swfVersion, switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssignmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
if (stack.size() == 1 && (stack.peek() instanceof SetLocalAVM2Item)) {
bottomStackSetLocals.add((SetLocalAVM2Item) stack.peek());

View File

@@ -236,7 +236,7 @@ public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter {
return;
}
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
ins.translate(localData, stack, output, 0, "");
}

View File

@@ -326,7 +326,7 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
continue outer;
}
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
ins.translate(localData, stack, output, 0, "");
if (def instanceof SetLocalTypeIns) {
int regId = ((SetLocalTypeIns) def).getRegisterId(ins);

View File

@@ -370,7 +370,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush
}
}
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
ins.translate(localData, stack, output, 0, "");
}

View File

@@ -339,7 +339,7 @@ public class AVM2Graph extends Graph {
localData2.localScopeStack = new ScopeStack();
List<GraphTargetItem> targetOutput = new GraphPartMarkedArrayList<>();
finallyTryTargetStack.setConnectedOutput(0, targetOutput);
finallyTryTargetStack.setConnectedOutput(0, targetOutput, localData);
try {
translatePart(targetOutput, localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target");
} catch (GraphPartChangeException ex1) { //should not happen

View File

@@ -200,7 +200,7 @@ public class AVM2GraphSource extends GraphSource {
@Override
public void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
Reference<GraphSourceItem> lineStartItem = new Reference<>(localData.lineStartInstruction);
code.toSourceOutput(output, localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals, localData.usedDeobfuscations);
code.toSourceOutput(localData.maxTempIndex, output, localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals, localData.usedDeobfuscations);
localData.lineStartInstruction = lineStartItem.getVal();
}

View File

@@ -271,6 +271,7 @@ public abstract class InstructionDefinition implements Serializable {
/**
* Translates instruction to high level code.
*
* @param maxTempIndex Max temp index
* @param usedDeobfuscations Used deobfuscations
* @param swfVersion SWF version
* @param switchParts Switch parts
@@ -300,7 +301,7 @@ public abstract class InstructionDefinition implements Serializable {
* @param bottomSetLocals Bottom set locals
* @throws InterruptedException On interrupt
*/
public void translate(Set<String> usedDeobfuscations, int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, Reference<GraphSourceItem> lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, AVM2Instruction ins, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, AVM2Code code, boolean thisHasDefaultToPrimitive, LinkedIdentityHashSet<SetLocalAVM2Item> bottomSetLocals) throws InterruptedException {
public void translate(Reference<Integer> maxTempIndex, Set<String> usedDeobfuscations, int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, Reference<GraphSourceItem> lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, AVM2Instruction ins, List<GraphTargetItem> output, MethodBody body, ABC abc, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, String path, HashMap<Integer, Integer> localRegsAssignmentIps, int ip, AVM2Code code, boolean thisHasDefaultToPrimitive, LinkedIdentityHashSet<SetLocalAVM2Item> bottomSetLocals) throws InterruptedException {
AVM2LocalData localData = new AVM2LocalData();
localData.allSwitchParts = switchParts;
localData.isStatic = isStatic;
@@ -325,6 +326,7 @@ public abstract class InstructionDefinition implements Serializable {
localData.bottomSetLocals = bottomSetLocals;
localData.swfVersion = swfVersion;
localData.usedDeobfuscations = usedDeobfuscations;
localData.maxTempIndex = maxTempIndex;
translate(localData, stack, ins, output, path);
lineStartItem.setVal(localData.lineStartInstruction);
}

View File

@@ -29,6 +29,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.DuplicateSourceItem;
import com.jpexs.decompiler.graph.model.HasTempIndex;
import java.util.List;
/**
@@ -56,14 +57,23 @@ public class DupIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem v = stack.pop();
int temp = 0;
if (v instanceof NewActivationAVM2Item
|| v instanceof ExceptionAVM2Item) {
stack.push(v);
} else {
stack.push(new DuplicateSourceItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v));
if (v instanceof HasTempIndex) {
temp = ((HasTempIndex) v).getTempIndex();
stack.push(v);
} else {
temp = localData.maxTempIndex.getVal() + 1;
localData.maxTempIndex.setVal(temp);
stack.push(new DuplicateSourceItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v, temp));
}
}
//stack.push(v);
stack.push(new DuplicateItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v));
stack.push(new DuplicateItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, v, temp));
//v.moreSrc.add(new GraphSourceItemPos(ins, 0));
}

View File

@@ -30,9 +30,13 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.DuplicateSourceItem;
import com.jpexs.decompiler.graph.model.HasTempIndex;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SetTemporaryItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.TemporaryItem;
import java.util.List;
/**
@@ -65,11 +69,13 @@ public class SwapIns extends InstructionDefinition {
GraphTargetItem o2 = stack.pop();
/*stack.push(o1);
stack.push(o2);
o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
*/
/*if (true) {
stack.push(o1);
stack.push(o2);
o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
return;
}*/
if (((o1 instanceof ExceptionAVM2Item) && (o2 instanceof ExceptionAVM2Item))
||
(
@@ -94,6 +100,7 @@ public class SwapIns extends InstructionDefinition {
return;
}
/*
stack.finishBlock(output);
if (!(o2 instanceof PopItem)) {
output.add(new PushItem(o2));
@@ -101,7 +108,35 @@ public class SwapIns extends InstructionDefinition {
if (!(o2 instanceof PopItem && o1 instanceof PopItem)) {
output.add(new PushItem(o1));
}
output.add(new SwapItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction));
output.add(new SwapItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction));
*/
/*if (o2 instanceof HasTempIndex) {
stack.push(o1);
stack.push(o2);
return;
}*/
/*
if (o2 instanceof SetTemporaryItem || o2 instanceof DuplicateSourceItem) {
HasTempIndex ti = (HasTempIndex) o2;
stack.addToOutput(new SetTemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2.value, ti.getTempIndex(), "swap"));
stack.push(o1);
stack.push(new TemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, ti.getTempIndex()));
return;
}
if (o2 instanceof TemporaryItem || o2 instanceof DuplicateItem) {
stack.push(o1);
stack.push(o2);
return;
}
*/
int temp = localData.maxTempIndex.getVal() + 1;
localData.maxTempIndex.setVal(temp);
stack.finishBlock(output);
stack.addToOutput(new SetTemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, temp, "swap"));
stack.push(o1);
stack.push(new TemporaryItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction, o2, temp));
stack.finishBlock(output);
}
@Override

View File

@@ -2451,7 +2451,7 @@ public class ActionScript3Parser {
break;
//Both ASs
case "dup":
ret = new DuplicateItem(DIALECT, null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc));
ret = new DuplicateItem(DIALECT, null, null, expression(allOpenedNamespaces, thisType, pkg, needsActivation, importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables, false, abc), 0);
allowMemberOrCall = true;
break;
case "push":

View File

@@ -76,7 +76,9 @@ import com.jpexs.decompiler.graph.model.LabelItem;
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.SetTemporaryItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TemporaryItem;
import com.jpexs.decompiler.graph.model.TrueItem;
import com.jpexs.decompiler.graph.model.WhileItem;
import com.jpexs.helpers.Helper;
@@ -342,6 +344,17 @@ public class ActionGraph extends Graph {
}
}
}
if (it instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) it;
if (st.value instanceof GetPropertyActionItem) {
GetPropertyActionItem gp = (GetPropertyActionItem) st.value;
if (gp.propertyIndex == 11 /*_target*/) {
list.remove(t);
t--;
continue;
}
}
}
if (it instanceof SetTargetActionItem) {
SetTargetActionItem st = (SetTargetActionItem) it;
if (st.target.isEmpty()) {
@@ -362,6 +375,11 @@ public class ActionGraph extends Graph {
t--;
continue;
}
if (st.target instanceof TemporaryItem) {
list.remove(t);
t--;
continue;
}
if ((st.target instanceof DirectValueActionItem) && st.target.getResult().equals("")) {
if (targetStart > -1) {
targetEnd = t;

View File

@@ -1869,7 +1869,7 @@ public class ActionScript2Parser {
break;
//Both ASs
case "dup":
ret = new DuplicateItem(DIALECT, null, null, expression(inFunction, inMethod, inTellTarget, allowRemainder, variables, functions, false, hasEval));
ret = new DuplicateItem(DIALECT, null, null, expression(inFunction, inMethod, inTellTarget, allowRemainder, variables, functions, false, hasEval), 0);
allowMemberOrCall = true;
break;
case "push":

View File

@@ -68,7 +68,8 @@ public class ActionPushDuplicate extends Action {
@Override
public void translate(Set<String> usedDeobfuscations, Map<String, Map<String, Trait>> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) {
GraphTargetItem value = stack.peek();
stack.push(new DuplicateItem(ActionGraphTargetDialect.INSTANCE, this, lineStartAction, value));
//TODO: implement logic similar to Avm2
stack.push(new DuplicateItem(ActionGraphTargetDialect.INSTANCE, this, lineStartAction, value, 0));
value.getMoreSrc().add(new GraphSourceItemPos(this, 0));
}

View File

@@ -2390,7 +2390,7 @@ public class Graph {
*/
protected final void translatePart(List<GraphTargetItem> output, BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
List<GraphPart> sub = part.getSubParts();
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
int end;
for (GraphPart p : sub) {
if (p.end == -1) {
@@ -3370,7 +3370,7 @@ public class Graph {
if (code.size() <= part.start) {
if (!(!ret.isEmpty() && ret.get(ret.size() - 1) instanceof ExitItem)) {
stack.setConnectedOutput(0, ret);
stack.setConnectedOutput(0, ret, localData);
stack.addToOutput(new ScriptEndItem(dialect));
}
return ret;
@@ -3503,7 +3503,7 @@ public class Graph {
if (currentRet instanceof GraphPartMarkedArrayList) {
((GraphPartMarkedArrayList) currentRet).startPart(part);
}
stack.setConnectedOutput(0, currentRet);
stack.setConnectedOutput(0, currentRet, localData);
if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) {
parseNext = false;
} else {
@@ -3512,7 +3512,7 @@ public class Graph {
do {
exHappened = false;
try {
stack.setConnectedOutput(currentRet.size(), output);
stack.setConnectedOutput(currentRet.size(), output, localData);
code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path);
} catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts
//output.addAll(ex.getOutput());

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
@@ -23,11 +24,16 @@ import com.jpexs.decompiler.graph.model.BranchStackResistant;
import com.jpexs.decompiler.graph.model.BreakItem;
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.DuplicateSourceItem;
import com.jpexs.decompiler.graph.model.ExitItem;
import com.jpexs.decompiler.graph.model.HasTempIndex;
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.SetTemporaryItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.TemporaryItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -60,6 +66,8 @@ public class TranslateStack extends Stack<GraphTargetItem> {
private Map<String, GraphTargetItem> marks = new HashMap<>();
public List<GraphTargetItem> outputQueue = new ArrayList<>();
public BaseLocalData localData = null;
@Override
public synchronized Object clone() {
@@ -75,9 +83,10 @@ public class TranslateStack extends Stack<GraphTargetItem> {
}
public void setConnectedOutput(int prevOutputSize, List<GraphTargetItem> connectedOutput) {
public void setConnectedOutput(int prevOutputSize, List<GraphTargetItem> connectedOutput, BaseLocalData localData) {
this.prevOutputSize = prevOutputSize;
this.connectedOutput = connectedOutput;
this.localData = localData;
}
@Override
@@ -86,7 +95,7 @@ public class TranslateStack extends Stack<GraphTargetItem> {
if (item instanceof FindPropertyAVM2Item) {
finishBlock(connectedOutput);
} else {
outputQueue.add(item);
outputQueue.add(item);
item = new CommaExpressionItem(item.dialect, null, item.lineStartItem, outputQueue);
outputQueue = new ArrayList<>();
}
@@ -226,6 +235,39 @@ public class TranslateStack extends Stack<GraphTargetItem> {
connectedOutput.addAll(oldQueue);
}
if (isEmpty() && connectedOutput != null) {
for (int i = connectedOutput.size() - 1; i >= 0; i--) {
GraphTargetItem item = connectedOutput.get(i);
if (item instanceof Block) {
break;
}
if (item instanceof PushItem) {
PushItem pi = (PushItem) item;
if (pi.value instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) pi.value;
connectedOutput.set(i, st);
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, st.tempIndex);
} else if (pi.value instanceof DuplicateSourceItem) {
DuplicateSourceItem ds = (DuplicateSourceItem) pi.value;
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, ds.getSrc(), ds.getLineStartItem(), ds.value, ds.tempIndex,"push"));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), ds.value, ds.tempIndex);
} /*else if (pi.value instanceof DuplicateItem) {
DuplicateItem d = (DuplicateItem) pi.value;
//connectedOutput.remove(i);
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, d.getSrc(), d.getLineStartItem(), d.value, d.tempIndex));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, d.tempIndex);
} */else if (pi.value instanceof TemporaryItem) {
connectedOutput.remove(i);
return pi.value;
} else {
int temp = localData.maxTempIndex.getVal() + 1;
localData.maxTempIndex.setVal(temp);
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp, "push"));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp);
}
}
}
}
if (path != null) {
if (this.isEmpty()) {
@@ -260,10 +302,25 @@ public class TranslateStack extends Stack<GraphTargetItem> {
}
}
private boolean isAllTemp() {
for (int i = 0; i < size(); i++) {
GraphTargetItem item = get(i);
if (item instanceof TemporaryItem) {
continue;
}
if (item instanceof DuplicateItem) {
continue;
}
return false;
}
return true;
}
public void addToOutput(GraphTargetItem item) {
if (isEmpty()
|| peek() instanceof ExceptionAVM2Item
|| peek() instanceof NewActivationAVM2Item
//|| isAllTemp()
) {
connectedOutput.add(item);
return;
@@ -356,7 +413,7 @@ public class TranslateStack extends Stack<GraphTargetItem> {
if (output.size() < 3) {
return;
}
if (!(output.get(output.size() - 1) instanceof SwapItem)) {
if (!(output.get(output.size() - 1) instanceof PushItem)) {
return;
}
@@ -364,13 +421,34 @@ public class TranslateStack extends Stack<GraphTargetItem> {
return;
}
if (!(output.get(output.size() - 3) instanceof PushItem)) {
if (!(output.get(output.size() - 3) instanceof SetTemporaryItem)) {
return;
}
PushItem pi1 = (PushItem) output.get(output.size() - 1);
if (!(pi1.value instanceof TemporaryItem)) {
return;
}
TemporaryItem ti = (TemporaryItem) pi1.value;
SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 3);
if (!"swap".equals(st.getSuffix())) {
return;
}
if (st.getTempIndex() != ti.getTempIndex()) {
return;
}
PushItem pi2 = (PushItem) output.get(output.size() - 2);
output.remove(output.size() - 1);
push(((PushItem)output.remove(output.size() - 1)).value);
push(((PushItem)output.remove(output.size() - 1)).value);
output.remove(output.size() - 1);
output.remove(output.size() - 1);
push(pi2.value);
push(ti.value);
//moveToStack(output);
}
}

View File

@@ -33,8 +33,9 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DuplicateItem extends GraphTargetItem implements SimpleValue {
public class DuplicateItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
*
@@ -43,8 +44,9 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
* @param lineStartIns Line start item
* @param value Value
*/
public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) {
public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
@@ -62,9 +64,12 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
/*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
return value.appendTry(writer, localData);
}*/
writer.append("§§dup(");
value.appendTry(writer, localData);
return writer.append(")");
if (tempIndex == 0) {
writer.append("§§dup(");
value.appendTry(writer, localData);
return writer.append(")");
}
return writer.append("_temp_").append(tempIndex);
}
@Override
@@ -137,4 +142,8 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}

View File

@@ -34,7 +34,9 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue {
public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
@@ -44,10 +46,11 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
* @param lineStartIns Line start item
* @param value Value
*/
public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) {
public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
public Object getResult() {
return value.getResult();
@@ -63,9 +66,18 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
/*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
return value.appendTry(writer, localData);
}*/
writer.append("§§dupsrc(");
value.appendTry(writer, localData);
return writer.append(")");
if (tempIndex == 0) {
writer.append("§§dupsrc(");
value.appendTry(writer, localData);
return writer.append(")");
}
GraphTargetItem val = value;
while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) {
val = val.value;
}
writer.append("_tempdup_").append(tempIndex).append(" = ");
val.appendTry(writer, localData);
return writer;
}
@Override
@@ -138,4 +150,8 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010-2025 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.model;
/**
*
* @author JPEXS
*/
public interface HasTempIndex {
public int getTempIndex();
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (C) 2010-2025 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.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetDialect;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.SourceGenerator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Duplicate item.
*
* @author JPEXS
*/
public class SetTemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
private static final boolean SHOW_SUFFIX = false;
public int tempIndex;
private final String suffix;
public String getSuffix() {
return suffix;
}
/**
* Constructor.
*
* @param dialect Dialect
* @param src Source
* @param lineStartIns Line start item
* @param value Value
*/
public SetTemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex, String suffix) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
this.suffix = suffix;
}
@Override
public Object getResult() {
return value.getResult();
}
@Override
public Double getResultAsNumber() {
return value.getResultAsNumber();
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
GraphTargetItem val = value;
while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) {
val = val.value;
}
writer.append("_temp");
if (SHOW_SUFFIX) {
writer.append(suffix);
}
writer.append("_").append(tempIndex).append(" = ");
val.appendTry(writer, localData);
return writer;
}
@Override
public GraphTargetItem getNotCoerced() {
return value.getNotCoerced();
}
@Override
public GraphTargetItem getNotCoercedNoDup() {
return this;
}
@Override
public GraphTargetItem getThroughRegister() {
return value.getThroughRegister();
}
@Override
public GraphTargetItem getThroughDuplicate() {
return value.getThroughDuplicate();
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
if (dependencies.contains(value)) {
return false;
}
if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) {
dependencies.add(value);
}
return value.isCompileTime(dependencies);
}
@Override
public boolean isVariableComputed() {
return value.isVariableComputed();
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return new ArrayList<>();
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem simplify(String implicitCoerce) {
return this;
}
@Override
public GraphTargetItem returnType() {
return value.returnType();
}
@Override
public boolean isSimpleValue() {
return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue());
}
@Override
public boolean hasSideEffect() {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2010-2025 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.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetDialect;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.SourceGenerator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Duplicate item.
*
* @author JPEXS
*/
public class TemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
*
* @param dialect Dialect
* @param src Source
* @param lineStartIns Line start item
* @param value Value
*/
public TemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
public Object getResult() {
return value.getResult();
}
@Override
public Double getResultAsNumber() {
return value.getResultAsNumber();
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
return writer.append("_temp_").append(tempIndex);
}
@Override
public GraphTargetItem getNotCoerced() {
return value.getNotCoerced();
}
@Override
public GraphTargetItem getNotCoercedNoDup() {
return this;
}
@Override
public GraphTargetItem getThroughRegister() {
return value.getThroughRegister();
}
@Override
public GraphTargetItem getThroughDuplicate() {
return value.getThroughDuplicate();
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
if (dependencies.contains(value)) {
return false;
}
if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) {
dependencies.add(value);
}
return value.isCompileTime(dependencies);
}
@Override
public boolean isVariableComputed() {
return value.isVariableComputed();
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return new ArrayList<>();
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem simplify(String implicitCoerce) {
return this;
}
@Override
public GraphTargetItem returnType() {
return value.returnType();
}
@Override
public boolean isSimpleValue() {
return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue());
}
@Override
public boolean hasSideEffect() {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}