diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index c5389d911..86bcc370d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1651,9 +1651,6 @@ public class AVM2Code implements Cloneable { Set usages = setLocalPosToGetLocalPos.get(ip); if (usages.size() == 1 && (usages.iterator().next().equals(ip + 1)) && (insAfter.definition instanceof GetLocalTypeIns) && (((GetLocalTypeIns) insAfter.definition).getRegisterId(insAfter) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins))) { - /*GraphTargetItem before = stack.peek(); - ins.definition.translate(setLocalPosToGetLocalPos, lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); - stack.push(before);*/ ip += 2; continue iploop; } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index bc7493a89..e5e4fd1eb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -27,10 +27,17 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictEqIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.DecLocalIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecLocalPIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncLocalPIns; import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item; @@ -161,8 +168,28 @@ public class AVM2Graph extends Graph { registerToLastSetLocalPos.put(regId, ip); setLocalPosToGetLocalPos.put(ip, new TreeSet<>()); } + List usedRegs = new ArrayList<>(); if (ins.definition instanceof GetLocalTypeIns) { int regId = ((GetLocalTypeIns) ins.definition).getRegisterId(ins); + usedRegs.add(regId); + } + if ((ins.definition instanceof IncLocalIns) + || (ins.definition instanceof IncLocalIIns) + || (ins.definition instanceof IncLocalPIns) + || (ins.definition instanceof DecLocalIns) + || (ins.definition instanceof DecLocalIIns) + || (ins.definition instanceof DecLocalPIns)) { + usedRegs.add(ins.operands[0]); + } + if ((ins.definition instanceof IncLocalPIns) + || (ins.definition instanceof DecLocalPIns)) { + usedRegs.add(ins.operands[1]); + } + if (ins.definition instanceof HasNext2Ins) { + usedRegs.add(ins.operands[0]); + usedRegs.add(ins.operands[1]); + } + for (int regId : usedRegs) { if (registerToLastSetLocalPos.containsKey(regId)) { int setLocalPos = registerToLastSetLocalPos.get(regId); setLocalPosToGetLocalPos.get(setLocalPos).add(ip); @@ -564,7 +591,7 @@ public class AVM2Graph extends Graph { } ret = new ArrayList<>(); ret.addAll(output); - GraphTargetItem lop = checkLoop(part, stopPart, loops); + GraphTargetItem lop = checkLoop(new ArrayList(), part, stopPart, loops); if (lop == null) { TranslateStack st = (TranslateStack) stack.clone(); st.clear(); @@ -777,7 +804,7 @@ public class AVM2Graph extends Graph { List> caseCommands = new ArrayList<>(); GraphPart next = breakPart; - GraphTargetItem ti = checkLoop(next, stopPart, loops); + GraphTargetItem ti = checkLoop(new ArrayList() /*??*/, next, stopPart, loops); //create switch as new loop break command detection to work currentLoop = new Loop(loops.size(), null, next); @@ -964,7 +991,7 @@ public class AVM2Graph extends Graph { @Override - protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List loops) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops) { AVM2LocalData aLocalData = (AVM2LocalData) localData; if (loopItem instanceof WhileItem) { WhileItem w = (WhileItem) loopItem; @@ -1007,10 +1034,97 @@ public class AVM2Graph extends Graph { if (w.commands.get(0) instanceof SetTypeAVM2Item) { SetTypeAVM2Item sti = (SetTypeAVM2Item) w.commands.remove(0); GraphTargetItem gti = sti.getValue().getNotCoerced(); + GraphTargetItem varName = sti.getObject(); + GraphTargetItem collection = hn.obj; + + if (hn.obj instanceof LocalRegAVM2Item) { + int objRegIndex = ((LocalRegAVM2Item) hn.obj).regIndex; + for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) { + if (output.get(i) instanceof SetLocalAVM2Item) { + SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i); + if (setLocal.regIndex == objRegIndex) { + int setLocalIp = aLocalData.code.adr2pos(setLocal.getSrc().getAddress()); + Set objUsages = new HashSet<>(aLocalData.setLocalPosToGetLocalPos.get(setLocalIp)); + int hnUsageIp = aLocalData.code.adr2pos(hn.getSrc().getAddress()); + objUsages.remove(hnUsageIp); + + if (gti instanceof NextValueAVM2Item) { + NextValueAVM2Item nextVal = (NextValueAVM2Item) gti; + if (nextVal.obj instanceof LocalRegAVM2Item) { + LocalRegAVM2Item nextValObjReg = (LocalRegAVM2Item) nextVal.obj; + if (nextValObjReg.regIndex == objRegIndex) { + int nextValUsage = aLocalData.code.adr2pos(nextValObjReg.getSrc().getAddress()); + objUsages.remove(nextValUsage); + } + } + } + if (gti instanceof NextNameAVM2Item) { + NextNameAVM2Item nextName = (NextNameAVM2Item) gti; + if (nextName.obj instanceof LocalRegAVM2Item) { + LocalRegAVM2Item nextValObjReg = (LocalRegAVM2Item) nextName.obj; + if (nextValObjReg.regIndex == objRegIndex) { + int nextNameUsage = aLocalData.code.adr2pos(nextValObjReg.getSrc().getAddress()); + objUsages.remove(nextNameUsage); + } + } + } + if (objUsages.isEmpty()) { + output.remove(i); + collection = setLocal.value; + } + } + } else { + break; + } + } + } + + if (hn.index instanceof LocalRegAVM2Item) { + int indexRegIndex = ((LocalRegAVM2Item) hn.index).regIndex; + for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) { + if (output.get(i) instanceof SetLocalAVM2Item) { + SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i); + if (setLocal.regIndex == indexRegIndex) { + int setLocalIp = aLocalData.code.adr2pos(setLocal.getSrc().getAddress()); + Set objUsages = new HashSet<>(aLocalData.setLocalPosToGetLocalPos.get(setLocalIp)); + int hnUsageIp = aLocalData.code.adr2pos(hn.getSrc().getAddress()); + objUsages.remove(hnUsageIp); + + if (gti instanceof NextValueAVM2Item) { + NextValueAVM2Item nextVal = (NextValueAVM2Item) gti; + if (nextVal.index instanceof LocalRegAVM2Item) { + LocalRegAVM2Item nextValIndexReg = (LocalRegAVM2Item) nextVal.index; + if (nextValIndexReg.regIndex == indexRegIndex) { + int nextValUsage = aLocalData.code.adr2pos(nextValIndexReg.getSrc().getAddress()); + objUsages.remove(nextValUsage); + } + } + } + if (gti instanceof NextNameAVM2Item) { + NextNameAVM2Item nextName = (NextNameAVM2Item) gti; + if (nextName.index instanceof LocalRegAVM2Item) { + LocalRegAVM2Item nextValIndexReg = (LocalRegAVM2Item) nextName.index; + if (nextValIndexReg.regIndex == indexRegIndex) { + int nextNameUsage = aLocalData.code.adr2pos(nextValIndexReg.getSrc().getAddress()); + objUsages.remove(nextNameUsage); + } + } + } + if (objUsages.isEmpty()) { + output.remove(i); + } + } + } else { + break; + } + } + } + + if (gti instanceof NextValueAVM2Item) { - return new ForEachInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), sti.getObject(), ((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).obj), w.commands); + return new ForEachInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), varName, collection), w.commands); } else if (gti instanceof NextNameAVM2Item) { - return new ForInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), sti.getObject(), ((HasNextAVM2Item) w.expression.get(w.expression.size() - 1)).obj), w.commands); + return new ForInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), varName, collection), w.commands); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/HasNext2Ins.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/HasNext2Ins.java index 03f37a6ea..f30f50a63 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/HasNext2Ins.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/HasNext2Ins.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.abc.avm2.instructions.other; import com.jpexs.decompiler.flash.abc.ABC; @@ -41,7 +42,10 @@ public class HasNext2Ins extends InstructionDefinition { int objectReg = ins.operands[0]; int indexReg = ins.operands[1]; //stack.push("_loc_" + objectReg + ".hasNext(cnt=_loc_" + indexReg + ")"); - stack.push(new HasNextAVM2Item(ins, localData.lineStartInstruction, new LocalRegAVM2Item(ins, localData.lineStartInstruction, indexReg, localData.localRegs.get(indexReg)), localData.localRegNames.containsKey(objectReg) ? new LocalRegAVM2Item(ins, localData.lineStartInstruction, objectReg, localData.localRegs.get(objectReg)) : localData.localRegs.get(objectReg))); + stack.push(new HasNextAVM2Item(ins, localData.lineStartInstruction, + new LocalRegAVM2Item(ins, localData.lineStartInstruction, indexReg, localData.localRegs.get(indexReg)), + new LocalRegAVM2Item(ins, localData.lineStartInstruction, objectReg, localData.localRegs.get(objectReg)) + )); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextNameAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextNameAVM2Item.java index a0e80ba2c..f9dc1a416 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextNameAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextNameAVM2Item.java @@ -34,9 +34,9 @@ import java.util.List; */ public class NextNameAVM2Item extends AVM2Item { - GraphTargetItem index; + public GraphTargetItem index; - GraphTargetItem obj; + public GraphTargetItem obj; public NextNameAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem index, GraphTargetItem obj) { super(instruction, lineStartIns, NOPRECEDENCE); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextValueAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextValueAVM2Item.java index 212da2108..62cfc0f08 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextValueAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NextValueAVM2Item.java @@ -34,9 +34,9 @@ import java.util.List; */ public class NextValueAVM2Item extends AVM2Item { - GraphTargetItem index; + public GraphTargetItem index; - GraphTargetItem obj; + public GraphTargetItem obj; public NextValueAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem index, GraphTargetItem obj) { super(instruction, lineStartIns, NOPRECEDENCE); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 1d5248dc7..01c638a2a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -471,7 +471,7 @@ public class ActionGraph extends Graph { List> caseCommands = new ArrayList<>(); GraphPart next = breakPart; - GraphTargetItem ti = checkLoop(next, stopPart, loops); + GraphTargetItem ti = checkLoop(new ArrayList(), next, stopPart, loops); //create switch as new loop break command detection to work currentLoop = new Loop(loops.size(), null, next); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 55109e03b..ec6027e6c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1460,7 +1460,7 @@ public class Graph { return ret; } - protected GraphTargetItem checkLoop(GraphPart part, List stopPart, List loops) { + protected GraphTargetItem checkLoop(List output, GraphPart part, List stopPart, List loops) { if (stopPart.contains(part)) { return null; } @@ -1817,7 +1817,7 @@ public class Graph { return printGraph(foundGotos, gotoTargets, partCodes, partCodePos, new HashSet<>(), localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0); } - protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List loops) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops) { return loopItem; } @@ -2927,7 +2927,7 @@ public class Graph { } currentLoop.phase = 2; - GraphTargetItem replaced = checkLoop(li, localData, loops); + GraphTargetItem replaced = checkLoop(ret, li, localData, loops); if (replaced != li) { int index = ret.indexOf(li); ret.remove(index);