diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 442419d21..b85a4290d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -243,14 +243,18 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSLateIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXAttrIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXElemIns; +import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.InitPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.ReturnVoidAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.SetPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; @@ -284,10 +288,15 @@ import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.SimpleValue; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.TypeItem; +import com.jpexs.decompiler.graph.model.BinaryOpItem; +import com.jpexs.decompiler.graph.model.DoWhileItem; import com.jpexs.decompiler.graph.model.ExitItem; +import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.ScriptEndItem; +import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Helper; import com.jpexs.helpers.stat.Statistics; import java.io.ByteArrayInputStream; @@ -1812,63 +1821,115 @@ public class AVM2Code implements Cloneable { toSourceCount = 0; } - private void injectDeclarations(List list, boolean[] declaredRegisters, List declaredSlots, ABC abc, MethodBody body) { + private GraphTargetItem handleDeclareReg(int minreg, GraphTargetItem assignment, DeclarationAVM2Item[] declaredRegisters, int reg) { + + //do not add declarations for reserved local registers like function arguments + if (reg < minreg) { + return assignment; + } + GraphTargetItem vtype = TypeItem.UNBOUNDED; + if (assignment.value instanceof ConvertAVM2Item) { + vtype = ((ConvertAVM2Item) assignment.value).type; + } + + if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof CoerceAVM2Item)) { + vtype = ((CoerceAVM2Item) assignment.value).typeObj; + } + if (vtype.equals(TypeItem.UNBOUNDED) && (assignment.value instanceof SimpleValue) && ((SimpleValue) assignment.value).isSimpleValue()) { + vtype = assignment.value.returnType(); + } + + if (declaredRegisters[reg] == null) { + declaredRegisters[reg] = new DeclarationAVM2Item(assignment, vtype); + if (assignment instanceof SetTypeAVM2Item) { + ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); + } + return declaredRegisters[reg]; + } + + if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) { + + } else if (!declaredRegisters[reg].type.equals(vtype)) { //already declared with different type + declaredRegisters[reg].type = TypeItem.UNBOUNDED; + } + + if (assignment instanceof SetTypeAVM2Item) { + ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); + } + + return assignment; + } + + private GraphTargetItem injectDeclarations(int minreg, GraphTargetItem ti, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, ABC abc, MethodBody body) { + if (ti.value != null) { + ti.value = injectDeclarations(minreg, ti.value, declaredRegisters, declaredSlots, abc, body); + } + //TODO: walk whole tree... some walker? + if (ti instanceof IfItem) { + ((IfItem) ti).expression = injectDeclarations(minreg, ((IfItem) ti).expression, declaredRegisters, declaredSlots, abc, body); + } + if (ti instanceof BinaryOpItem) { + ((BinaryOpItem) ti).leftSide = injectDeclarations(minreg, ((BinaryOpItem) ti).leftSide, declaredRegisters, declaredSlots, abc, body); + ((BinaryOpItem) ti).rightSide = injectDeclarations(minreg, ((BinaryOpItem) ti).rightSide, declaredRegisters, declaredSlots, abc, body); + } + if (ti instanceof ForEachInAVM2Item) { + ForEachInAVM2Item fei = (ForEachInAVM2Item) ti; + if (fei.expression.object instanceof LocalRegAVM2Item) { + int reg = ((LocalRegAVM2Item) fei.expression.object).regIndex; + if (declaredRegisters[reg] == null) { + fei.expression.object = handleDeclareReg(minreg, fei.expression.object, declaredRegisters, reg); + } + } + } + if (ti instanceof ForInAVM2Item) { + ForInAVM2Item fi = (ForInAVM2Item) ti; + if (fi.expression.object instanceof LocalRegAVM2Item) { + int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex; + fi.expression.object = handleDeclareReg(minreg, fi.expression.object, declaredRegisters, reg); + //nowdeclaredRegs.add(reg); + + } + } + if (ti instanceof Block) { + Block bl = (Block) ti; + for (List s : bl.getSubs()) { + injectDeclarations(minreg, s, declaredRegisters, declaredSlots, abc, body); + } + } + if (ti instanceof SetLocalAVM2Item) { + int reg = ((SetLocalAVM2Item) ti).regIndex; + ti = handleDeclareReg(minreg, ti, declaredRegisters, reg); + return ti; + } + if (ti instanceof SetSlotAVM2Item) { + SetSlotAVM2Item ssti = (SetSlotAVM2Item) ti; + Slot sl = new Slot(ssti.scope, ssti.slotName); + if (!declaredSlots.contains(sl)) { + GraphTargetItem type = TypeItem.UNBOUNDED; + for (int t = 0; t < body.traits.traits.size(); t++) { + if (body.traits.traits.get(t).getName(abc) == sl.multiname) { + if (body.traits.traits.get(t) instanceof TraitSlotConst) { + type = PropertyAVM2Item.multinameToType(((TraitSlotConst) body.traits.traits.get(t)).type_index, abc.constants); + } + } + } + ti = new DeclarationAVM2Item(ti, type); + declaredSlots.add(sl); + return ti; + //nowdeclaredSlots.add(sl); + } + } + return ti; + } + + private void injectDeclarations(int minreg, List list, DeclarationAVM2Item[] declaredRegisters, List declaredSlots, ABC abc, MethodBody body) { //List nowdeclaredRegs=new ArrayList<>(); //List nowdeclaredSlots=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { GraphTargetItem ti = list.get(i); - if (ti instanceof ForEachInAVM2Item) { - ForEachInAVM2Item fei = (ForEachInAVM2Item) ti; - if (fei.expression.object instanceof LocalRegAVM2Item) { - int reg = ((LocalRegAVM2Item) fei.expression.object).regIndex; - if (!declaredRegisters[reg]) { - fei.expression.object = new DeclarationAVM2Item(fei.expression.object); - declaredRegisters[reg] = true; - //nowdeclaredRegs.add(reg); - } - } - } - if (ti instanceof ForInAVM2Item) { - ForInAVM2Item fi = (ForInAVM2Item) ti; - if (fi.expression.object instanceof LocalRegAVM2Item) { - int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex; - if (!declaredRegisters[reg]) { - fi.expression.object = new DeclarationAVM2Item(fi.expression.object); - declaredRegisters[reg] = true; - //nowdeclaredRegs.add(reg); - } - } - } - if (ti instanceof Block) { - Block bl = (Block) ti; - for (List s : bl.getSubs()) { - injectDeclarations(s, declaredRegisters, declaredSlots, abc, body); - } - } - if (ti instanceof SetLocalAVM2Item) { - int reg = ((SetLocalAVM2Item) ti).regIndex; - if (!declaredRegisters[reg]) { - list.set(i, new DeclarationAVM2Item(ti)); - declaredRegisters[reg] = true; - //nowdeclaredRegs.add(reg); - } - } - if (ti instanceof SetSlotAVM2Item) { - SetSlotAVM2Item ssti = (SetSlotAVM2Item) ti; - Slot sl = new Slot(ssti.scope, ssti.slotName); - if (!declaredSlots.contains(sl)) { - GraphTargetItem type = TypeItem.UNBOUNDED; - for (int t = 0; t < body.traits.traits.size(); t++) { - if (body.traits.traits.get(t).getName(abc) == sl.multiname) { - if (body.traits.traits.get(t) instanceof TraitSlotConst) { - type = PropertyAVM2Item.multinameToType(((TraitSlotConst) body.traits.traits.get(t)).type_index, abc.constants); - } - } - } - list.set(i, new DeclarationAVM2Item(ti, type)); - declaredSlots.add(sl); - //nowdeclaredSlots.add(sl); - } + GraphTargetItem ti2 = injectDeclarations(minreg, ti, declaredRegisters, declaredSlots, abc, body); + if (ti != ti2) { + list.set(i, ti2); } } @@ -1958,7 +2019,39 @@ public class AVM2Code implements Cloneable { } } // Declarations - injectDeclarations(list, new boolean[regCount], new ArrayList<>(), abc, body); + + DeclarationAVM2Item d[] = new DeclarationAVM2Item[regCount]; + + int param_types[] = abc.method_info.get(body.method_info).param_types; + int r = 1; + for (int i = 0; i < param_types.length; i++) { + GraphTargetItem type; + if (param_types[i] == 0) { + type = TypeItem.UNBOUNDED; + } else { + type = new TypeItem(abc.constants.getMultiname(param_types[i]).getNameWithNamespace(abc.constants)); + } + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), type); + } + r++; + } + if (abc.method_info.get(body.method_info).flagNeed_arguments()) { + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY /*?*/); + } + r++; + } + if (abc.method_info.get(body.method_info).flagNeed_rest()) { + if (d.length > r) { + d[r] = new DeclarationAVM2Item(new SetLocalAVM2Item(null, null, r, new NullAVM2Item(null, null)), TypeItem.ARRAY/*?*/); + } + r++; + } + // + + //int minreg = abc.method_info.get(body.method_info).getMaxReservedReg() + 1; + injectDeclarations(1, list, d, new ArrayList<>(), abc, body); int lastPos = list.size() - 1; if (lastPos < 0) { @@ -1993,7 +2086,8 @@ public class AVM2Code implements Cloneable { ins.operands[j] = updater.updateOperandOffset(target, ins.operands[j]); } }*/ //Faster, but not so universal - if (ins.definition instanceof IfTypeIns) { + { + if (ins.definition instanceof IfTypeIns) { long target = ins.getTargetAddress(); try { ins.operands[0] = updater.updateOperandOffset(ins.getAddress(), target, ins.operands[0]); @@ -2001,6 +2095,7 @@ public class AVM2Code implements Cloneable { throw new ConvertException("Invalid offset (" + ins + ")", i); } } + } ins.setAddress(updater.updateInstructionOffset(ins.getAddress())); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java index 359471107..b5248f3c0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConvertAVM2Item.java @@ -38,7 +38,10 @@ public class ConvertAVM2Item extends AVM2Item { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - return value.toString(writer, localData); + type.toString(writer, localData).append("("); + value.toString(writer, localData); + writer.append(")"); + return writer; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/InitPropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/InitPropertyAVM2Item.java index 53dbd4ace..ea9cc3b84 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/InitPropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/InitPropertyAVM2Item.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.AssignmentAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -33,6 +34,17 @@ public class InitPropertyAVM2Item extends AVM2Item implements SetTypeAVM2Item, A public FullMultinameAVM2Item propertyName; + public DeclarationAVM2Item declaration; + + @Override + public DeclarationAVM2Item getDeclaration() { + return declaration; + } + + public void setDeclaration(DeclarationAVM2Item declaration) { + this.declaration = declaration; + } + public InitPropertyAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem object, FullMultinameAVM2Item propertyName, GraphTargetItem value) { super(instruction, lineStartIns, PRECEDENCE_ASSIGMENT, value); this.object = object; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NameValuePair.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NameValuePair.java index d30aef024..a85df2e15 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NameValuePair.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NameValuePair.java @@ -37,7 +37,7 @@ public class NameValuePair extends AVM2Item { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - name.toString(writer, localData); + name.toStringString(writer, localData); writer.append(":"); if (value instanceof TernarOpItem) { //Ternar operator contains ":" writer.append("("); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NanAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NanAVM2Item.java index 4fae387c3..915206a1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NanAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NanAVM2Item.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SimpleValue; import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; @@ -33,7 +34,7 @@ import java.util.List; * * @author JPEXS */ -public class NanAVM2Item extends AVM2Item { +public class NanAVM2Item extends AVM2Item implements SimpleValue { public NanAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns) { super(instruction, lineStartIns, NOPRECEDENCE); @@ -60,4 +61,9 @@ public class NanAVM2Item extends AVM2Item { public boolean hasReturnValue() { return true; } + + @Override + public boolean isSimpleValue() { + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java index 09783ffbc..d6d64ab59 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.AssignmentAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -37,6 +38,17 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig public int regIndex; + public DeclarationAVM2Item declaration; + + @Override + public DeclarationAVM2Item getDeclaration() { + return declaration; + } + + public void setDeclaration(DeclarationAVM2Item declaration) { + this.declaration = declaration; + } + public SetLocalAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, int regIndex, GraphTargetItem value) { super(instruction, lineStartIns, PRECEDENCE_ASSIGMENT, value); this.regIndex = regIndex; @@ -47,6 +59,9 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig String localName = localRegName(localData.localRegNames, regIndex); getSrcData().localName = localName; writer.append(localName).append(" = "); + if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) { + return value.value.toString(writer, localData); + } return value.toString(writer, localData); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetPropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetPropertyAVM2Item.java index ef860a927..9934bee77 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetPropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetPropertyAVM2Item.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.AssignmentAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.CompilationException; @@ -41,6 +42,17 @@ public class SetPropertyAVM2Item extends AVM2Item implements SetTypeAVM2Item, As public GraphTargetItem propertyName; + public DeclarationAVM2Item declaration; + + @Override + public DeclarationAVM2Item getDeclaration() { + return declaration; + } + + public void setDeclaration(DeclarationAVM2Item declaration) { + this.declaration = declaration; + } + @Override public GraphPart getFirstPart() { return value.getFirstPart(); @@ -57,6 +69,9 @@ public class SetPropertyAVM2Item extends AVM2Item implements SetTypeAVM2Item, As public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { formatProperty(writer, object, propertyName, localData); writer.append(" = "); + if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) { + return value.value.toString(writer, localData); + } return value.toString(writer, localData); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java index 3a561d93e..fda54388f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetSlotAVM2Item.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.abc.avm2.model.clauses.AssignmentAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphPart; @@ -35,6 +36,17 @@ public class SetSlotAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assign public GraphTargetItem scope; + public DeclarationAVM2Item declaration; + + @Override + public DeclarationAVM2Item getDeclaration() { + return declaration; + } + + public void setDeclaration(DeclarationAVM2Item declaration) { + this.declaration = declaration; + } + public SetSlotAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem scope, Multiname slotName, GraphTargetItem value) { super(instruction, lineStartIns, PRECEDENCE_ASSIGMENT, value); this.slotName = slotName; @@ -55,6 +67,9 @@ public class SetSlotAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assign } getName(writer, localData); writer.append(" = "); + if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) { + return value.value.toString(writer, localData); + } return value.toString(writer, localData); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetTypeAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetTypeAVM2Item.java index 472c8ca17..318a1d4e8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetTypeAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetTypeAVM2Item.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.abc.avm2.model.clauses.DeclarationAVM2Item; import com.jpexs.decompiler.graph.GraphTargetItem; /** @@ -27,4 +28,8 @@ public interface SetTypeAVM2Item { public GraphTargetItem getObject(); public GraphTargetItem getValue(); + + public DeclarationAVM2Item getDeclaration(); + + public void setDeclaration(DeclarationAVM2Item dec); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/UndefinedAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/UndefinedAVM2Item.java index 70f6cf62b..5e5de4c39 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/UndefinedAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/UndefinedAVM2Item.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SimpleValue; import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; @@ -35,7 +36,7 @@ import java.util.Set; * * @author JPEXS */ -public class UndefinedAVM2Item extends AVM2Item { +public class UndefinedAVM2Item extends AVM2Item implements SimpleValue { public UndefinedAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns) { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); @@ -58,7 +59,7 @@ public class UndefinedAVM2Item extends AVM2Item { @Override public GraphTargetItem returnType() { - return new TypeItem(DottedChain.UNDEFINED); + return TypeItem.UNBOUNDED; } @Override @@ -72,4 +73,9 @@ public class UndefinedAVM2Item extends AVM2Item { new AVM2Instruction(0, AVM2Instructions.PushUndefined, null) ); } + + @Override + public boolean isSimpleValue() { + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java index befc41053..1dae2ee03 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java @@ -85,6 +85,7 @@ public class DeclarationAVM2Item extends AVM2Item { srcData.declaration = true; srcData.regIndex = lti.regIndex; + GraphTargetItem val = lti.value; GraphTargetItem coerType = TypeItem.UNBOUNDED; if (lti.value instanceof CoerceAVM2Item) { coerType = ((CoerceAVM2Item) lti.value).typeObj; @@ -92,13 +93,17 @@ public class DeclarationAVM2Item extends AVM2Item { if (lti.value instanceof ConvertAVM2Item) { coerType = ((ConvertAVM2Item) lti.value).type; } + //strip coerce if its declared as this type + if (coerType.equals(type) && !coerType.equals(TypeItem.UNBOUNDED)) { + val = val.value; + } srcData.declaredType = (coerType instanceof TypeItem) ? ((TypeItem) coerType).fullTypeName : DottedChain.ALL; writer.append("var "); writer.append(localName); writer.append(":"); - coerType.appendTry(writer, localData); + type.appendTry(writer, localData); writer.append(" = "); - return lti.value.toString(writer, localData); + return val.toString(writer, localData); } if (assignment instanceof SetSlotAVM2Item) { SetSlotAVM2Item ssti = (SetSlotAVM2Item) assignment; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodInfo.java index 59eba6822..022b3dd2f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodInfo.java @@ -303,6 +303,10 @@ public class MethodInfo { return constants.getString(name_index); } + public int getMaxReservedReg() { + return param_types.length + (flagNeed_rest() ? 1 : 0) + (flagNeed_arguments() ? 1 : 0); + } + public GraphTextWriter getParamStr(GraphTextWriter writer, AVM2ConstantPool constants, MethodBody body, ABC abc, List fullyQualifiedNames) { Map localRegNames = new HashMap<>(); if (body != null && Configuration.getLocalNamesFromDebugInfo.get()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java index eb867d9f6..769b193bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.graph; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item; 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.NameValuePair; @@ -331,7 +332,14 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { public GraphTextWriter appendTry(GraphTextWriter writer, LocalData localData, String implicitCoerce) throws InterruptedException { GraphTargetItem t = this; - if (!implicitCoerce.isEmpty() && Configuration.autoDeobfuscate.get()) { + if (!implicitCoerce.isEmpty()) { //if implicit coerce equals explicit + if (t instanceof ConvertAVM2Item) { + if (implicitCoerce.equals((((ConvertAVM2Item) t).type.toString()))) { + t = t.value; + } + } + } + if (!implicitCoerce.isEmpty() && Configuration._simplifyExpressions.get()) { t = t.simplify(implicitCoerce); } return t.appendTo(writer, localData); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DoWhileItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DoWhileItem.java index 6c2c73097..d88b82c1f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DoWhileItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/DoWhileItem.java @@ -50,6 +50,9 @@ public class DoWhileItem extends LoopItem implements Block { @Override public List> getSubs() { List> ret = new ArrayList<>(); + if (expression != null) { + ret.add(expression); + } if (commands != null) { ret.add(commands); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/WhileItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/WhileItem.java index b5783ece7..2ef292a1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/WhileItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/WhileItem.java @@ -45,6 +45,9 @@ public class WhileItem extends LoopItem implements Block { @Override public List> getSubs() { List> ret = new ArrayList<>(); + if (expression != null) { + ret.add(expression); + } if (commands != null) { ret.add(commands); } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java index 184f51253..150b63b3d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -605,7 +605,7 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testMissingDefault() { - decompileMethod("testMissingDefault", "var jj:* = 1;\r\n" + decompileMethod("testMissingDefault", "var jj:int = 1;\r\n" + "switch(jj)\r\n" + "{\r\n" + "case 1:\r\n" @@ -621,10 +621,10 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testChainedAssignments() { - decompileMethod("testChainedAssignments", "var a:* = 0;\r\n" - + "var b:* = 0;\r\n" - + "var c:* = 0;\r\n" - + "var d:* = 0;\r\n" + decompileMethod("testChainedAssignments", "var a:int = 0;\r\n" + + "var b:int = 0;\r\n" + + "var c:int = 0;\r\n" + + "var d:int = 0;\r\n" + "d = c = b = a = 5;\r\n" + "var e:TestClass2 = TestClass2.createMe(\"test\");\r\n" + "e.attrib1 = e.attrib2 = e.attrib3 = this.getCounter();\r\n" @@ -671,10 +671,10 @@ public class ActionScript3Test extends ActionScriptTestBase { public void testDeclarations() { decompileMethod("testDeclarations", "var vall:* = undefined;\r\n" + "var vstr:String = null;\r\n" - + "var vint:* = 0;\r\n" + + "var vint:int = 0;\r\n" + "var vuint:uint = 0;\r\n" + "var vclass:TestClass1 = null;\r\n" - + "var vnumber:* = NaN;\r\n" + + "var vnumber:Number = NaN;\r\n" + "var vobject:Object = null;\r\n" + "vall = 6;\r\n" + "vstr = \"hello\";\r\n" @@ -689,7 +689,7 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testForIn() { decompileMethod("testForIn", "var dic:Dictionary = null;\r\n" - + "var item:Object = null;\r\n" + + "var item:* = null;\r\n" + "for(item in dic)\r\n" + "{\r\n" + "trace(item);\r\n" @@ -712,16 +712,16 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testComplexExpressions() { - decompileMethod("testComplexExpressions", "var i:* = 0;\r\n" - + "var j:* = 0;\r\n" + decompileMethod("testComplexExpressions", "var i:int = 0;\r\n" + + "var j:int = 0;\r\n" + "j = i = i + (i = i + i++);\r\n", false); } @Test public void testExpressions() { decompileMethod("testExpressions", "var arr:Array = null;\r\n" - + "var i:* = 5;\r\n" - + "var j:* = 5;\r\n" + + "var i:int = 5;\r\n" + + "var j:int = 5;\r\n" + "if((i = i = i / 2) == 1 || i == 2)\r\n" + "{\r\n" + "arguments.concat(i);\r\n" @@ -745,7 +745,7 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testLogicalComputing() { - decompileMethod("testLogicalComputing", "var b:* = false;\r\n" + decompileMethod("testLogicalComputing", "var b:Boolean = false;\r\n" + "var i:* = 5;\r\n" + "var j:* = 7;\r\n" + "if(i > j)\r\n" @@ -770,8 +770,8 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testDecl2() { - decompileMethod("testDecl2", "var k:* = 0;\r\n" - + "var i:* = 5;\r\n" + decompileMethod("testDecl2", "var k:int = 0;\r\n" + + "var i:int = 5;\r\n" + "i = i + 7;\r\n" + "if(i == 5)\r\n" + "{\r\n" @@ -786,10 +786,10 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testChain2() { decompileMethod("testChain2", "var g:Array = null;\r\n" - + "var h:* = false;\r\n" - + "var extraLine:* = false;\r\n" - + "var r:* = 7;\r\n" - + "var t:* = 0;\r\n" + + "var h:Boolean = false;\r\n" + + "var extraLine:Boolean = false;\r\n" + + "var r:int = 7;\r\n" + + "var t:int = 0;\r\n" + "t = this.getInt();\r\n" + "if(t + 1 < g.length)\r\n" + "{\r\n" @@ -804,7 +804,7 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testDoWhile2() { - decompileMethod("testDoWhile2", "var k:* = 5;\r\n" + decompileMethod("testDoWhile2", "var k:int = 5;\r\n" + "do\r\n" + "{\r\n" + "k++;\r\n" @@ -825,8 +825,8 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testWhileAnd() { - decompileMethod("testWhileAnd", "var a:* = 5;\r\n" - + "var b:* = 10;\r\n" + decompileMethod("testWhileAnd", "var a:int = 5;\r\n" + + "var b:int = 10;\r\n" + "while(a < 10 && b > 1)\r\n" + "{\r\n" + "a++;\r\n" @@ -846,7 +846,7 @@ public class ActionScript3Test extends ActionScriptTestBase { @Test public void testStringConcat() { - decompileMethod("testStringConcat", "var k:* = 8;\r\n" + decompileMethod("testStringConcat", "var k:int = 8;\r\n" + "this.traceIt(\"hello\" + 5 * 6);\r\n" + "this.traceIt(\"hello\" + (k - 1));\r\n" + "this.traceIt(\"hello\" + 5 + 6);\r\n", false); @@ -1176,4 +1176,14 @@ public class ActionScript3Test extends ActionScriptTestBase { + "trace(\"after switch\");\r\n", false); } + /** + * Note: this one should be better compiled with ASC2/air, for String(xy) to + * be convert_s + */ + @Test + public void testManualConvert() { + decompileMethod("testManualConvert", "trace(\"String(this).length\");\r\n" + + "trace(String(this).length);\r\n", false); + } + }