diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c518978e..faa9412cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ All notable changes to this project will be documented in this file. - [#2486] AS Loop in loop producing gotos in some cases - [#2486] AS1/2 Switch after function, problem with labels - [#2486] AS ifs with direct breaks (in obfuscated code) +- [#2486] AS3 skipping label instruction ### Changed - Icon of "Deobfuscation options" menu from pile of pills to medkit 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 e45ff31d5..ce2ba3d1e 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 @@ -1220,13 +1220,26 @@ public class AVM2Graph extends Graph { } } + //try in while + if (afterPart == part) { + afterPart = null; + } + GraphPart exAfterPart = afterPart; if (finallyException == null) { List stopPart2 = new ArrayList<>(stopPart); - stopPart2.add(afterPart); List stopPartKind2 = new ArrayList<>(stopPartKind); - stopPartKind2.add(StopPartKind.OTHER); + if (afterPart != null) { + stopPart2.add(afterPart); + stopPartKind2.add(StopPartKind.OTHER); + } + + for (Loop el : loops) { + if (el.loopContinue == part && el.phase == 1) { + el.phase = 4; //Special case: try inside loop. 4 is immediately switched back to 1 inside printGraph + } + } tryCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, stopPart2, stopPartKind2, loops, throwStates, staticOperation, path); } @@ -2654,23 +2667,22 @@ public class AVM2Graph extends Graph { } } - AVM2FinalProcessLocalData adata = (AVM2FinalProcessLocalData) localData; //if(false) if (!adata.bottomSetLocals.isEmpty()) { boolean modified = false; for (int i = 0; i < list.size(); i++) { - + if (list.get(i) instanceof LoopItem) { continue; } if (list.get(i) instanceof WithEndAVM2Item) { continue; } - + List foundSetLoc = new ArrayList<>(); List ignoredItems = new ArrayList<>(); - + //We need to ignore everything on the right side of && and ||, list.get(i).visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() { @Override @@ -2690,16 +2702,14 @@ public class AVM2Graph extends Graph { } } }); - + list.get(i).visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() { @Override public void visit(GraphTargetItem item, Stack parentStack) { - + if (item instanceof SetLocalAVM2Item) { - if ( - adata.bottomSetLocals.contains((SetLocalAVM2Item) item) - && !ignoredItems.contains((SetLocalAVM2Item) item) - ) { + if (adata.bottomSetLocals.contains((SetLocalAVM2Item) item) + && !ignoredItems.contains((SetLocalAVM2Item) item)) { int s = parentStack.size() - 1; if (parentStack.get(s) instanceof CoerceAVM2Item) { s--; @@ -2710,21 +2720,21 @@ public class AVM2Graph extends Graph { GraphTargetItem parent = parentStack.get(s); boolean move = true; if (parent instanceof SetTypeAVM2Item) { - SetTypeAVM2Item setType = (SetTypeAVM2Item) parent; - + SetTypeAVM2Item setType = (SetTypeAVM2Item) parent; + if (setType.getValue().getNotCoerced() == item) { //chained assignment //if (!((parent instanceof SetLocalAVM2Item) // && ((SetLocalAVM2Item)parent).regIndex == ((SetLocalAVM2Item) item).regIndex)) { //no chain for the same localreg - move = false; - } + move = false; + } } - if (move) { + if (move) { foundSetLoc.add(0, (SetLocalAVM2Item) item); } - } + } } } - } + } }); for (SetLocalAVM2Item setLoc : foundSetLoc) { list.add(i, setLoc.clone()); @@ -2740,7 +2750,7 @@ public class AVM2Graph extends Graph { GraphTargetItem lastExpr = list.remove(list.size() - 1); List onTrue = new ArrayList<>(); BreakItem bi = new BreakItem(dialect, null, null, wi.loop.id); - onTrue.add(bi); + onTrue.add(bi); IfItem ifi = new IfItem(dialect, null, null, lastExpr.invert(null), onTrue, new ArrayList<>()); list.add(ifi); wi.commands.addAll(0, list); @@ -2748,9 +2758,9 @@ public class AVM2Graph extends Graph { list.add(new TrueItem(dialect, null, null)); } } - + } - + /* convert this situation: @@ -2766,7 +2776,7 @@ 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> setRegisters = new HashMap<>(); @@ -2880,7 +2890,7 @@ public class AVM2Graph extends Graph { }); i = newI.getVal(); } - */ + */ //Handle for loops at the end: super.finalProcess(parent, list, level, localData, path); } @@ -2888,7 +2898,7 @@ public class AVM2Graph extends Graph { @Override protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops, List throwStates) { FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).bottomSetLocals); - finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos; + finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos; return finalProcess; } @@ -3191,11 +3201,11 @@ public class AVM2Graph extends Graph { protected SecondPassData prepareSecondPass(List list) { return new SecondPassData(); } - + @Override protected GraphTargetItem getIfExpression(BaseLocalData localData, TranslateStack stack, List output) { GraphTargetItem result = stack.pop(); - + /* Fixes this case: @@ -3212,8 +3222,7 @@ public class AVM2Graph extends Graph { dup setlocal x - */ - + */ if (stack.getMark("firstSetLocal") != null) { SetLocalAVM2Item setLocal = (SetLocalAVM2Item) stack.getMark("firstSetLocal"); if (setLocal.directlyCausedByDup) { @@ -3221,7 +3230,7 @@ public class AVM2Graph extends Graph { setLocal.hideValue = true; } } - + return result; } @@ -3230,7 +3239,7 @@ public class AVM2Graph extends Graph { if (localData.swfVersion < 50) { return ternar; } - + if (ternar.expression instanceof EqAVM2Item) { EqAVM2Item eq = (EqAVM2Item) ternar.expression; if (eq.rightSide instanceof NullAVM2Item) { @@ -3243,7 +3252,7 @@ public class AVM2Graph extends Graph { } } } - + if (ternar.expression instanceof NeqAVM2Item) { NeqAVM2Item neq = (NeqAVM2Item) ternar.expression; if (neq.rightSide instanceof NullAVM2Item) { @@ -3252,7 +3261,41 @@ public class AVM2Graph extends Graph { } } } - + return ternar; - } + } + + @Override + protected int checkIp(int ip) { + if (true) { + //return ip; + } + /* + Ignore label instructions + +
+        locA:
+            label
+        locB:
+            pushbyte 1
+        
+        =>
+        
+        locAB: 
+            pushbyte 1
+        
+ */ + while (ip < code.size()) { + GraphSourceItem ins = code.get(ip); + if (!(ins instanceof AVM2Instruction)) { + break; + } + AVM2Instruction ains = (AVM2Instruction) ins; + if (!(ains.definition instanceof LabelIns)) { + break; + } + ip++; + } + return ip; + } } 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 185ab8e94..59ba031c9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -559,7 +559,7 @@ public class Graph { if (l.loopBreak != null) { loopBreaks.add(l.loopBreak); } - } + } } for (GraphPart p : parts) { @@ -1034,8 +1034,8 @@ public class Graph { } /** - * This is needed to avoid loop/switch identifiers in AS1/2. AS3 supports them, but - * AS1/2 not. + * This is needed to avoid loop/switch identifiers in AS1/2. AS3 supports + * them, but AS1/2 not. * *
      * loop1: switch(a) { //has loop identifier
@@ -1113,7 +1113,7 @@ public class Graph {
                     boolean isLastCase = h == sw.caseCommands.size() - 1;
                     int last = com.size() - 1;
                     boolean hasBreak = ((com.get(last) instanceof BreakItem) && (((BreakItem) com.get(last)).loopId == sw.loop.id));
-                    
+
                     if (!isLastCase && !hasBreak) {
                         continue;
                     }
@@ -1142,11 +1142,11 @@ public class Graph {
                                     }
                                     lastCommand = caseCommands.get(caseCommands.size() - 1);
                                     if ((lastCommand instanceof BreakItem) || (lastCommand instanceof ContinueItem) || (lastCommand instanceof ExitItem)) {
-                                        changeBreakToBreak(caseCommands, sw.loop.id, innerSwitch.loop.id);                                    
+                                        changeBreakToBreak(caseCommands, sw.loop.id, innerSwitch.loop.id);
                                     } else if (k == subs.size() - 1) {
-                                        changeBreakToBreak(caseCommands, sw.loop.id, innerSwitch.loop.id);                                    
-                                    }                                
-                                }                                
+                                        changeBreakToBreak(caseCommands, sw.loop.id, innerSwitch.loop.id);
+                                    }
+                                }
                             } else {
                                 LoopItem innerLoop = (LoopItem) lastCommand;
                                 changeBreakToBreak(innerLoop.getBaseBodyCommands(), sw.loop.id, innerLoop.loop.id);
@@ -1248,11 +1248,7 @@ public class Graph {
                             if (lastCommand instanceof LoopItem) {
                                 LoopItem innerLoop = (LoopItem) lastCommand;
                                 Block blk = (Block) lastCommand;
-                                List> subs = blk.getSubs();
-
-                                for (List subItems : subs) {
-                                    changeContinueToBreak(subItems, li.loop.id, innerLoop.loop.id);
-                                }
+                                changeContinueToBreak(blk, li.loop.id, innerLoop.loop.id);
                             } else if (lastCommand instanceof Block) {
                                 Block blk = (Block) lastCommand;
                                 List> newTodos = new ArrayList<>(blk.getSubs());
@@ -1270,14 +1266,21 @@ public class Graph {
         }
     }
 
+    private void changeContinueToBreak(Block blk, long continueLoopId, long breakLoopId) {
+        for (List subItems : blk.getSubs()) {
+            changeContinueToBreak(subItems, continueLoopId, breakLoopId);
+        }
+        if (blk instanceof SwitchItem) {
+            fixSwitchEnd((SwitchItem) blk);
+        }
+    }
+
     private void changeContinueToBreak(List items, long continueLoopId, long breakLoopId) {
         for (int i = 0; i < items.size(); i++) {
             GraphTargetItem item = items.get(i);
             if (item instanceof Block) {
                 Block blk = (Block) item;
-                for (List subItems : blk.getSubs()) {
-                    changeContinueToBreak(subItems, continueLoopId, breakLoopId);
-                }
+                changeContinueToBreak(blk, continueLoopId, breakLoopId);
             }
             if (item instanceof ContinueItem) {
                 ContinueItem ci = (ContinueItem) item;
@@ -1466,11 +1469,6 @@ public class Graph {
                             if (cnt.loopId == lastLoopId) {
                                 hasContinues = true;
                                 commands.set(commands.size() - 1, new BreakItem(dialect, null, null, swi.loop.id));
-                                if (c == swi.caseCommands.size() - 1) {
-                                    if (commands.size() == 1) {
-                                        commands.remove(0);
-                                    }
-                                }
                             }
                         }
                     }
@@ -1490,6 +1488,7 @@ public class Graph {
                         targetCommands.add(new BreakItem(dialect, null, null, swi.loop.id));
                     }
                 }
+                fixSwitchEnd(swi);
             } else if (item instanceof IfItem) {
                 processSwitches(((IfItem) item).onTrue, lastLoopId);
                 processSwitches(((IfItem) item).onFalse, lastLoopId);
@@ -1610,7 +1609,8 @@ public class Graph {
         for (Loop el : loops) {
             el.backEdges.clear();
             Set uniqueRefs = new HashSet<>(el.loopContinue.refs);
-            loopr: for (GraphPart r : uniqueRefs) {
+            loopr:
+            for (GraphPart r : uniqueRefs) {
                 for (Loop el2 : loops) {
                     if (el2.phase == 1) {
                         if (el2.loopContinue == r) {
@@ -2536,6 +2536,9 @@ public class Graph {
                     }
                 }
             }
+
+            boolean isLoop = false;
+            Loop currentLoop = null;
             try {
                 if (lastP1 != null && canBeCandidate && canBeBreakCandidate(localData, part, throwStates)) {
                     if (lastP1.breakCandidates.contains(part)) {
@@ -2545,19 +2548,55 @@ public class Graph {
                     } else {
                         List loops2 = new ArrayList<>(loops);
                         loops2.remove(lastP1);
-                        if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, throwStates, true)) {
-                            if (lastP1.breakCandidatesLocked == 0) {
-                                if (debugGetLoops) {
-                                    System.err.println("added breakCandidate " + part + " to " + lastP1);
-                                }
 
-                                lastP1.breakCandidates.add(part);
-                                lastP1.breakCandidatesLevels.add(level);
-                                return;
+                        for (ThrowState ts : throwStates) {
+                            if (ts.throwingParts.contains(part)) {
+                                ts.state *= -1;
                             }
                         }
+
+                        try {
+                            if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, throwStates, true)) {
+                                if (lastP1.breakCandidatesLocked == 0) {
+                                    if (debugGetLoops) {
+                                        System.err.println("added breakCandidate " + part + " to " + lastP1);
+                                    }
+
+                                    lastP1.breakCandidates.add(part);
+                                    lastP1.breakCandidatesLevels.add(level);
+                                    return;
+                                }
+                            }
+                        } finally {
+                            for (ThrowState ts : throwStates) {
+                                if (ts.throwingParts.contains(part)) {
+                                    ts.state *= -1;
+                                }
+                            }
+
+                        }
                     }
                 }
+
+                for (Loop el : loops) {
+                    if (el.loopContinue == part) {
+                        return;
+                    }
+                }
+
+                if (stopPart != null && stopPart.contains(part)) {
+                    return;
+                }
+                part.level = level;
+
+                isLoop = part.leadsTo(localData, this, code, part, loops, throwStates, true);
+                currentLoop = null;
+                if (isLoop) {
+                    currentLoop = new Loop(loops.size(), part, null);
+                    currentLoop.phase = 1;
+                    loops.add(currentLoop);
+                }
+
             } finally {
                 for (ThrowState ts : throwStates) {
                     if (ts.throwingParts.contains(part)) {
@@ -2566,25 +2605,6 @@ public class Graph {
                 }
             }
 
-            for (Loop el : loops) {
-                if (el.loopContinue == part) {
-                    return;
-                }
-            }
-
-            if (stopPart != null && stopPart.contains(part)) {
-                return;
-            }
-            part.level = level;
-
-            boolean isLoop = part.leadsTo(localData, this, code, part, loops, throwStates, true);
-            Loop currentLoop = null;
-            if (isLoop) {
-                currentLoop = new Loop(loops.size(), part, null);
-                currentLoop.phase = 1;
-                loops.add(currentLoop);
-            }
-
             for (ThrowState ts : throwStates) {
                 if (ts.throwingParts.contains(part)) {
                     GraphPart t = ts.targetPart;
@@ -2717,6 +2737,7 @@ public class Graph {
                             candThrowStates.add(ts.exceptionId);
                         }
                     }
+
                 }
 
                 do {
@@ -3155,6 +3176,11 @@ public class Graph {
                     }
                     continue;
                 }
+                //Special case: for example in AS3 - try in while loop.
+                if (el.phase == 4) {
+                    el.phase = 1;
+                    continue;
+                }
                 if (el.phase != 1) {
                     if (debugPrintGraph) {
                         System.err.println("ignoring loop " + el);
@@ -3225,7 +3251,7 @@ public class Graph {
                         if (stopPart.get(i) == part) {
                             isRealStopPart = true;
                         }
-                        break;                                                
+                        break;
                     }
                 }
 
@@ -4185,13 +4211,17 @@ public class Graph {
             parent.nextParts.add(ret);
         }
         while (ip < code.size()) {
-            ip = checkIp(ip);
+            int aip = checkIp(ip);
             if (ip >= code.size()) {
                 break;
             }
+            if (aip >= code.size()) {
+                ip = aip;
+                break;
+            }
             if (visited[ip] || ((ip != startIp) && (refs.get(ip).size() > 1))) {
                 part.end = lastIp;
-                GraphPart found = searchPart(ip, allBlocks);
+                GraphPart found = searchPart(aip, allBlocks);
 
                 allBlocks.add(part);
 
@@ -4200,7 +4230,7 @@ public class Graph {
                     found.refs.add(part);
                     break;
                 } else {
-                    GraphPart nextPart = new GraphPart(ip, -1);
+                    GraphPart nextPart = new GraphPart(aip, -1);
                     nextPart.path = path;
                     part.nextParts.add(nextPart);
                     nextPart.refs.add(part);
@@ -4208,6 +4238,7 @@ public class Graph {
                 }
             }
             visited[ip] = true;
+            ip = aip;
             lastIp = ip;
             GraphSourceItem ins = code.get(ip);
             if (ins.isIgnored()) {
@@ -4659,6 +4690,59 @@ public class Graph {
             }
         }
 
+        nextRef.setVal(next);
+
+        currentLoop.phase = 2;
+        GraphTargetItem ti = checkLoop(new ArrayList<>() /*??*/, next, stopPart, loops, throwStates);
+        tiRef.setVal(ti);
+
+        SwitchItem ret = new SwitchItem(dialect, null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping);
+        fixSwitchEnd(ret);
+        return ret;
+    }
+
+    private void fixSwitchEnd(SwitchItem sw) {
+
+        List caseValuesMap = sw.caseValues;
+        List valuesMapping = sw.valuesMapping;
+        List> caseCommands = sw.caseCommands;
+        long loopId = sw.loop.id;
+
+        //Remove empty default clauses:
+        loopj:
+        for (int j = 0; j < caseValuesMap.size(); j++) {
+            if (caseValuesMap.get(j) instanceof DefaultItem) {
+                int m = valuesMapping.get(j);
+                List cc = caseCommands.get(m);
+                if (cc.size() == 1) {
+                    if (cc.get(0) instanceof BreakItem) {
+                        BreakItem br = (BreakItem) cc.get(0);
+                        if (br.loopId == loopId) {
+                            caseValuesMap.remove(j);
+                            valuesMapping.remove(j);
+                            boolean hasOther = false;
+                            for (int k = 0; k < valuesMapping.size(); k++) {
+                                if (valuesMapping.get(k) == m) {
+                                    hasOther = true;
+                                    break;
+                                }
+                            }
+                            if (!hasOther) {
+                                caseCommands.remove(m);
+                                for (int k = 0; k < valuesMapping.size(); k++) {
+                                    int vm = valuesMapping.get(k);
+                                    if (vm > m) {
+                                        valuesMapping.set(k, vm - 1);
+                                    }
+                                }
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
         //If the lastone is default empty and alone, remove it
         if (!caseCommands.isEmpty()) {
             List lastc = caseCommands.get(caseCommands.size() - 1);
@@ -4691,14 +4775,6 @@ public class Graph {
                 lastc.remove(lastc.size() - 1);
             }
         }
-        nextRef.setVal(next);
-
-        currentLoop.phase = 2;
-        GraphTargetItem ti = checkLoop(new ArrayList<>() /*??*/, next, stopPart, loops, throwStates);
-        tiRef.setVal(ti);
-
-        return new SwitchItem(dialect, null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping);
-
     }
 
     /**
diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java
index 47dddbd7c..94be0a4a0 100644
--- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java
+++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java
@@ -284,6 +284,29 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
                  false);
     }
 
+    @Test
+    public void testLabel() {
+        decompileMethod("assembled", "testLabel", "var _loc2_:String = param1.substr(0,1);\r\n"
+                + "var _loc3_:Boolean = false;\r\n"
+                + "var _loc4_:uint = 0;\r\n"
+                + "if(_loc2_ == \"E\")\r\n"
+                + "{\r\n"
+                + "_loc4_ = 0;\r\n"
+                + "if(_loc3_ == false)\r\n"
+                + "{\r\n"
+                + "trace(param1);\r\n"
+                + "}\r\n"
+                + "}\r\n"
+                + "else if(_loc2_ == \"A\")\r\n"
+                + "{\r\n"
+                + "_loc4_ = 0;\r\n"
+                + "}\r\n"
+                + "else if(_loc2_ == \"L\")\r\n"
+                + "{\r\n"
+                + "}\r\n",
+                 false);
+    }
+
     @Test
     public void testLocalRegIf() {
         decompileMethod("assembled", "testLocalRegIf", "var _loc1_:int = 8;\r\n"
@@ -440,33 +463,33 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
                 + "case 1:\r\n"
                 + "case 6:\r\n"
                 + "trace(\"1-6\");\r\n"
-                + "addr0120:\r\n"
+                + "addr0121:\r\n"
                 + "trace(\"F\");\r\n"
                 + "break;\r\n"
                 + "case 5:\r\n"
                 + "trace(\"5\");\r\n"
-                + "addr0119:\r\n"
+                + "addr011a:\r\n"
                 + "trace(\"E\");\r\n"
-                + "§§goto(addr0120);\r\n"
+                + "§§goto(addr0121);\r\n"
                 + "case 7:\r\n"
                 + "trace(\"7\");\r\n"
-                + "addr0112:\r\n"
+                + "addr0113:\r\n"
                 + "trace(\"D\");\r\n"
-                + "§§goto(addr0119);\r\n"
+                + "§§goto(addr011a);\r\n"
                 + "case 2:\r\n"
                 + "trace(\"2\");\r\n"
-                + "addr010b:\r\n"
+                + "addr010c:\r\n"
                 + "trace(\"C\");\r\n"
-                + "§§goto(addr0112);\r\n"
+                + "§§goto(addr0113);\r\n"
                 + "case 8:\r\n"
                 + "trace(\"8\");\r\n"
-                + "addr0104:\r\n"
+                + "addr0105:\r\n"
                 + "trace(\"B\");\r\n"
-                + "§§goto(addr010b);\r\n"
+                + "§§goto(addr010c);\r\n"
                 + "default:\r\n"
                 + "trace(\"def\");\r\n"
                 + "trace(\"A\");\r\n"
-                + "§§goto(addr0104);\r\n"
+                + "§§goto(addr0105);\r\n"
                 + "}\r\n"
                 + "trace(\"G\");\r\n"
                 + "return null;\r\n",
@@ -559,6 +582,7 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT
                 + "{\r\n"
                 + "try\r\n"
                 + "{\r\n"
+                + "trace(\"second\");\r\n"
                 + "}\r\n"
                 + "catch(e:Error)\r\n"
                 + "{\r\n"
diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java
index ae586e649..4f27ec848 100644
--- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java
+++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java
@@ -425,8 +425,8 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
         decompileMethod("classic_air", "testDefaultNotLastGrouped", "var k:int = 10;\r\n"
                 + "switch(k)\r\n"
                 + "{\r\n"
-                + "default:\r\n"
                 + "case \"six\":\r\n"
+                + "default:\r\n"
                 + "trace(\"def and 6\");\r\n"
                 + "case \"five\":\r\n"
                 + "trace(\"def and 6 and 5\");\r\n"
@@ -783,7 +783,6 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile
                 + "break;\r\n"
                 + "case 3:\r\n"
                 + "trace(\"4\");\r\n"
-                + "break;\r\n"
                 + "}\r\n"
                 + "if(c)\r\n"
                 + "{\r\n"
diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java
index 0d4557fad..b476ec617 100644
--- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java
+++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java
@@ -781,7 +781,6 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
                 + "break;\r\n"
                 + "case 4:\r\n"
                 + "trace(\"4\");\r\n"
-                + "break;\r\n"
                 + "}\r\n"
                 + "if(c)\r\n"
                 + "{\r\n"
diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileDecompileTest.java
index 21a56e584..5b6009ee0 100644
--- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileDecompileTest.java
+++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileDecompileTest.java
@@ -354,6 +354,7 @@ public class ActionScript3CrossCompileDecompileTest extends ActionScript3Decompi
                 + "trace(\"before loop\");\r\n"
                 + "while(true)\r\n"
                 + "{\r\n"
+                + "trace(\"a\");\r\n"
                 + "try\r\n"
                 + "{\r\n"
                 + "trace(\"in try\");\r\n"
diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileSwfToolsDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileSwfToolsDecompileTest.java
index 9bbcaacc9..9a9e8ce1c 100644
--- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileSwfToolsDecompileTest.java
+++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3CrossCompileSwfToolsDecompileTest.java
@@ -345,6 +345,7 @@ public class ActionScript3CrossCompileSwfToolsDecompileTest extends ActionScript
                 + "trace(\"before loop\");\r\n"
                 + "while(true)\r\n"
                 + "{\r\n"
+                + "trace(\"a\");\r\n"
                 + "try\r\n"
                 + "{\r\n"
                 + "trace(\"in try\");\r\n"
diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc
index 17a3ba11b..c66ba235a 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc and b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc differ
diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm
index f3fd6eeea..4d4cab84c 100644
--- a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm
+++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm
@@ -39,5 +39,6 @@ program
  #include "tests/TestGoto2.script.asasm"
  #include "tests/TestAlwaysBreak.script.asasm"
  #include "tests/TestAlwaysBreak2.script.asasm"
+ #include "tests/TestLabel.script.asasm"
  ; place to add next
 end ; program
diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.class.asasm
new file mode 100644
index 000000000..aaa3a92ab
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.class.asasm
@@ -0,0 +1,165 @@
+class
+ refid "tests:TestLabel"
+ instance QName(PackageNamespace("tests"), "TestLabel")
+  extends QName(PackageNamespace(""), "Object")
+  flag SEALED
+  flag PROTECTEDNS
+  protectedns ProtectedNamespace("tests:TestLabel")
+  iinit
+   refid "tests:TestLabel/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
+    param QName(PackageNamespace(""),"String")      
+    refid "tests:TestLabel/instance/run"
+    returns QName(PackageNamespace(""), "void")
+    body
+     maxstack 2
+     localcount 4
+     initscopedepth 4
+     maxscopedepth 5
+     code
+      getlocal0
+            pushscope
+            getlocal1
+            pushbyte 0
+            pushbyte 1
+            callproperty QName(Namespace("http://adobe.com/AS3/2006/builtin"),"substr"), 2
+            coerce_s
+            setlocal2
+            pushfalse
+            setlocal3
+            pushbyte 0
+            convert_u
+            setlocal 4
+            jump ofs00aa
+   ofs0017:
+            label
+            jump ofs0025
+   ofs001c:
+            label
+            getlocal2
+            pushstring "L"
+            ifne ofs0025
+   ofs0024:
+            label
+   ofs0025:
+            returnvoid
+            pushtrue
+            iftrue ofs002b
+   ofs002b:
+            label
+            getlocal0
+            getlocal1
+            callpropvoid QName(PrivateNamespace(""),"_-9m"), 1
+            jump ofs0035
+   ofs0035:
+            label
+            jump ofs0017
+            getlocal0
+            getproperty QName(PackageNamespace(""),"_-J0")
+            getlocal1
+            callpropvoid QName(Namespace("http://adobe.com/AS3/2006/builtin"),"push"), 1
+            jump ofs0045
+   ofs0045:
+            label
+            getlocal 4
+            increment
+            convert_u
+            setlocal 4
+            jump ofs0050
+   ofs0050:
+            label
+            jump ofs0035
+            label
+            getlocal1
+            getlocal0
+            getproperty QName(PackageNamespace(""),"_-J0")
+            getlocal 4
+            getproperty MultinameL([PrivateNamespace("","1"),PackageNamespace(""),PrivateNamespace("","2"),PackageInternalNs(""),Namespace("http://adobe.com/AS3/2006/builtin"),PackageNamespace("flash.display"),PackageNamespace("flash.events"),PackageNamespace("flash.system"),PackageNamespace("flash.text"),PackageNamespace("_-Pz"),PackageNamespace("com.newgrounds"),PackageNamespace("Playtomic"),PackageNamespace("flash.net"),PackageNamespace("flash.xml"),PackageNamespace("_-P2"),ProtectedNamespace("Main"),StaticProtectedNs("Main"),StaticProtectedNs("flash.display:MovieClip"),StaticProtectedNs("flash.display:Sprite"),StaticProtectedNs("flash.display:DisplayObjectContainer"),StaticProtectedNs("flash.display:InteractiveObject"),StaticProtectedNs("flash.display:DisplayObject"),StaticProtectedNs("flash.events:EventDispatcher"),StaticProtectedNs("Object")])
+            ifne ofs0062
+   ofs0062:
+            pushtrue
+            setlocal3
+            jump ofs0068
+   ofs0068:
+            label
+            jump ofs0024
+   ofs006d:
+            label
+            getlocal2
+            pushstring "A"
+            ifne ofs001c
+            pushbyte 0
+            convert_u
+            setlocal 4
+            jump ofs0050
+   ofs007e:
+            label
+            findproperty QName(PackageNamespace(""),"trace")
+            getlocal1
+            callpropvoid QName(PackageNamespace(""),"trace"), 1
+            jump ofs0068
+   ofs0089:
+            label
+            getlocal3
+            pushfalse
+            ifne ofs0068
+            jump ofs007e
+            label
+            getlocal 4
+            increment
+            convert_u
+            setlocal 4
+            jump ofs009f
+   ofs009f:
+            label
+            jump ofs0089
+            pushtrue
+            setlocal3
+            jump ofs00aa
+   ofs00aa:
+            getlocal2
+            pushstring "E"
+            ifne ofs006d
+            pushbyte 0
+            convert_u
+            setlocal 4
+            jump ofs009f
+            returnvoid
+      end ; code
+    end ; body
+   end ; method
+  end ; trait
+ end ; instance
+ cinit
+  refid "tests:TestLabel/class/init"
+  body
+   maxstack 1
+   localcount 1
+   initscopedepth 3
+   maxscopedepth 4
+   code
+    getlocal0
+    pushscope
+
+    returnvoid
+   end ; code
+  end ; body
+ end ; method
+end ; class
diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.script.asasm
new file mode 100644
index 000000000..18ab93ab6
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestLabel.script.asasm
@@ -0,0 +1,29 @@
+script
+ sinit
+  refid "tests:TestLabel/init"
+  body
+   maxstack 2
+   localcount 1
+   initscopedepth 1
+   maxscopedepth 3
+   code
+    getlocal0
+    pushscope
+
+    findpropstrict      Multiname("TestLabel", [PackageNamespace("tests")])
+    getlex              QName(PackageNamespace(""), "Object")
+    pushscope
+
+    getlex              Multiname("Object", [PrivateNamespace(null, "tests:TestLabel"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")])
+    newclass            "tests:TestLabel"
+    popscope
+    initproperty        QName(PackageNamespace("tests"), "TestLabel")
+
+    returnvoid
+   end ; code
+  end ; body
+ end ; method
+ trait class QName(PackageNamespace("tests"), "TestLabel")
+  #include "TestLabel.class.asasm"
+ end ; trait
+end ; script
diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf
index 692633add..cf6619d5c 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf and b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf differ
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf
index 1c38ff305..3f5933fcc 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf differ
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf
index f0f0cf96f..0d94f280c 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf differ
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf
index b1c82e0c4..05813e11b 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf differ
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf
index 48a7fc4ea..d7c1c5c7d 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf differ
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/build_flex_debug.bat b/libsrc/ffdec_lib/testdata/as3_cross_compile/build_flex_debug.bat
index e28a2256f..1194ea75a 100644
--- a/libsrc/ffdec_lib/testdata/as3_cross_compile/build_flex_debug.bat
+++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/build_flex_debug.bat
@@ -1,6 +1,7 @@
 @echo off
 set COMPILERKIND=flex
 set SWFNAME=as3_cross_compile
-c:\flex\bin\mxmlc.exe -warnings=false -debug=true -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
+rem c:\flex\bin\mxmlc.exe -warnings=false -debug=true -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
+call c:\flex\bin\mxmlc.bat -warnings=false -debug=true -output bin/%SWFNAME%.%COMPILERKIND%.swf src/Main.as 1> buildlog.%COMPILERKIND%.txt 2>&1
 IF NOT ERRORLEVEL 0 echo "FAILED"
 exit /b 0
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak3.as b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak3.as
index 804ebc38b..6c48a5a32 100644
--- a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak3.as
+++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak3.as
@@ -15,7 +15,7 @@ package tests
 			a = 0;			
 			trace("before loop");			
 			while (true) { 
-				
+				trace("a");
 				try
 				{
 					trace("in try"); 
@@ -38,4 +38,4 @@ package tests
 		
 	}
 
-}
\ No newline at end of file
+}
diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf
index 53f40ff52..b68cc7c74 100644
Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ