diff --git a/trunk/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java b/trunk/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java index ef0749e3f..f69d0295a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java +++ b/trunk/src/com/jpexs/decompiler/flash/SourceGeneratorLocalData.java @@ -16,11 +16,15 @@ */ package com.jpexs.decompiler.flash; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.abc.types.ABCException; +import java.io.IOException; import java.io.Serializable; +import java.nio.CharBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @@ -33,6 +37,9 @@ public class SourceGeneratorLocalData implements Serializable { public Boolean inMethod; public Integer forInLevel; public List exceptions = new ArrayList<>(); + public List finallyCatches = new ArrayList(); + public Map finallyCounter = new HashMap<>(); + public int finallyRegister = -1; public String currentClass; public int activationReg = 0; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 6d7b9aab6..957300a95 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1848,14 +1848,15 @@ public class AVM2Code implements Serializable { private boolean walkCode(CodeStats stats, int pos, int stack, int scope, ABC abc) { while (pos < code.size()) { + AVM2Instruction ins = code.get(pos); if (stats.instructionStats[pos].seen) { //check stack mismatch here - return true; + return true; } stats.instructionStats[pos].seen = true; stats.instructionStats[pos].stackpos = stack; stats.instructionStats[pos].scopepos = scope; - AVM2Instruction ins = code.get(pos); + int stackDelta = ins.definition.getStackDelta(ins, abc); int scopeDelta = ins.definition.getScopeStackDelta(ins, abc); int oldStack = stack; @@ -1864,6 +1865,9 @@ public class AVM2Code implements Serializable { stack += stackDelta; scope += scopeDelta; + stats.instructionStats[pos].stackpos_after = stack; + stats.instructionStats[pos].scopepos_after = scope; + if (stack > stats.maxstack) { stats.maxstack = stack; } @@ -1914,6 +1918,9 @@ public class AVM2Code implements Serializable { } if (ins.definition instanceof LookupSwitchIns) { for (int i = 0; i < ins.operands.length; i++) { + if (i == 1) { + continue; + } try { int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); if (!walkCode(stats, newpos, stack, scope, abc)) { @@ -1935,29 +1942,51 @@ public class AVM2Code implements Serializable { return null; } int scopePos = -1; - for (ABCException ex : body.exceptions) { + int prevStart = 0; + for (int e=0;e visited = new ArrayList<>(); - for(int i=0;i toSource(SourceGeneratorLocalData localData, SourceGenerator generator) { - return toSourceMerge(localData, generator, value, - new AVM2Instruction(0, new ReturnValueIns(), new int[]{}, new byte[0]) - ); + return ((AVM2SourceGenerator)generator).generate(localData, this); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ReturnVoidAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ReturnVoidAVM2Item.java index e7f301348..11794c649 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ReturnVoidAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ReturnVoidAVM2Item.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -41,8 +42,7 @@ public class ReturnVoidAVM2Item extends AVM2Item implements ExitItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) { - return toSourceMerge(localData, generator, new AVM2Instruction(0, new ReturnVoidIns(), new int[]{}, new byte[0]) - ); + return ((AVM2SourceGenerator)generator).generate(localData, this); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ThrowAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ThrowAVM2Item.java index 782041e0c..c71fd2a48 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ThrowAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/ThrowAVM2Item.java @@ -16,11 +16,16 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.List; public class ThrowAVM2Item extends AVM2Item { @@ -45,4 +50,11 @@ public class ThrowAVM2Item extends AVM2Item { public boolean hasReturnValue() { return false; } + + @Override + public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) { + return ((AVM2SourceGenerator)generator).generate(localData, this); + } + + } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index f4b459d2c..a83662d8d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -34,6 +34,7 @@ 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.GetLocal0Ins; import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.KillIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns; @@ -46,6 +47,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextValueIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSlotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopScopeIns; @@ -53,13 +55,17 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns; import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ReturnValueAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ThrowAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item; @@ -126,7 +132,8 @@ public class AVM2SourceGenerator implements SourceGenerator { public static final int MARK_E_START = 0; public static final int MARK_E_END = 1; public static final int MARK_E_TARGET = 2; - + public static final int MARK_E_FINALLYPART = 3; + private AVM2Instruction ins(InstructionDefinition def, int... operands) { return new AVM2Instruction(0, def, operands, new byte[0]); } @@ -191,22 +198,22 @@ public class AVM2SourceGenerator implements SourceGenerator { return list; } - private List condition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset){ - if(t instanceof IfCondition){ - IfCondition ic=(IfCondition)t; - return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(),ic.getRightSide(),ins(ic.getIfDefinition(),offset)); + private List condition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset) { + if (t instanceof IfCondition) { + IfCondition ic = (IfCondition) t; + return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(), ic.getRightSide(), ins(ic.getIfDefinition(), offset)); } - return GraphTargetItem.toSourceMerge(localData, this, t, ins(new IfTrueIns(),offset)); + return GraphTargetItem.toSourceMerge(localData, this, t, ins(new IfTrueIns(), offset)); } - - private List notCondition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset){ - if(t instanceof IfCondition){ - IfCondition ic=(IfCondition)t; - return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(),ic.getRightSide(),ins(ic.getIfNotDefinition(),offset)); + + private List notCondition(SourceGeneratorLocalData localData, GraphTargetItem t, int offset) { + if (t instanceof IfCondition) { + IfCondition ic = (IfCondition) t; + return GraphTargetItem.toSourceMerge(localData, this, ic.getLeftSide(), ic.getRightSide(), ins(ic.getIfNotDefinition(), offset)); } - return GraphTargetItem.toSourceMerge(localData, this, t, ins(new IfFalseIns(),offset)); + return GraphTargetItem.toSourceMerge(localData, this, t, ins(new IfFalseIns(), offset)); } - + private List generateIf(SourceGeneratorLocalData localData, GraphTargetItem expression, List onTrueCmds, List onFalseCmds, boolean ternar) { List ret = new ArrayList<>(); //ret.addAll(notCondition(localData, expression)); @@ -234,13 +241,13 @@ public class AVM2SourceGenerator implements SourceGenerator { onTrue.add(ajmp); } } - + byte[] onTrueBytes = insToBytes(onTrue); int onTrueLen = onTrueBytes.length; ret.addAll(notCondition(localData, expression, onTrueLen)); - ret.addAll(onTrue); - + ret.addAll(onTrue); + if (onFalse != null) { byte[] onFalseBytes = insToBytes(onFalse); int onFalseLen = onFalseBytes.length; @@ -297,53 +304,52 @@ public class AVM2SourceGenerator implements SourceGenerator { List ex = new ArrayList<>(item.expression); GraphTargetItem lastItem = null; - if (!ex.isEmpty()) { + if (!ex.isEmpty()) { lastItem = ex.remove(ex.size() - 1); - while(lastItem instanceof CommaExpressionItem){ - CommaExpressionItem cei=(CommaExpressionItem)lastItem; + while (lastItem instanceof CommaExpressionItem) { + CommaExpressionItem cei = (CommaExpressionItem) lastItem; ex.addAll(cei.commands); lastItem = ex.remove(ex.size() - 1); } whileExpr.addAll(generateToActionList(localData, ex)); } - List whileBody = generateToActionList(localData, item.commands); - AVM2Instruction forwardJump = ins(new JumpIns(),0); + List whileBody = generateToActionList(localData, item.commands); + AVM2Instruction forwardJump = ins(new JumpIns(), 0); ret.add(forwardJump); - whileBody.add(0,ins(new LabelIns())); + whileBody.add(0, ins(new LabelIns())); ret.addAll(whileBody); int whileBodyLen = insToBytes(whileBody).length; forwardJump.operands[0] = whileBodyLen; whileExpr.addAll(toInsList(condition(localData, lastItem, 0))); int whileExprLen = insToBytes(whileExpr).length; - whileExpr.get(whileExpr.size()-1).operands[0] = -(whileExprLen+whileBodyLen); //Assuming last is if instruction + whileExpr.get(whileExpr.size() - 1).operands[0] = -(whileExprLen + whileBodyLen); //Assuming last is if instruction ret.addAll(whileExpr); fixLoop(whileBody, whileBodyLen + whileExprLen, whileBodyLen, item.loop.id); return ret; } - + public List generate(SourceGeneratorLocalData localData, ForEachInAVM2Item item) { - return generateForIn(localData,item.expression.collection,(AssignableAVM2Item)item.expression.object,item.commands,true); + return generateForIn(localData, item.expression.collection, (AssignableAVM2Item) item.expression.object, item.commands, true); } - + public List generate(SourceGeneratorLocalData localData, ForInAVM2Item item) { - return generateForIn(localData,item.expression.collection,(AssignableAVM2Item)item.expression.object,item.commands,false); + return generateForIn(localData, item.expression.collection, (AssignableAVM2Item) item.expression.object, item.commands, false); } - - public List generateForIn(SourceGeneratorLocalData localData,GraphTargetItem collection, AssignableAVM2Item assignable,List commands, final boolean each) { + + public List generateForIn(SourceGeneratorLocalData localData, GraphTargetItem collection, AssignableAVM2Item assignable, List commands, final boolean each) { List ret = new ArrayList<>(); final Reference counterReg = new Reference<>(0); final Reference collectionReg = new Reference<>(0); - - ret.addAll(GraphTargetItem.toSourceMerge(localData, this, - ins(new PushByteIns(),0), + + ret.addAll(GraphTargetItem.toSourceMerge(localData, this, + ins(new PushByteIns(), 0), AssignableAVM2Item.setTemp(localData, this, counterReg), collection, NameAVM2Item.generateCoerce(this, "*"), - AssignableAVM2Item.setTemp(localData, this, collectionReg) - )); - - - GraphTargetItem assigned=new GraphTargetItem() { + AssignableAVM2Item.setTemp(localData, this, collectionReg) + )); + + GraphTargetItem assigned = new GraphTargetItem() { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { @@ -362,37 +368,37 @@ public class AVM2SourceGenerator implements SourceGenerator { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) { - return toSourceMerge(localData, generator, - AssignableAVM2Item.getTemp(localData, generator, collectionReg), - AssignableAVM2Item.getTemp(localData, generator, counterReg), - ins(each?new NextValueIns():new NextNameIns()) + return toSourceMerge(localData, generator, + AssignableAVM2Item.getTemp(localData, generator, collectionReg), + AssignableAVM2Item.getTemp(localData, generator, counterReg), + ins(each ? new NextValueIns() : new NextNameIns()) ); - } + } }; assignable.setAssignedValue(assigned); - - List forBody = toInsList(GraphTargetItem.toSourceMerge(localData, this, + + List forBody = toInsList(GraphTargetItem.toSourceMerge(localData, this, ins(new LabelIns()), assignable.toSourceIgnoreReturnValue(localData, this) - )); - + )); + forBody.addAll(generateToActionList(localData, commands)); int forBodyLen = insToBytes(forBody).length; - - AVM2Instruction forwardJump = ins(new JumpIns(),forBodyLen); + + AVM2Instruction forwardJump = ins(new JumpIns(), forBodyLen); ret.add(forwardJump); - + List expr = new ArrayList<>(); - expr.add(ins(new HasNext2Ins(),collectionReg.getVal(),counterReg.getVal())); - AVM2Instruction backIf = ins(new IfTrueIns(),0); + expr.add(ins(new HasNext2Ins(), collectionReg.getVal(), counterReg.getVal())); + AVM2Instruction backIf = ins(new IfTrueIns(), 0); expr.add(backIf); - + int exprLen = insToBytes(expr).length; backIf.operands[0] = -(exprLen + forBodyLen); - + ret.addAll(forBody); ret.addAll(expr); - ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(collectionReg,counterReg))); + ret.addAll(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(collectionReg, counterReg))); return ret; } @@ -403,28 +409,28 @@ public class AVM2SourceGenerator implements SourceGenerator { List ex = new ArrayList<>(item.expression); GraphTargetItem lastItem = null; - if (!ex.isEmpty()) { + if (!ex.isEmpty()) { lastItem = ex.remove(ex.size() - 1); - while(lastItem instanceof CommaExpressionItem){ - CommaExpressionItem cei=(CommaExpressionItem)lastItem; + while (lastItem instanceof CommaExpressionItem) { + CommaExpressionItem cei = (CommaExpressionItem) lastItem; ex.addAll(cei.commands); lastItem = ex.remove(ex.size() - 1); } whileExpr.addAll(generateToActionList(localData, ex)); } - List dowhileBody = generateToActionList(localData, item.commands); + List dowhileBody = generateToActionList(localData, item.commands); List labelBody = new ArrayList<>(); labelBody.add(ins(new LabelIns())); int labelBodyLen = insToBytes(labelBody).length; - - AVM2Instruction forwardJump = ins(new JumpIns(),labelBodyLen); + + AVM2Instruction forwardJump = ins(new JumpIns(), labelBodyLen); ret.add(forwardJump); - ret.addAll(labelBody); - ret.addAll(dowhileBody); + ret.addAll(labelBody); + ret.addAll(dowhileBody); int dowhileBodyLen = insToBytes(dowhileBody).length; whileExpr.addAll(toInsList(condition(localData, lastItem, 0))); int dowhileExprLen = insToBytes(whileExpr).length; - whileExpr.get(whileExpr.size()-1).operands[0] = -(dowhileExprLen+dowhileBodyLen+labelBodyLen); //Assuming last is if instruction + whileExpr.get(whileExpr.size() - 1).operands[0] = -(dowhileExprLen + dowhileBodyLen + labelBodyLen); //Assuming last is if instruction ret.addAll(whileExpr); fixLoop(dowhileBody, dowhileBodyLen + dowhileExprLen, dowhileBodyLen, item.loop.id); return ret; @@ -435,36 +441,35 @@ public class AVM2SourceGenerator implements SourceGenerator { List ret = new ArrayList<>(); List forExpr = new ArrayList<>(); - List ex = new ArrayList<>(); + List ex = new ArrayList<>(); ex.add(item.expression); - + GraphTargetItem lastItem = null; - if (!ex.isEmpty()) { + if (!ex.isEmpty()) { lastItem = ex.remove(ex.size() - 1); - while(lastItem instanceof CommaExpressionItem){ - CommaExpressionItem cei=(CommaExpressionItem)lastItem; + while (lastItem instanceof CommaExpressionItem) { + CommaExpressionItem cei = (CommaExpressionItem) lastItem; ex.addAll(cei.commands); lastItem = ex.remove(ex.size() - 1); } forExpr.addAll(generateToActionList(localData, ex)); } - List forBody = generateToActionList(localData, item.commands); - List forFinalCommands = generateToActionList(localData, item.finalCommands); - - - ret.addAll(generateToActionList(localData, item.firstCommands)); - - AVM2Instruction forwardJump = ins(new JumpIns(),0); + List forBody = generateToActionList(localData, item.commands); + List forFinalCommands = generateToActionList(localData, item.finalCommands); + + ret.addAll(generateToActionList(localData, item.firstCommands)); + + AVM2Instruction forwardJump = ins(new JumpIns(), 0); ret.add(forwardJump); - forBody.add(0,ins(new LabelIns())); + forBody.add(0, ins(new LabelIns())); ret.addAll(forBody); ret.addAll(forFinalCommands); int forBodyLen = insToBytes(forBody).length; int forFinalCLen = insToBytes(forFinalCommands).length; - forwardJump.operands[0] = forBodyLen+forFinalCLen; + forwardJump.operands[0] = forBodyLen + forFinalCLen; forExpr.addAll(toInsList(condition(localData, lastItem, 0))); int forExprLen = insToBytes(forExpr).length; - forExpr.get(forExpr.size()-1).operands[0] = -(forExprLen+forBodyLen+forFinalCLen); //Assuming last is if instruction + forExpr.get(forExpr.size() - 1).operands[0] = -(forExprLen + forBodyLen + forFinalCLen); //Assuming last is if instruction ret.addAll(forExpr); fixLoop(forBody, forBodyLen + forFinalCLen + forExprLen, forBodyLen, item.loop.id); return ret; @@ -480,61 +485,58 @@ public class AVM2SourceGenerator implements SourceGenerator { public List generate(SourceGeneratorLocalData localData, SwitchItem item) { List ret = new ArrayList<>(); Reference switchedReg = new Reference<>(0); - AVM2Instruction forwardJump = ins(new JumpIns(),0); + AVM2Instruction forwardJump = ins(new JumpIns(), 0); ret.add(forwardJump); - - List cases=new ArrayList<>(); - cases.addAll(toInsList(new IntegerValueAVM2Item(null, (long)item.caseValues.size()).toSource(localData, this))); + List cases = new ArrayList<>(); + cases.addAll(toInsList(new IntegerValueAVM2Item(null, (long) item.caseValues.size()).toSource(localData, this))); int cLen = insToBytes(cases).length; - List caseLast=new ArrayList<>(); - caseLast.add(0,ins(new JumpIns(),cLen)); - caseLast.addAll(0,toInsList(new IntegerValueAVM2Item(null, (long)item.caseValues.size()).toSource(localData, this))); + List caseLast = new ArrayList<>(); + caseLast.add(0, ins(new JumpIns(), cLen)); + caseLast.addAll(0, toInsList(new IntegerValueAVM2Item(null, (long) item.caseValues.size()).toSource(localData, this))); int cLastLen = insToBytes(caseLast).length; - caseLast.add(0,ins(new JumpIns(),cLastLen)); - cases.addAll(0,caseLast); - - List preCases=new ArrayList<>(); + caseLast.add(0, ins(new JumpIns(), cLastLen)); + cases.addAll(0, caseLast); + + List preCases = new ArrayList<>(); preCases.addAll(toInsList(item.switchedObject.toSource(localData, this))); preCases.addAll(toInsList(AssignableAVM2Item.setTemp(localData, this, switchedReg))); - - for(int i=item.caseValues.size()-1;i>=0;i--){ - List sub=new ArrayList<>(); - sub.addAll(toInsList(new IntegerValueAVM2Item(null, (long)i).toSource(localData, this))); - sub.add(ins(new JumpIns(),insToBytes(cases).length)); + + for (int i = item.caseValues.size() - 1; i >= 0; i--) { + List sub = new ArrayList<>(); + sub.addAll(toInsList(new IntegerValueAVM2Item(null, (long) i).toSource(localData, this))); + sub.add(ins(new JumpIns(), insToBytes(cases).length)); int subLen = insToBytes(sub).length; - - cases.addAll(0,sub); - cases.add(0,ins(new IfStrictNeIns(), subLen)); - cases.addAll(0,toInsList(AssignableAVM2Item.getTemp(localData, this, switchedReg))); - cases.addAll(0,toInsList(item.caseValues.get(i).toSource(localData, this))); + + cases.addAll(0, sub); + cases.add(0, ins(new IfStrictNeIns(), subLen)); + cases.addAll(0, toInsList(AssignableAVM2Item.getTemp(localData, this, switchedReg))); + cases.addAll(0, toInsList(item.caseValues.get(i).toSource(localData, this))); } - cases.addAll(0,preCases); - - - - AVM2Instruction lookupOp = new AVM2Instruction(0, new LookupSwitchIns(), new int[item.caseValues.size()+1+1+1], new byte[0]); - cases.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(switchedReg)))); + cases.addAll(0, preCases); + + AVM2Instruction lookupOp = new AVM2Instruction(0, new LookupSwitchIns(), new int[item.caseValues.size() + 1 + 1 + 1], new byte[0]); + cases.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(switchedReg)))); List bodies = new ArrayList<>(); - List bodiesOffsets=new ArrayList<>(); + List bodiesOffsets = new ArrayList<>(); int defOffset; int casesLen = insToBytes(cases).length; bodies.addAll(generateToActionList(localData, item.defaultCommands)); - bodies.add(0,ins(new LabelIns())); - bodies.add(ins(new BreakJumpIns(item.loop.id),0)); //There could be two breaks when default clause ends with break, but official compiler does this too, so who cares... + bodies.add(0, ins(new LabelIns())); + bodies.add(ins(new BreakJumpIns(item.loop.id), 0)); //There could be two breaks when default clause ends with break, but official compiler does this too, so who cares... defOffset = -(insToBytes(bodies).length + casesLen); - for(int i=item.caseCommands.size()-1;i>=0;i--){ - bodies.addAll(0,generateToActionList(localData, item.caseCommands.get(i))); - bodies.add(0,ins(new LabelIns())); - bodiesOffsets.add(0,-(insToBytes(bodies).length + casesLen)); + for (int i = item.caseCommands.size() - 1; i >= 0; i--) { + bodies.addAll(0, generateToActionList(localData, item.caseCommands.get(i))); + bodies.add(0, ins(new LabelIns())); + bodiesOffsets.add(0, -(insToBytes(bodies).length + casesLen)); } - lookupOp.operands[0] = defOffset; + lookupOp.operands[0] = defOffset; lookupOp.operands[1] = item.valuesMapping.size(); lookupOp.operands[2 + item.caseValues.size()] = defOffset; - for(int i=0;i shiftExc(List list,int shift){ - for(AVM2Instruction ins:list){ - if(ins instanceof ExceptionMarkAVM2Instruction){ - ExceptionMarkAVM2Instruction e=(ExceptionMarkAVM2Instruction)ins; - e.exceptionId+=shift; + private List shiftExc(List list, int shift) { + for (AVM2Instruction ins : list) { + if (ins instanceof ExceptionMarkAVM2Instruction) { + ExceptionMarkAVM2Instruction e = (ExceptionMarkAVM2Instruction) ins; + e.exceptionId += shift; } } return list; } - + + private static int currentFinId = 1; + + private static int finId() { + return currentFinId++; + } + public List generate(SourceGeneratorLocalData localData, TryAVM2Item item) { List ret = new ArrayList<>(); - - - + + boolean newFinallyReg = false; int firstId = 0; - List newex=new ArrayList<>(); + List newex = new ArrayList<>(); + int aloneFinallyEx = -1; + int finallyEx = -1; for (NameAVM2Item e : item.catchExceptions2) { ABCException aex = new ABCException(); - aex.name_index = abc.constants.getMultinameId(new Multiname(Multiname.QNAME, abc.constants.getStringId(e.getVariableName(), true), abc.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abc.constants.getStringId("", true)), 0, true), 0,0,new ArrayList()),true); + aex.name_index = abc.constants.getMultinameId(new Multiname(Multiname.QNAME, abc.constants.getStringId(e.getVariableName(), true), abc.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abc.constants.getStringId("", true)), 0, true), 0, 0, new ArrayList()), true); aex.type_index = typeName(localData, e.type); newex.add(aex); } - - List tryCmds=generateToActionList(localData, item.tryCommands); - List> catchCmds=new ArrayList<>(); - for(int c=0;c -1) { + localData.finallyCatches.add(finId); + } + List tryCmds = generateToActionList(localData, item.tryCommands); + List> catchCmds = new ArrayList<>(); + for (int c = 0; c < item.catchCommands.size(); c++) { catchCmds.add(generateToActionList(localData, item.catchCommands.get(c))); } - + firstId = localData.exceptions.size(); - - - for (int i=firstId;i -1) { + aloneFinallyEx += firstId; + } + if (finallyEx > -1) { + finallyEx += firstId; + } + + for (int i = firstId; i < firstId + item.catchExceptions2.size(); i++) { ret.add(new ExceptionMarkAVM2Instruction(i, MARK_E_START)); } - + if (aloneFinallyEx > -1) { + ret.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_START)); + } + if (finallyEx > -1) { + ret.add(new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_START)); + } + ret.addAll(tryCmds); - - for (int i=firstId;i catches=new ArrayList<>(); - Reference tempReg=new Reference<>(0); - for (int c=item.catchCommands.size()-1;c>=0;c--) { - List preCatches=new ArrayList<>(); + if (aloneFinallyEx > -1) { + ret.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_END)); + } + + int i = firstId + item.catchCommands.size() - 1; + List catches = new ArrayList<>(); + Reference tempReg = new Reference<>(0); + for (int c = item.catchCommands.size() - 1; c >= 0; c--) { + List preCatches = new ArrayList<>(); preCatches.add(ins(new GetLocal0Ins())); preCatches.add(ins(new PushScopeIns())); preCatches.add(AssignableAVM2Item.generateGetLoc(localData.activationReg)); preCatches.add(ins(new PushScopeIns())); - preCatches.add(ins(new NewCatchIns(),i)); + preCatches.add(ins(new NewCatchIns(), i)); preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg))); preCatches.add(ins(new DupIns())); preCatches.add(ins(new PushScopeIns())); preCatches.add(ins(new SwapIns())); - preCatches.add(ins(new SetSlotIns(),1)); + preCatches.add(ins(new SetSlotIns(), 1)); preCatches.addAll(catchCmds.get(c)); preCatches.add(ins(new PopScopeIns())); preCatches.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg)))); - catches.addAll(0,preCatches); - catches.add(0,new ExceptionMarkAVM2Instruction(i, MARK_E_TARGET)); + catches.addAll(0, preCatches); + catches.add(0, new ExceptionMarkAVM2Instruction(i, MARK_E_TARGET)); i--; - catches.add(0,ins(new JumpIns(), insToBytes(catches).length)); + catches.add(0, ins(new JumpIns(), insToBytes(catches).length)); } + + if (aloneFinallyEx > -1) { + List preCatches = new ArrayList<>(); + preCatches.add(ins(new GetLocal0Ins())); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(AssignableAVM2Item.generateGetLoc(localData.activationReg)); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(ins(new NewCatchIns(), aloneFinallyEx)); + preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg))); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(ins(new ThrowIns())); + preCatches.add(ins(new PopScopeIns())); + preCatches.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg)))); + catches.add(ins(new JumpIns(), insToBytes(preCatches).length)); + catches.add(new ExceptionMarkAVM2Instruction(aloneFinallyEx, MARK_E_TARGET)); + catches.addAll(preCatches); + } + AVM2Instruction finSwitch = null; + AVM2Instruction pushDefIns = ins(new PushByteIns(), 0); + + int defPos = 0; + if (finallyEx > -1) { + List preCatches = new ArrayList<>(); + preCatches.add(0, new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_TARGET)); + preCatches.add(ins(new GetLocal0Ins())); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(AssignableAVM2Item.generateGetLoc(localData.activationReg)); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(ins(new NewCatchIns(), finallyEx)); + preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg))); + preCatches.add(ins(new PushScopeIns())); + preCatches.add(ins(new PopScopeIns())); + Reference tempReg2 = new Reference<>(0); + preCatches.add(ins(new KillIns(), tempReg.getVal())); + preCatches.add(ins(new CoerceAIns())); + preCatches.addAll(toInsList(AssignableAVM2Item.setTemp(localData, this, tempReg2))); + preCatches.add(pushDefIns); + + List finallySwitchCmds = new ArrayList<>(); + + finSwitch = new AVM2Instruction(0, new LookupSwitchIns(), new int[1 + 1 + 1], new byte[0]); + finSwitch.operands[0] = finSwitch.getBytes().length; + finSwitch.operands[1] = 0; //switch cnt + + List preFinallySwitch = new ArrayList<>(); + preFinallySwitch.add(ins(new LabelIns())); + preFinallySwitch.add(ins(new PopIns())); + int preFinallySwitchLen = insToBytes(preFinallySwitch).length; + + finallySwitchCmds.add(ins(new LabelIns())); + finallySwitchCmds.addAll(toInsList(AssignableAVM2Item.getTemp(localData, this, tempReg2))); + finallySwitchCmds.add(ins(new KillIns(), tempReg2.getVal())); + finallySwitchCmds.add(ins(new ThrowIns())); + finallySwitchCmds.add(ins(new PushByteIns(), 255)); + finallySwitchCmds.add(ins(new PopScopeIns())); + finallySwitchCmds.add(ins(new KillIns(), tempReg.getVal())); + + int finSwitchLen = insToBytes(finallySwitchCmds).length; + + preCatches.add(ins(new JumpIns(), preFinallySwitchLen + finSwitchLen)); + AVM2Instruction fjump = ins(new JumpIns(), 0); + fjump.operands[0] = insToBytes(preCatches).length + preFinallySwitchLen + finSwitchLen; + + preCatches.add(0, fjump); + preCatches.add(0, new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_END)); + preCatches.add(0, ins(new PushByteIns(), 255)); + + finallySwitchCmds.add(new ExceptionMarkAVM2Instruction(finallyEx, MARK_E_FINALLYPART)); + + int oldReg = localData.finallyRegister; + localData.finallyRegister = getFreeRegister(localData); + Integer cnt = localData.finallyCounter.get(finId); + if (cnt == null) { + cnt = -1; + } + defPos = cnt; + cnt++; //Skip default clause (throw) + localData.finallyCounter.put(finId, cnt); + finallySwitchCmds.addAll(generateToActionList(localData, item.finallyCommands)); + killRegister(localData, localData.finallyRegister); + localData.finallyRegister = oldReg; + finSwitchLen = insToBytes(finallySwitchCmds).length; + + finSwitch.operands[2] = -finSwitchLen; + preCatches.addAll(preFinallySwitch); + preCatches.addAll(finallySwitchCmds); + preCatches.add(finSwitch); + + catches.addAll(preCatches); + AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg, tempReg2)); + } + ret.addAll(catches); - localData.exceptions.addAll(newex); - //TODO: finally + localData.exceptions.addAll(newex); + + if (finallyEx > -1) { + localData.finallyCatches.remove(localData.finallyCatches.size() - 1); + } + if (newFinallyReg) { + localData.finallyRegister = -1; + killRegister(localData, localData.finallyRegister); + } + int pos = 0; + int finallyPos = 0; + int switchPos = 0; + for (int s = 0; s < ret.size(); s++) { + GraphSourceItem src = ret.get(s); + if (src == finSwitch) { + switchPos = pos; + } + if (src instanceof AVM2Instruction) { + AVM2Instruction ins = (AVM2Instruction) src; + if (ins instanceof ExceptionMarkAVM2Instruction) { + ExceptionMarkAVM2Instruction em = (ExceptionMarkAVM2Instruction) ins; + if (em.exceptionId == finallyEx && em.markType == MARK_E_FINALLYPART) { + finallyPos = pos; + ret.remove(s); + s--; + continue; + } + } + pos += ins.getBytes().length; + } + + } + + if (finSwitch != null) { + pos = 0; + int defLoc = finSwitch.operands[2]; + List switchLoc = new ArrayList<>(); + boolean wasDef = false; + for (int s = 0; s < ret.size(); s++) { + GraphSourceItem src = ret.get(s); + if (src instanceof AVM2Instruction) { + AVM2Instruction ins = (AVM2Instruction) src; + if (ins.definition instanceof FinallyJumpIns) { + FinallyJumpIns fji = (FinallyJumpIns) ins.definition; + if (fji.getClauseId() == finId) { + List bet = new ArrayList<>(); + bet.add(ins(new LabelIns())); + bet.add(ins(new PopIns())); + int betLen = insToBytes(bet).length; + if (wasDef) { + ins.operands[0] = 0; + } else { + ins.operands[0] = finallyPos - (pos + ins.getBytes().length); + } + ins.definition = new JumpIns(); + switchLoc.add(pos + ins.getBytes().length + betLen - switchPos); + } + } + pos += ins.getBytes().length; + } + if (defPos == switchLoc.size() - 1) { + switchLoc.add(defLoc); + wasDef = true; + } + } + finSwitch.operands = new int[1 + 1 + switchLoc.size()]; + pushDefIns.operands[0] = defPos + 1; + int afterLoc = finSwitch.getBytes().length; + finSwitch.operands[0] = afterLoc; + finSwitch.operands[1] = switchLoc.size() - 1; + for (int j = 0; j < switchLoc.size(); j++) { + finSwitch.operands[2 + j] = switchLoc.get(j); + } + } + return ret; } @@ -652,6 +862,69 @@ public class AVM2SourceGenerator implements SourceGenerator { return ret; } + public List generate(SourceGeneratorLocalData localData, ReturnValueAVM2Item item) { + List ret = new ArrayList<>(); + ret.addAll(item.value.toSource(localData, this)); + if (!localData.finallyCatches.isEmpty()) { + ret.add(ins(new CoerceAIns())); + ret.add(AssignableAVM2Item.generateSetLoc(localData.finallyRegister)); + for (int i = localData.finallyCatches.size() - 1; i >= 0; i--) { + if (i < localData.finallyCatches.size() - 1) { + ret.add(ins(new LabelIns())); + } + int clauseId = localData.finallyCatches.get(i); + Integer cnt = localData.finallyCounter.get(clauseId); + if (cnt == null) { + cnt = -1; + } + cnt++; + localData.finallyCounter.put(clauseId, cnt); + ret.addAll(new IntegerValueAVM2Item(null, (long) cnt).toSource(localData, this)); + ret.add(ins(new FinallyJumpIns(clauseId), 0)); + ret.add(ins(new LabelIns())); + ret.add(ins(new PopIns())); + } + ret.add(ins(new LabelIns())); + ret.add(AssignableAVM2Item.generateGetLoc(localData.finallyRegister)); + ret.add(ins(new KillIns(), localData.finallyRegister)); + } + ret.add(ins(new ReturnValueIns())); + return ret; + } + + public List generate(SourceGeneratorLocalData localData, ReturnVoidAVM2Item item) { + List ret = new ArrayList<>(); + if (!localData.finallyCatches.isEmpty()) { + + for (int i = 0; i < localData.finallyCatches.size(); i++) { + if (i > 0) { + ret.add(ins(new LabelIns())); + } + int clauseId = localData.finallyCatches.get(i); + Integer cnt = localData.finallyCounter.get(clauseId); + if (cnt == null) { + cnt = -1; + } + cnt++; + localData.finallyCounter.put(clauseId, cnt); + ret.addAll(new IntegerValueAVM2Item(null, (long) cnt).toSource(localData, this)); + ret.add(ins(new FinallyJumpIns(clauseId), 0)); + ret.add(ins(new LabelIns())); + ret.add(ins(new PopIns())); + } + ret.add(ins(new LabelIns())); + } + ret.add(ins(new ReturnVoidIns())); + return ret; + } + + public List generate(SourceGeneratorLocalData localData, ThrowAVM2Item item) { + List ret = new ArrayList<>(); + ret.addAll(item.value.toSource(localData, this)); + ret.add(ins(new ThrowIns())); + return ret; + } + private List generateToActionList(SourceGeneratorLocalData localData, List commands) { return toInsList(generate(localData, commands)); } @@ -735,10 +1008,10 @@ public class AVM2SourceGenerator implements SourceGenerator { generateTraitsPhase2(initScope, pkg, name, superName, false, localData, traitItems, instanceInfo.instance_traits, it); generateTraitsPhase2(initScope, pkg, name, superName, true, localData, traitItems, classInfo.static_traits, st); if (constructor == null) { - instanceInfo.iinit_index = method(pkg.packageName,false,new ArrayList(),initScope + 1, false, 0, name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), TypeItem.UNBOUNDED/*?? FIXME*/); + instanceInfo.iinit_index = method(pkg.packageName, false, new ArrayList(), initScope + 1, false, 0, name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), TypeItem.UNBOUNDED/*?? FIXME*/); } else { MethodAVM2Item m = (MethodAVM2Item) constructor; - instanceInfo.iinit_index = method(pkg.packageName,m.needsActivation,m.subvariables,initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/); + instanceInfo.iinit_index = method(pkg.packageName, m.needsActivation, m.subvariables, initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/); } //Class initializer @@ -828,7 +1101,7 @@ public class AVM2SourceGenerator implements SourceGenerator { String pkg = ""; String name = type.toString(); - if("*".equals(name)){ + if ("*".equals(name)) { return 0; } TypeItem nameItem = (TypeItem) type; @@ -919,11 +1192,11 @@ public class AVM2SourceGenerator implements SourceGenerator { return false; } - public int method(String pkg,boolean needsActivation,List subvariables,int initScope, boolean hasRest, int line, String className, String superType, boolean constructor, SourceGeneratorLocalData localData, List paramTypes, List paramNames, List paramValues, List body, GraphTargetItem retType) throws ParseException { + public int method(String pkg, boolean needsActivation, List subvariables, int initScope, boolean hasRest, int line, String className, String superType, boolean constructor, SourceGeneratorLocalData localData, List paramTypes, List paramNames, List paramValues, List body, GraphTargetItem retType) throws ParseException { //Reference hasArgs = new Reference<>(Boolean.FALSE); //calcRegisters(localData,needsActivation,paramNames,subvariables,body, hasArgs); localData.activationReg = 0; - + for (NameAVM2Item n : subvariables) { if (n.unresolved) { GraphTargetItem resolved = null; @@ -959,25 +1232,24 @@ public class AVM2SourceGenerator implements SourceGenerator { if (resolved == null) { throw new ParseException("Unknown variable or property:" + n.getVariableName(), n.line); } - } + } } - - + boolean hasArguments = false; List slotNames = new ArrayList<>(); List slotTypes = new ArrayList<>(); slotNames.add("--first"); slotTypes.add("-"); - + List registerNames = new ArrayList<>(); List registerTypes = new ArrayList<>(); - registerTypes.add(pkg.equals("")?className:pkg+"."+className); - registerNames.add("this"); - for(GraphTargetItem t:paramTypes){ + registerTypes.add(pkg.equals("") ? className : pkg + "." + className); + registerNames.add("this"); + for (GraphTargetItem t : paramTypes) { registerTypes.add(t.toString()); slotTypes.add(t.toString()); } - registerNames.addAll(paramNames); + registerNames.addAll(paramNames); slotNames.addAll(paramNames); localData.registerVars.clear(); for (NameAVM2Item n : subvariables) { @@ -989,15 +1261,15 @@ public class AVM2SourceGenerator implements SourceGenerator { } } int paramRegCount = registerNames.size(); - - if(needsActivation){ + + if (needsActivation) { registerNames.add("+$activation"); - localData.activationReg = registerNames.size()-1; + localData.activationReg = registerNames.size() - 1; registerTypes.add("Object"); } for (NameAVM2Item n : subvariables) { if (n.isDefinition()) { - if(!needsActivation || (n.getSlotScope()<=0)){ + if (!needsActivation || (n.getSlotScope() <= 0)) { registerNames.add(n.getVariableName()); registerTypes.add(n.type.toString()); slotNames.add(n.getVariableName()); @@ -1005,68 +1277,83 @@ public class AVM2SourceGenerator implements SourceGenerator { } } } - - - + int slotScope = 1; //? - + for (NameAVM2Item n : subvariables) { if (n.getVariableName() != null) { - if(needsActivation){ - if(n.getSlotNumber() <= 0){ + if (needsActivation) { + if (n.getSlotNumber() <= 0) { n.setSlotNumber(slotNames.indexOf(n.getVariableName())); - n.setSlotScope(slotScope); + n.setSlotScope(slotScope); } - }else{ + } else { n.setRegNumber(registerNames.indexOf(n.getVariableName())); } } } - + for (int i = 0; i < registerNames.size(); i++) { - if(needsActivation && i>localData.activationReg){ + if (needsActivation && i > localData.activationReg) { break; } localData.registerVars.put(registerNames.get(i), i); } - List declarations=new ArrayList<>(); - loopn:for (NameAVM2Item n : subvariables) { - if(!n.isDefinition()){ - continue; + List declarations = new ArrayList<>(); + loopn: + for (NameAVM2Item n : subvariables) { + //if (!n.isDefinition()) { + // continue; + //} + + if (needsActivation) { + if (n.getSlotScope() != slotScope) { + continue; + } else { + if (n.getSlotNumber() < paramRegCount) { + continue; + } + } } - if(n.getSlotScope()!=slotScope){ - continue; - } - for(NameAVM2Item d:declarations){ - if(n.getVariableName()!=null && n.getVariableName().equals(d.getVariableName())){ + for (NameAVM2Item d : declarations) { + if (n.getVariableName() != null && n.getVariableName().equals(d.getVariableName())) { continue loopn; } } - for(GraphTargetItem it:body){ //search first level of commands - if(it instanceof NameAVM2Item){ - NameAVM2Item n2=(NameAVM2Item)it; - if(n2.isDefinition() && n2.getAssignedValue()!=null && n2.getVariableName().equals(n.getVariableName())){ + for (GraphTargetItem it : body) { //search first level of commands + if (it instanceof NameAVM2Item) { + NameAVM2Item n2 = (NameAVM2Item) it; + if (n2.isDefinition() && n2.getAssignedValue() != null && n2.getVariableName().equals(n.getVariableName())) { continue loopn; } - if(!n2.isDefinition() && n2.getVariableName()!=null && n2.getVariableName().equals(n.getVariableName())){ //used earlier than defined + if (!n2.isDefinition() && n2.getVariableName() != null && n2.getVariableName().equals(n.getVariableName())) { //used earlier than defined break; } } } - NameAVM2Item d=new NameAVM2Item(n.type, n.line, n.getVariableName(), NameAVM2Item.getDefaultValue(""+n.type), true, n.openedNamespaces); - if(needsActivation){ - if(d.getSlotNumber() <= 0) - { + if (n.unresolved) { + continue; + } + if (n.redirect != null) { + continue; + } + if (n.getNs() != null) { + continue; + } + + NameAVM2Item d = new NameAVM2Item(n.type, n.line, n.getVariableName(), NameAVM2Item.getDefaultValue("" + n.type), true, n.openedNamespaces); + //no index + if (needsActivation) { + if (d.getSlotNumber() <= 0) { d.setSlotNumber(n.getSlotNumber()); d.setSlotScope(n.getSlotScope()); } - }else{ + } else { d.setRegNumber(n.getRegNumber()); } declarations.add(d); } - - + int param_types[] = new int[paramTypes.size()]; ValueKind optional[] = new ValueKind[paramValues.size()]; //int param_names[] = new int[paramNames.size()]; @@ -1085,9 +1372,9 @@ public class AVM2SourceGenerator implements SourceGenerator { } //No param names like in official /* - if (!paramNames.isEmpty()) { - mi.setFlagHas_paramnames(); - }*/ + if (!paramNames.isEmpty()) { + mi.setFlagHas_paramnames(); + }*/ if (!paramValues.isEmpty()) { mi.setFlagHas_optional(); } @@ -1097,47 +1384,43 @@ public class AVM2SourceGenerator implements SourceGenerator { MethodBody mbody = new MethodBody(); mbody.method_info = abc.addMethodInfo(mi); - - mbody.traits = new Traits(); - int slotId = 1; - for(int i=1;i()), true); - tsc.type_index = typeName(localData, new TypeItem(slotTypes.get(i))); - mbody.traits.traits.add(tsc); - } - - if(needsActivation){ - for(int i=1;i()); + + if (needsActivation) { + mbody.traits = new Traits(); + int slotId = 1; + for (int i = 1; i < slotNames.size(); i++) { + TraitSlotConst tsc = new TraitSlotConst(); + tsc.slot_id = slotId++; + tsc.name_index = abc.constants.getMultinameId(new Multiname(Multiname.QNAME, abc.constants.getStringId(slotNames.get(i), true), abc.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE_INTERNAL, abc.constants.getStringId(pkg, true)), 0, true), 0, 0, new ArrayList()), true); + tsc.type_index = typeName(localData, new TypeItem(slotTypes.get(i))); + mbody.traits.traits.add(tsc); + } + for (int i = 1; i < paramRegCount; i++) { + NameAVM2Item param = new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), null, false, new ArrayList()); param.setRegNumber(i); - NameAVM2Item d=new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), param, true, new ArrayList()); + NameAVM2Item d = new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), param, true, new ArrayList()); d.setSlotScope(slotScope); d.setSlotNumber(slotNames.indexOf(registerNames.get(i))); declarations.add(d); } } - body.addAll(0,declarations); - + body.addAll(0, declarations); + localData.exceptions = new ArrayList<>(); List src = generate(localData, body); mbody.code = new AVM2Code(); mbody.code.code = toInsList(src); - if(needsActivation){ - List acts=new ArrayList<>(); + if (needsActivation) { + List acts = new ArrayList<>(); acts.add(ins(new NewActivationIns())); acts.add(ins(new DupIns())); acts.add(AssignableAVM2Item.generateSetLoc(localData.activationReg)); acts.add(ins(new PushScopeIns())); - - - - - mbody.code.code.addAll(0,acts); + + mbody.code.code.addAll(0, acts); } - + if (constructor) { List abcs = new ArrayList<>(); abcs.add(abc); @@ -1187,24 +1470,28 @@ public class AVM2SourceGenerator implements SourceGenerator { } mbody.exceptions = localData.exceptions.toArray(new ABCException[localData.exceptions.size()]); int offset = 0; - for (AVM2Instruction ins : mbody.code.code) { - if(ins instanceof ExceptionMarkAVM2Instruction){ - ExceptionMarkAVM2Instruction m=(ExceptionMarkAVM2Instruction)ins; - switch(m.markType){ + for (int i = 0; i < mbody.code.code.size(); i++) { + AVM2Instruction ins = mbody.code.code.get(i); + if (ins instanceof ExceptionMarkAVM2Instruction) { + ExceptionMarkAVM2Instruction m = (ExceptionMarkAVM2Instruction) ins; + switch (m.markType) { case MARK_E_START: mbody.exceptions[m.exceptionId].start = offset; break; - case MARK_E_END: + case MARK_E_END: mbody.exceptions[m.exceptionId].end = offset; break; case MARK_E_TARGET: mbody.exceptions[m.exceptionId].target = offset; break; } + mbody.code.code.remove(i); + i--; + continue; } - offset+=ins.getBytes().length; + offset += ins.getBytes().length; } - + mbody.autoFillStats(abc, initScope); abc.addMethodBody(mbody); @@ -1276,10 +1563,10 @@ public class AVM2SourceGenerator implements SourceGenerator { if (mai.isStatic() != generateStatic) { continue; } - ((TraitMethodGetterSetter) traits[k]).method_info = method(pkg.packageName,mai.needsActivation,mai.subvariables,initScope + 1/*class scope*/, mai.hasRest,mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType); + ((TraitMethodGetterSetter) traits[k]).method_info = method(pkg.packageName, mai.needsActivation, mai.subvariables, initScope + 1/*class scope*/, mai.hasRest, mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType); } else if (item instanceof FunctionAVM2Item) { FunctionAVM2Item fai = (FunctionAVM2Item) item; - ((TraitFunction) traits[k]).method_info = method(pkg.packageName,fai.needsActivation,fai.subvariables,initScope, fai.hasRest, fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType); + ((TraitFunction) traits[k]).method_info = method(pkg.packageName, fai.needsActivation, fai.subvariables, initScope, fai.hasRest, fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType); } } } @@ -1592,10 +1879,9 @@ public class AVM2SourceGenerator implements SourceGenerator { } } - /* public void calcRegisters(Reference activationReg, SourceGeneratorLocalData localData, boolean needsActivation, List funParamNames,List funSubVariables,List funBody, Reference hasArguments) throws ParseException { + /* public void calcRegisters(Reference activationReg, SourceGeneratorLocalData localData, boolean needsActivation, List funParamNames,List funSubVariables,List funBody, Reference hasArguments) throws ParseException { - }*/ - + }*/ public int resolveType(String objType) { if (objType.equals("*")) { return 0; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FinallyJumpIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FinallyJumpIns.java new file mode 100644 index 000000000..656bf8599 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/FinallyJumpIns.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.abc.avm2.parser.script; + +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; + +/** + * + * @author JPEXS + */ +public class FinallyJumpIns extends JumpIns { + + private long finallyClauseId; + + public FinallyJumpIns(long finallyClauseId) { + this.finallyClauseId = finallyClauseId; + } + + public long getClauseId() { + return finallyClauseId; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java index 22c62ef0d..771ae1753 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/NameAVM2Item.java @@ -95,11 +95,6 @@ public class NameAVM2Item extends AssignableAVM2Item { public int getSlotScope() { return slotScope; } - - - - - public void setNs(GraphTargetItem ns) { this.ns = ns; @@ -111,12 +106,12 @@ public class NameAVM2Item extends AssignableAVM2Item { public int getSlotNumber() { return slotNumber; - } + } public void setSlotNumber(int slotNumber) { this.slotNumber = slotNumber; - } - + } + public int getRegNumber() { return regNumber; } @@ -189,8 +184,8 @@ public class NameAVM2Item extends AssignableAVM2Item { return abc.constants.getNamespaceSetId(new NamespaceSet(nssa), true); } - public static GraphTargetItem getDefaultValue(String type){ - switch(type){ + public static GraphTargetItem getDefaultValue(String type) { + switch (type) { case "*": return new UndefinedAVM2Item(null); case "int": @@ -201,7 +196,7 @@ public class NameAVM2Item extends AssignableAVM2Item { return new NullAVM2Item(null); } } - + public static AVM2Instruction generateCoerce(SourceGenerator generator, String type) { AVM2Instruction ins; switch (type) { @@ -223,10 +218,10 @@ public class NameAVM2Item extends AssignableAVM2Item { } private List toSource(SourceGeneratorLocalData localData, SourceGenerator generator, boolean needsReturn) { - if (variableName != null && regNumber == -1 && slotNumber == -1 && ns == null) { + if (variableName != null && regNumber == -1 && slotNumber == -1 && ns == null) { throw new RuntimeException("No register or slot set for " + variableName); } - if (definition && assignedValue == null) { + if (definition && assignedValue == null) { return new ArrayList(); } AVM2SourceGenerator g = (AVM2SourceGenerator) generator; @@ -276,7 +271,7 @@ public class NameAVM2Item extends AssignableAVM2Item { if (index != null) { if (assignedValue != null) { return toSourceMerge(localData, generator, - generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), index, assignedValue, + generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), index, assignedValue, needsReturn ? dupSetTemp(localData, generator, ret_temp) : null, ins(new SetPropertyIns(), g.abc.constants.getMultinameId(new Multiname(Multiname.MULTINAMEL, 0, 0, allNsSet(g.abc), 0, new ArrayList()), true)), needsReturn ? getTemp(localData, generator, ret_temp) : null, @@ -292,25 +287,23 @@ public class NameAVM2Item extends AssignableAVM2Item { } if (assignedValue != null) { - List basicTypes = Arrays.asList("int","Number"); - if(slotNumber>-1) - { - return toSourceMerge(localData, generator, - ins(new GetScopeObjectIns(),slotScope), - assignedValue, !((""+assignedValue.returnType()).equals(""+type)&&(basicTypes.contains(""+type))) ? generateCoerce(generator, "" + type) : null, needsReturn - ? dupSetTemp(localData, generator, ret_temp) : null, generateSetLoc(regNumber),slotNumber>-1? - ins(new SetSlotIns(),slotNumber) - :null, - needsReturn?getTemp(localData, generator, ret_temp):null, - killTemp(localData, generator, Arrays.asList(ret_temp))); - } - else{ - - return toSourceMerge(localData, generator, assignedValue, !((""+assignedValue.returnType()).equals(""+type)&&(basicTypes.contains(""+type))) ? generateCoerce(generator, "" + type) : null, needsReturn - ? ins(new DupIns()) : null, generateSetLoc(regNumber)); + List basicTypes = Arrays.asList("int", "Number"); + if (slotNumber > -1) { + return toSourceMerge(localData, generator, + ins(new GetScopeObjectIns(), slotScope), + assignedValue, !(("" + assignedValue.returnType()).equals("" + type) && (basicTypes.contains("" + type))) ? generateCoerce(generator, "" + type) : null, needsReturn + ? dupSetTemp(localData, generator, ret_temp) : null, generateSetLoc(regNumber), slotNumber > -1 + ? ins(new SetSlotIns(), slotNumber) + : null, + needsReturn ? getTemp(localData, generator, ret_temp) : null, + killTemp(localData, generator, Arrays.asList(ret_temp))); + } else { + + return toSourceMerge(localData, generator, assignedValue, !(("" + assignedValue.returnType()).equals("" + type) && (basicTypes.contains("" + type))) ? generateCoerce(generator, "" + type) : null, needsReturn + ? ins(new DupIns()) : null, generateSetLoc(regNumber)); } } else { - return toSourceMerge(localData, generator, generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), + return toSourceMerge(localData, generator, generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), needsReturn ? null : ins(new PopIns())); } } @@ -431,7 +424,7 @@ public class NameAVM2Item extends AssignableAVM2Item { if (index != null) { return toSourceMerge(localData, generator, - generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), dupSetTemp(localData, generator, name_temp), index, dupSetTemp(localData, generator, index_temp), + generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), dupSetTemp(localData, generator, name_temp), index, dupSetTemp(localData, generator, index_temp), //Start get original //generateGetLoc(regNumber), getTemp(localData, generator, index_temp), ins(new GetPropertyIns(), g.abc.constants.getMultinameId(new Multiname(Multiname.MULTINAMEL, 0, 0, allNsSet(g.abc), 0, new ArrayList()), true)), @@ -449,23 +442,23 @@ public class NameAVM2Item extends AssignableAVM2Item { ); } - if(!needsReturn){ - if(slotNumber>-1){ + if (!needsReturn) { + if (slotNumber > -1) { return toSourceMerge(localData, generator, - ins(new GetScopeObjectIns(),slotScope), - generateGetSlot(slotScope,slotNumber), + ins(new GetScopeObjectIns(), slotScope), + generateGetSlot(slotScope, slotNumber), (decrement ? ins(isInteger ? new DecrementIIns() : new DecrementIns()) : ins(isInteger ? new IncrementIIns() : new IncrementIns())), - ins(new SetSlotIns(),slotNumber) + ins(new SetSlotIns(), slotNumber) ); - }else{ + } else { return toSourceMerge(localData, generator, - ins(isInteger?new IncLocalIIns():new IncLocalIns(),regNumber)); + ins(isInteger ? new IncLocalIIns() : new IncLocalIns(), regNumber)); } } return toSourceMerge(localData, generator, - slotNumber>-1?ins(new GetScopeObjectIns(),slotScope):null, + slotNumber > -1 ? ins(new GetScopeObjectIns(), slotScope) : null, //Start get original - generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), + generateGetLoc(regNumber), generateGetSlot(slotScope, slotNumber), //End get original !isInteger ? ins(new ConvertDIns()) : null, //End get original @@ -473,7 +466,7 @@ public class NameAVM2Item extends AssignableAVM2Item { needsReturn ? ins(new DupIns()) : null, (post) ? (decrement ? ins(isInteger ? new DecrementIIns() : new DecrementIns()) : ins(isInteger ? new IncrementIIns() : new IncrementIns())) : null, generateSetLoc(regNumber), - slotNumber>-1?ins(new SetSlotIns(),slotNumber):null + slotNumber > -1 ? ins(new SetSlotIns(), slotNumber) : null ); } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/todo.txt b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/todo.txt index fcbb2edc5..ab421f1aa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/todo.txt +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/todo.txt @@ -1,6 +1,5 @@ TODO List for AS3 parser/compiler: ------------------------------ -- finally clause - E4X (XML) - typenames (Vectors) - inner functions (activation, slots, etc.)