Fixed: #2270 AS3 decompilation - unnnecessary local registers assignments as part of expressions when using optimization like dup, setlocal N instead of setlocal N, getlocal N

This commit is contained in:
Jindra Petřík
2024-08-12 17:50:16 +02:00
parent 02baf4baa6
commit 16ff10a890
31 changed files with 487 additions and 58 deletions

View File

@@ -20,6 +20,7 @@ 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.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
@@ -30,6 +31,7 @@ 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 com.jpexs.helpers.LinkedIdentityHashSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -221,6 +223,12 @@ public class AVM2LocalData extends BaseLocalData {
*/
public Set<Integer> seenMethods = new HashSet<>();
/**
* Bottom set locals
*/
public LinkedIdentityHashSet<SetLocalAVM2Item> bottomSetLocals = new LinkedIdentityHashSet<>();
/**
* Constructs a new AVM2LocalData
*/
@@ -287,6 +295,7 @@ public class AVM2LocalData extends BaseLocalData {
pushDefaultPart = localData.pushDefaultPart;
finallyKinds = localData.finallyKinds;
seenMethods = localData.seenMethods;
bottomSetLocals = localData.bottomSetLocals;
}
/**

View File

@@ -289,6 +289,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.graph.AbstractGraphTargetRecursiveVisitor;
import com.jpexs.decompiler.graph.AbstractGraphTargetVisitor;
import com.jpexs.decompiler.graph.Block;
import com.jpexs.decompiler.graph.DottedChain;
@@ -302,6 +303,7 @@ import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.ScriptEndItem;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.LinkedIdentityHashSet;
import com.jpexs.helpers.Reference;
import com.jpexs.helpers.ReflectionTools;
import com.jpexs.helpers.stat.Statistics;
@@ -320,6 +322,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -1842,11 +1845,12 @@ public class AVM2Code implements Cloneable {
* @param fullyQualifiedNames Fully qualified names
* @param visited Visited
* @param localRegAssigmentIps Local register assignment IPs
* @param bottomStackSetLocals Set locals on bottom of the stack
* @return Convert output
* @throws ConvertException On convert error
* @throws InterruptedException On interrupt
*/
public ConvertOutput toSourceOutput(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> localRegAssigmentIps) throws ConvertException, InterruptedException {
public ConvertOutput toSourceOutput(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> localRegAssigmentIps, LinkedIdentityHashSet<SetLocalAVM2Item> bottomStackSetLocals) 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());
@@ -1901,26 +1905,13 @@ public class AVM2Code implements Cloneable {
}
}
}
/*if ((ins.definition instanceof SetLocalTypeIns) && (ip + 1 <= end)) { // set_local_x,get_local_x.. no other local_x get
AVM2Instruction insAfter = code.get(ip + 1);
Set<Integer> usages = setLocalPosToGetLocalPos.containsKey(ip) ? setLocalPosToGetLocalPos.get(ip) : new HashSet<>();
if (!(stack.peek().getNotCoercedNoDup() instanceof DuplicateItem) && !AVM2Item.mustStayIntact2(stack.peek()) && usages.size() == 1 && (usages.iterator().next().equals(ip + 1)) && (insAfter.definition instanceof GetLocalTypeIns) && (((GetLocalTypeIns) insAfter.definition).getRegisterId(insAfter) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins))) {
ip += 2;
continue iploop;
} else {
ins.definition.translate(setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive);
ip++;
continue iploop;
}
} else*/
/*
if (ins.definition instanceof DupIns) {
int nextPos;
do {
AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null;
if (insAfter == null) {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
ip++;
break;
}
@@ -1942,14 +1933,16 @@ public class AVM2Code implements Cloneable {
//stack.add("(" + stack.pop() + ")||");
isAnd = false;
} else {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
ip++;
break;
//throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString());
}
} while (ins.definition instanceof DupIns);
} else if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive);
} else
*/
if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
//ip = end + 1;
break;
} else if (ins.definition instanceof NewFunctionIns) {
@@ -1985,13 +1978,18 @@ public class AVM2Code implements Cloneable {
}
}
// What to do when hasDup is false?
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive);
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek();
nft.functionName = functionName;
ip++;
} else {
try {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive);
try {
ins.definition.translate(switchParts, callStack, abcIndex, setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, localScopeStack, ins, output, body, abc, localRegNames, localRegTypes, fullyQualifiedNames, path, localRegAssigmentIps, ip, this, thisHasDefaultToPrimitive, bottomStackSetLocals);
if (stack.size() == 1 && (stack.peek() instanceof SetLocalAVM2Item)) {
bottomStackSetLocals.add((SetLocalAVM2Item) stack.peek());
}
} catch (RuntimeException re) {
/*String last="";
int len=5;
@@ -2281,9 +2279,9 @@ public class AVM2Code implements Cloneable {
break;
}*/
Reference<Boolean> hasPrevReference = new Reference<>(false);
value.visitRecursivelyNoBlock(new AbstractGraphTargetVisitor() {
value.visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() {
@Override
public void visit(GraphTargetItem subItem) {
public void visit(GraphTargetItem subItem, Stack<GraphTargetItem> parentStack) {
Multiname propertyMultiName;
String propertyName;
if (subItem instanceof GetPropertyAVM2Item) {
@@ -2343,9 +2341,9 @@ public class AVM2Code implements Cloneable {
GraphTargetItem currentItem = items.get(i);
List<GraphTargetItem> itemsOnLine = new ArrayList<>();
itemsOnLine.add(currentItem);
currentItem.visitRecursivelyNoBlock(new AbstractGraphTargetVisitor() {
currentItem.visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() {
@Override
public void visit(GraphTargetItem item) {
public void visit(GraphTargetItem item, Stack<GraphTargetItem> parentStack) {
itemsOnLine.add(item);
}
});

View File

@@ -17,7 +17,9 @@
package com.jpexs.decompiler.flash.abc.avm2;
import com.jpexs.decompiler.flash.FinalProcessLocalData;
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.helpers.LinkedIdentityHashSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -40,6 +42,11 @@ public class AVM2FinalProcessLocalData extends FinalProcessLocalData {
* Set local position to get local position mapping.
*/
public Map<Integer, Set<Integer>> setLocalPosToGetLocalPos = new HashMap<>();
/**
* Bottom set locals
*/
public LinkedIdentityHashSet<SetLocalAVM2Item> bottomSetLocals = new LinkedIdentityHashSet<>();
/**
* Constructs AVM2 final process local data.
@@ -49,11 +56,13 @@ public class AVM2FinalProcessLocalData extends FinalProcessLocalData {
* mapping
* @param setLocalPosToGetLocalPos Set local position to get local position
* mapping
* @param bottomSetLocals Bottom set locals
*/
public AVM2FinalProcessLocalData(List<Loop> loops, HashMap<Integer, String> localRegNames, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos) {
public AVM2FinalProcessLocalData(List<Loop> loops, HashMap<Integer, String> localRegNames, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, LinkedIdentityHashSet<SetLocalAVM2Item> bottomSetLocals) {
super(loops);
this.localRegNames = localRegNames;
this.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos;
this.bottomSetLocals = bottomSetLocals;
}
/**

View File

@@ -48,7 +48,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ConstructAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
@@ -81,6 +83,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictEqAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.graph.AbstractGraphTargetRecursiveVisitor;
import com.jpexs.decompiler.graph.AbstractGraphTargetVisitor;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.Graph;
@@ -122,6 +125,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Level;
@@ -2641,6 +2645,51 @@ public class AVM2Graph extends Graph {
}
}
AVM2FinalProcessLocalData adata = (AVM2FinalProcessLocalData) localData;
//if(false)
if (!adata.bottomSetLocals.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof LoopItem) {
continue;
}
if (list.get(i) instanceof WithEndAVM2Item) {
continue;
}
Reference<SetLocalAVM2Item> foundSetLoc = new Reference<>(null);
list.get(i).visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() {
@Override
public void visit(GraphTargetItem item, Stack<GraphTargetItem> parentStack) {
if (item instanceof SetLocalAVM2Item) {
if (adata.bottomSetLocals.contains((SetLocalAVM2Item) item)) {
int s = parentStack.size() - 1;
if (parentStack.get(s) instanceof CoerceAVM2Item) {
s--;
} else if (parentStack.get(s) instanceof ConvertAVM2Item) {
s--;
}
if (s >= 0) {
GraphTargetItem parent = parentStack.get(s);
if (!(parent instanceof SetTypeAVM2Item)) { //not a chained assignment
foundSetLoc.setVal((SetLocalAVM2Item) item);
}
}
}
}
}
});
if (foundSetLoc.getVal() != null) {
SetLocalAVM2Item setLoc = foundSetLoc.getVal();
list.add(i, setLoc.clone());
setLoc.hideValue = true;
i++;
}
}
}
/*
convert this situation:
@@ -2656,13 +2705,13 @@ public class AVM2Graph extends Graph {
It's TestSwapAssignment assembled test case.
*/
for (int i = 0; i < list.size(); i++) {
/*for (int i = 0; i < list.size(); i++) {
GraphTargetItem item = list.get(i);
Map<Integer, List<SetLocalAVM2Item>> setRegisters = new HashMap<>();
item.visitRecursivelyNoBlock(new AbstractGraphTargetVisitor() {
item.visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() {
@Override
public void visit(GraphTargetItem item) {
public void visit(GraphTargetItem item, GraphTargetItem parent) {
if (item instanceof SetLocalAVM2Item) {
SetLocalAVM2Item setLoc = (SetLocalAVM2Item) item;
if (setLoc.causedByDup) {
@@ -2770,15 +2819,15 @@ public class AVM2Graph extends Graph {
});
i = newI.getVal();
}
*/
//Handle for loops at the end:
super.finalProcess(list, level, localData, path);
}
@Override
protected FinalProcessLocalData getFinalData(BaseLocalData localData, List<Loop> loops, List<ThrowState> throwStates) {
FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames, ((AVM2LocalData) localData).setLocalPosToGetLocalPos);
finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos;
FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).bottomSetLocals);
finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos;
return finalProcess;
}
@@ -3081,4 +3130,37 @@ public class AVM2Graph extends Graph {
protected SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
return new SecondPassData();
}
@Override
protected GraphTargetItem getIfExpression(BaseLocalData localData, TranslateStack stack, List<GraphTargetItem> output) {
GraphTargetItem result = stack.pop();
/*
Fixes this case:
var i:int;
if ((i = 5) > 2 && i < 10) {
...
}
when instead
setlocal x
getlocal x
there is:
dup
setlocal x
*/
if (stack.getMark("firstSetLocal") != null) {
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) stack.getMark("firstSetLocal");
if (setLocal.directlyCausedByDup) {
output.add(setLocal.clone());
setLocal.hideValue = true;
}
}
return result;
}
}

View File

@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.ConvertOutput;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.Graph;
@@ -30,6 +31,7 @@ import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.helpers.LinkedIdentityHashSet;
import com.jpexs.helpers.Reference;
import java.util.ArrayList;
import java.util.HashMap;
@@ -203,7 +205,7 @@ public class AVM2GraphSource extends GraphSource {
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
List<GraphTargetItem> ret = new ArrayList<>();
Reference<GraphSourceItem> lineStartItem = new Reference<>(localData.lineStartInstruction);
ConvertOutput co = code.toSourceOutput(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()], localRegAssigmentIps);
ConvertOutput co = code.toSourceOutput(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()], localRegAssigmentIps, ((AVM2LocalData) localData).bottomSetLocals);
localData.lineStartInstruction = lineStartItem.getVal();
ret.addAll(co.output);
return ret;

View File

@@ -62,6 +62,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.helpers.LinkedIdentityHashSet;
import com.jpexs.helpers.Reference;
import java.io.Serializable;
import java.util.ArrayList;
@@ -290,9 +291,10 @@ public abstract class InstructionDefinition implements Serializable {
* @param ip IP
* @param code AVM2 code
* @param thisHasDefaultToPrimitive This has default to primitive
* @param bottomSetLocals Bottom set locals
* @throws InterruptedException On interrupt
*/
public void translate(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) throws InterruptedException {
public void translate(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;
@@ -314,6 +316,7 @@ public abstract class InstructionDefinition implements Serializable {
localData.code = code;
localData.thisHasDefaultToPrimitive = thisHasDefaultToPrimitive;
localData.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos;
localData.bottomSetLocals = bottomSetLocals;
translate(localData, stack, ins, output, path);
lineStartItem.setVal(localData.lineStartInstruction);
}

View File

@@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.CompoundableBinaryOp;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.PopItem;
import java.util.List;
@@ -145,6 +146,10 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
}
}
}
if (value instanceof DuplicateItem) {
result.directlyCausedByDup = true;
}
SetTypeIns.handleResult(value, stack, output, localData, result, regId, value.returnType());
}

View File

@@ -72,6 +72,11 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig
* Caused by duplicate
*/
public boolean causedByDup = false;
/**
* Directly caused by duplicate
*/
public boolean directlyCausedByDup = false;
@Override
public DeclarationAVM2Item getDeclaration() {

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph;
import java.util.Collection;
import java.util.Stack;
/**
* Abstract graph target recursive visitor.
*
* @author JPEXS
*/
public abstract class AbstractGraphTargetRecursiveVisitor implements GraphTargetRecursiveVisitorInterface {
/**
* Constructs new AbstractGraphTargetVisitor
*/
public AbstractGraphTargetRecursiveVisitor() {
}
@Override
public abstract void visit(GraphTargetItem item, Stack<GraphTargetItem> parentStack);
@Override
public final void visitAll(Collection<GraphTargetItem> items, Stack<GraphTargetItem> parentStack) {
for (GraphTargetItem item : items) {
visit(item, parentStack);
}
}
}

View File

@@ -2715,6 +2715,18 @@ public class Graph {
return printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, stopPartKind, loops, throwStates, null, staticOperation, path, 0);
}
/**
* Gets if expression from stack.
* Can be overriden for custom handling
* @param localData Local data
* @param stack Stack
* @param output Output
* @return Expression
*/
protected GraphTargetItem getIfExpression(BaseLocalData localData, TranslateStack stack, List<GraphTargetItem> output) {
return stack.pop();
}
/**
* Walks graph parts and converts them to target items.
*
@@ -3254,7 +3266,7 @@ public class Graph {
} //else
GraphPart nextOnePart = null;
if (getNextParts(localData, part).size() == 2 && !partIsSwitch(part)) {
GraphTargetItem expr = stack.pop();
GraphTargetItem expr = getIfExpression(localData, stack, currentRet);
if (nextOnePart == null) {

View File

@@ -48,6 +48,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
/**
* Graph target item - an item in high level representation of the code.
@@ -963,15 +964,19 @@ public abstract class GraphTargetItem implements Serializable, Cloneable {
*
* @param visitor Visitor
*/
public final void visitRecursivelyNoBlock(GraphTargetVisitorInterface visitor) {
public final void visitRecursivelyNoBlock(GraphTargetRecursiveVisitorInterface visitor) {
Set<GraphTargetItem> visitedItems = new HashSet<>();
Stack<GraphTargetItem> parentStack = new Stack<>();
parentStack.add(this);
visitNoBlock(new AbstractGraphTargetVisitor() {
@Override
public void visit(GraphTargetItem item) {
if (item != null && !visitedItems.contains(item)) {
visitedItems.add(item);
visitor.visit(item);
visitor.visit(item, parentStack);
parentStack.push(item);
item.visitNoBlock(this);
parentStack.pop();
}
}
});

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph;
import java.util.Collection;
import java.util.Stack;
/**
* Recursive graph target visitor interface.
*
* @author JPEXS
*/
public interface GraphTargetRecursiveVisitorInterface {
/**
* Visits a graph target item.
*
* @param item Graph target item
* @param parentStack Stack of parents
*/
public void visit(GraphTargetItem item, Stack<GraphTargetItem> parentStack);
/**
* Visits all graph target items.
*
* @param items Collection of graph target items
* @param parentStack Stack of parents
*/
public void visitAll(Collection<GraphTargetItem> items, Stack<GraphTargetItem> parentStack);
}

View File

@@ -19,7 +19,7 @@ package com.jpexs.decompiler.graph;
import java.util.Collection;
/**
* Graph source visitor interface.
* Graph target visitor interface.
*
* @author JPEXS
*/

View File

@@ -17,6 +17,10 @@
package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.graph.model.PopItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -38,6 +42,27 @@ public class TranslateStack extends Stack<GraphTargetItem> {
*/
private final String path;
private Map<String, GraphTargetItem> marks = new HashMap<>();
/**
* Sets mark.
* @param name Name
* @param value Value
*/
public void setMark(String name, GraphTargetItem value) {
marks.put(name, value);
}
/**
* Gets mark.
* @param name Name
* @return Value
*/
public GraphTargetItem getMark(String name) {
return marks.get(name);
}
/**
* Simplifies all items in the stack.
*/