mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-19 00:38:13 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ package com.jpexs.decompiler.graph;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Graph source visitor interface.
|
||||
* Graph target visitor interface.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -100,7 +100,8 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
public void testDupAssignment() {
|
||||
decompileMethod("assembled", "testDupAssignment", "var _loc1_:int = 0;\r\n"
|
||||
+ "var _loc2_:int = 10;\r\n"
|
||||
+ "if(_loc1_ = _loc2_)\r\n"
|
||||
+ "_loc1_ = _loc2_;\r\n"
|
||||
+ "if(_loc1_)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(_loc2_);\r\n"
|
||||
+ "}\r\n",
|
||||
@@ -154,6 +155,16 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalRegIf() {
|
||||
decompileMethod("assembled", "testLocalRegIf", "var _loc1_:int = 8;\r\n"
|
||||
+ "if(_loc1_ > 5 && _loc1_ < 10)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"I\");\r\n"
|
||||
+ "}\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMutatingSwitch() {
|
||||
decompileMethod("assembled", "testMutatingSwitch", "switch(this.k)\r\n"
|
||||
|
||||
@@ -280,8 +280,8 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
+ "var dict:Dictionary = new Dictionary();\r\n"
|
||||
+ "s = \"a\";\r\n"
|
||||
+ "i = int(s);\r\n"
|
||||
+ "var j:int;\r\n"
|
||||
+ "s = String(j = n);\r\n"
|
||||
+ "var j:int = n;\r\n"
|
||||
+ "s = String(j);\r\n"
|
||||
+ "s = ns;\r\n"
|
||||
+ "s = String(i == 4 ? \"\" : i);\r\n"
|
||||
+ "s = i == 4 ? \"\" : String(i);\r\n"
|
||||
@@ -296,8 +296,8 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
+ "2:\"C\"\r\n"
|
||||
+ "};\r\n"
|
||||
+ "i = int(s.charAt(10));\r\n"
|
||||
+ "var v:Vector.<String>;\r\n"
|
||||
+ "(v = new Vector.<String>()).push(\"A\");\r\n"
|
||||
+ "var v:Vector.<String> = new Vector.<String>();\r\n"
|
||||
+ "v.push(\"A\");\r\n"
|
||||
+ "v.push(\"B\");\r\n"
|
||||
+ "i = int(v[0]);\r\n"
|
||||
+ "s = v[1];\r\n"
|
||||
@@ -321,11 +321,11 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
+ "trace(\"c\");\r\n"
|
||||
+ "i = int(x.item[i].@id);\r\n"
|
||||
+ "dict[String(x.item[i].@id)] = \"Hello\";\r\n"
|
||||
+ "var lc:LocalClass;\r\n"
|
||||
+ "i = (lc = new LocalClass()).attr;\r\n"
|
||||
+ "var lc:LocalClass = new LocalClass();\r\n"
|
||||
+ "i = lc.attr;\r\n"
|
||||
+ "s = String(lc.attr);\r\n"
|
||||
+ "var f:Function;\r\n"
|
||||
+ "if(Boolean(f = this.f))\r\n"
|
||||
+ "var f:Function = this.f;\r\n"
|
||||
+ "if(Boolean(f))\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"OK\");\r\n"
|
||||
+ "}\r\n"
|
||||
@@ -537,7 +537,8 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
decompileMethod("classic_air", "testExpressions", "var arr:Array = null;\r\n"
|
||||
+ "var i:int = 5;\r\n"
|
||||
+ "var j:int = 5;\r\n"
|
||||
+ "if((i = i /= 2) == 1 || i == 2)\r\n"
|
||||
+ "i = i /= 2;\r\n"
|
||||
+ "if(i == 1 || i == 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "arguments.concat(i);\r\n"
|
||||
+ "}\r\n"
|
||||
@@ -920,7 +921,8 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
+ "var b:int = 6;\r\n"
|
||||
+ "for(i = 0; i < len; k = myXML.book.(@isbn == \"12345\"))\r\n"
|
||||
+ "{\r\n"
|
||||
+ "if((c = 1) == 2)\r\n"
|
||||
+ "c = 1;\r\n"
|
||||
+ "if(c == 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"A\");\r\n"
|
||||
+ "}\r\n"
|
||||
@@ -1667,6 +1669,20 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptimization() {
|
||||
decompileMethod("classic_air", "testOptimization", "var f:int = 0;\r\n"
|
||||
+ "var g:* = 0;\r\n"
|
||||
+ "var h:int = 0;\r\n"
|
||||
+ "var a:int = 1;\r\n"
|
||||
+ "var b:int = 2;\r\n"
|
||||
+ "var c:int = 3;\r\n"
|
||||
+ "var d:int = 4;\r\n"
|
||||
+ "var e:int = d + 5;\r\n"
|
||||
+ "var i:int = h = g = f;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamNames() {
|
||||
decompileMethod("classic_air", "testParamNames", "return firstp + secondp + thirdp;\r\n",
|
||||
@@ -2327,12 +2343,12 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
|
||||
@Test
|
||||
public void testXml() {
|
||||
decompileMethod("classic_air", "testXml", "var name:String = \"ahoj\";\r\n"
|
||||
+ "var myXML:XML;\r\n"
|
||||
+ "var k:* = (myXML = <order id=\"604\">\r\n"
|
||||
+ "var myXML:XML = <order id=\"604\">\r\n"
|
||||
+ "<book isbn=\"12345\">\r\n"
|
||||
+ "<title>{name}</title>\r\n"
|
||||
+ "</book>\r\n"
|
||||
+ "</order>).@id;\r\n"
|
||||
+ "</order>;\r\n"
|
||||
+ "var k:* = myXML.@id;\r\n"
|
||||
+ "var all:String = myXML.@*.toXMLString();\r\n"
|
||||
+ "k = myXML.book;\r\n"
|
||||
+ "k = myXML.book.(@isbn == \"12345\");\r\n"
|
||||
|
||||
@@ -539,7 +539,8 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
decompileMethod("classic", "testExpressions", "var arr:Array = null;\r\n"
|
||||
+ "var i:int = 5;\r\n"
|
||||
+ "var j:int = 5;\r\n"
|
||||
+ "if((i = i = i / 2) == 1 || i == 2)\r\n"
|
||||
+ "i = i = i / 2;\r\n"
|
||||
+ "if(i == 1 || i == 2)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "arguments.concat(i);\r\n"
|
||||
+ "}\r\n"
|
||||
@@ -1654,6 +1655,20 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptimization() {
|
||||
decompileMethod("classic", "testOptimization", "var f:int = 0;\r\n"
|
||||
+ "var g:int = 0;\r\n"
|
||||
+ "var h:int = 0;\r\n"
|
||||
+ "var a:int = 1;\r\n"
|
||||
+ "var b:int = 2;\r\n"
|
||||
+ "var c:int = 3;\r\n"
|
||||
+ "var d:int = 4;\r\n"
|
||||
+ "var e:int = d + 5;\r\n"
|
||||
+ "var i:int = h = g = f;\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamNames() {
|
||||
decompileMethod("classic", "testParamNames", "return firstp + secondp + thirdp;\r\n",
|
||||
|
||||
@@ -522,8 +522,8 @@ public class ActionScript3CrossCompileSwfToolsDecompileTest extends ActionScript
|
||||
public void testTryCatchWith() {
|
||||
decompileMethod("swftools", "testTryCatchWith", "var _loc1_:* = new MyTest();\r\n"
|
||||
+ "trace(\"before with\");\r\n"
|
||||
+ "var _loc2_:*;\r\n"
|
||||
+ "with(_loc2_ = _loc1_)\r\n"
|
||||
+ "var _loc2_:* = _loc1_;\r\n"
|
||||
+ "with(_loc2_)\r\n"
|
||||
+ "{\r\n"
|
||||
+ "trace(\"before try\");\r\n"
|
||||
+ "try\r\n"
|
||||
|
||||
Binary file not shown.
@@ -34,5 +34,6 @@ program
|
||||
#include "tests/TestMutatingSwitch.script.asasm"
|
||||
#include "tests/TestSwitchMostCommon.script.asasm"
|
||||
#include "tests/TestXmlStar.script.asasm"
|
||||
#include "tests/TestLocalRegIf.script.asasm"
|
||||
; place to add next
|
||||
end ; program
|
||||
|
||||
80
libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLocalRegIf.class.asasm
vendored
Normal file
80
libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLocalRegIf.class.asasm
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
class
|
||||
refid "tests:TestLocalRegIf"
|
||||
instance QName(PackageNamespace("tests"), "TestLocalRegIf")
|
||||
extends QName(PackageNamespace(""), "Object")
|
||||
flag SEALED
|
||||
flag PROTECTEDNS
|
||||
protectedns ProtectedNamespace("tests:TestLocalRegIf")
|
||||
iinit
|
||||
refid "tests:TestLocalRegIf/instance/init"
|
||||
body
|
||||
maxstack 1
|
||||
localcount 1
|
||||
initscopedepth 4
|
||||
maxscopedepth 5
|
||||
code
|
||||
getlocal0
|
||||
pushscope
|
||||
|
||||
getlocal0
|
||||
constructsuper 0
|
||||
|
||||
returnvoid
|
||||
end ; code
|
||||
end ; body
|
||||
end ; method
|
||||
trait method QName(PackageNamespace(""), "run")
|
||||
method
|
||||
refid "tests:TestLocalRegIf/instance/run"
|
||||
returns QName(PackageNamespace(""), "void")
|
||||
body
|
||||
maxstack 2
|
||||
localcount 7
|
||||
initscopedepth 4
|
||||
maxscopedepth 5
|
||||
code
|
||||
getlocal0
|
||||
pushscope
|
||||
pushbyte 8
|
||||
dup
|
||||
setlocal1
|
||||
pushbyte 5
|
||||
greaterthan
|
||||
dup
|
||||
iffalse ofs0020
|
||||
pop
|
||||
getlocal1
|
||||
pushbyte 10
|
||||
lessthan
|
||||
ofs0020:
|
||||
iffalse ofs0030
|
||||
getlex QName(PackageNamespace(""),"trace")
|
||||
getglobalscope
|
||||
pushstring "I"
|
||||
call 1
|
||||
pop
|
||||
ofs0030:
|
||||
returnvoid
|
||||
|
||||
returnvoid
|
||||
end ; code
|
||||
end ; body
|
||||
end ; method
|
||||
end ; trait
|
||||
end ; instance
|
||||
cinit
|
||||
refid "tests:TestLocalRegIf/class/init"
|
||||
body
|
||||
maxstack 1
|
||||
localcount 1
|
||||
initscopedepth 3
|
||||
maxscopedepth 4
|
||||
code
|
||||
getlocal0
|
||||
pushscope
|
||||
|
||||
returnvoid
|
||||
end ; code
|
||||
end ; body
|
||||
end ; method
|
||||
end ; class
|
||||
29
libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLocalRegIf.script.asasm
vendored
Normal file
29
libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLocalRegIf.script.asasm
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
script
|
||||
sinit
|
||||
refid "tests:TestLocalRegIf/init"
|
||||
body
|
||||
maxstack 2
|
||||
localcount 1
|
||||
initscopedepth 1
|
||||
maxscopedepth 3
|
||||
code
|
||||
getlocal0
|
||||
pushscope
|
||||
|
||||
findpropstrict Multiname("TestLocalRegIf", [PackageNamespace("tests")])
|
||||
getlex QName(PackageNamespace(""), "Object")
|
||||
pushscope
|
||||
|
||||
getlex Multiname("Object", [PrivateNamespace(null, "tests:TestLocalRegIf"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")])
|
||||
newclass "tests:TestLocalRegIf"
|
||||
popscope
|
||||
initproperty QName(PackageNamespace("tests"), "TestLocalRegIf")
|
||||
|
||||
returnvoid
|
||||
end ; code
|
||||
end ; body
|
||||
end ; method
|
||||
trait class QName(PackageNamespace("tests"), "TestLocalRegIf")
|
||||
#include "TestLocalRegIf.class.asasm"
|
||||
end ; trait
|
||||
end ; script
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,4 +2,6 @@
|
||||
set COMPILERKIND=air
|
||||
set SWFNAME=as3_new
|
||||
call c:\air\bin\mxmlc.bat -debug=true -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
|
||||
rem -warnings=false
|
||||
rem set COMPILERKIND=air.optimize
|
||||
rem call c:\air\bin\mxmlc.bat -compiler.optimize -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
|
||||
rem -warnings=false
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
set COMPILERKIND=flex
|
||||
set SWFNAME=as3_new
|
||||
call c:\flex\bin\mxmlc.bat -debug=true -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
|
||||
rem set COMPILERKIND=flex.optimize
|
||||
rem call c:\flex\bin\mxmlc.bat -compiler.optimize -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
|
||||
rem -warnings=false
|
||||
|
||||
@@ -97,6 +97,7 @@ package
|
||||
TestNegate;
|
||||
TestNumberCall;
|
||||
TestOperations;
|
||||
TestOptimization;
|
||||
TestOptionalParameters;
|
||||
TestParamNames;
|
||||
TestParamsCount;
|
||||
|
||||
@@ -5,7 +5,7 @@ package tests
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
trace("hello");
|
||||
trace("hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestOptimization.as
vendored
Normal file
25
libsrc/ffdec_lib/testdata/as3_new/src/tests/TestOptimization.as
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package tests
|
||||
{
|
||||
|
||||
public class TestOptimization
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
// Add more than 3 variables.
|
||||
// Optimization happens from register 4 on.
|
||||
// (setlocal X takes more bytes than dup)
|
||||
var a:int = 1;
|
||||
var b:int = 2;
|
||||
var c:int = 3;
|
||||
|
||||
var d:int = 4; //setlocal N
|
||||
var e:int = d + 5; //getlocal N is replaced with dup before setlocal N
|
||||
|
||||
//We must leave this case intact:
|
||||
var f:int;
|
||||
var g:int;
|
||||
var h:int;
|
||||
var i:int = h = g = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user