diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java index 5a3d7af2a..a2990a7fd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java @@ -72,6 +72,8 @@ public class AVM2LocalData extends BaseLocalData { public AVM2Code code; + public boolean thisHasDefaultToPrimitive; + public AVM2LocalData() { } @@ -94,6 +96,7 @@ public class AVM2LocalData extends BaseLocalData { ip = localData.ip; refs = localData.refs; code = localData.code; + thisHasDefaultToPrimitive = localData.thisHasDefaultToPrimitive; } public AVM2ConstantPool getConstants() { 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 b85a4290d..04037ad5a 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 @@ -1480,7 +1480,7 @@ public class AVM2Code implements Cloneable { return pos2adr(fixIPAfterDebugLine(adr2pos(addr, true))); } - public ConvertOutput toSourceOutput(Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssigmentIps, HashMap> refs) throws ConvertException, InterruptedException { + public ConvertOutput toSourceOutput(boolean thisHasDefaultToPrimitive, Reference lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, ABC abc, MethodBody body, int start, int end, HashMap localRegNames, List fullyQualifiedNames, boolean[] visited, HashMap localRegAssigmentIps, HashMap> refs) throws ConvertException, InterruptedException { calcKilledStats(body); boolean debugMode = DEBUG_MODE; if (debugMode) { @@ -1585,12 +1585,12 @@ public class AVM2Code implements Cloneable { AVM2Instruction insAfter = code.get(ip + 1); if ((insAfter.definition instanceof GetLocalTypeIns) && (((GetLocalTypeIns) insAfter.definition).getRegisterId(insAfter) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins))) { GraphTargetItem before = stack.peek(); - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); stack.push(before); ip += 2; continue iploop; } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); ip++; continue iploop; } @@ -1599,7 +1599,7 @@ public class AVM2Code implements Cloneable { do { AVM2Instruction insAfter = ip + 1 < code.size() ? code.get(ip + 1) : null; if (insAfter == null) { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); ip++; break; } @@ -1633,7 +1633,7 @@ public class AVM2Code implements Cloneable { if (((GetLocalTypeIns) code.get(t).definition).getRegisterId(code.get(t)) == reg) { if (code.get(t + 1).definition instanceof KillIns) { if (code.get(t + 1).operands[0] == reg) { - ConvertOutput assignment = toSourceOutput(lineStartItem, path, part, processJumps, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, abc, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited, localRegAssigmentIps, refs); + ConvertOutput assignment = toSourceOutput(thisHasDefaultToPrimitive, lineStartItem, path, part, processJumps, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, abc, body, ip + 2, t - 1, localRegNames, fullyQualifiedNames, visited, localRegAssigmentIps, refs); if (!assignment.output.isEmpty()) { GraphTargetItem tar = assignment.output.remove(assignment.output.size() - 1); tar.firstPart = part; @@ -1667,21 +1667,21 @@ public class AVM2Code implements Cloneable { } stack.push(vx); } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); } ip++; break; //} } else { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); ip++; break; //throw new ConvertException("Unknown pattern after DUP:" + insComparsion.toString()); } } while (ins.definition instanceof DupIns); } else if ((ins.definition instanceof ReturnValueIns) || (ins.definition instanceof ReturnVoidIns) || (ins.definition instanceof ThrowIns)) { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); //ip = end + 1; break; } else if (ins.definition instanceof NewFunctionIns) { @@ -1717,13 +1717,13 @@ public class AVM2Code implements Cloneable { } } // What to do when hasDup is false? - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); NewFunctionAVM2Item nft = (NewFunctionAVM2Item) stack.peek(); nft.functionName = functionName; ip++; } else { try { - ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this); + ins.definition.translate(lineStartItem, isStatic, scriptIndex, classIndex, localRegs, stack, scopeStack, ins, output, body, abc, localRegNames, fullyQualifiedNames, path, localRegAssigmentIps, ip, refs, this, thisHasDefaultToPrimitive); } catch (RuntimeException re) { /*String last=""; int len=5; @@ -1944,7 +1944,7 @@ public class AVM2Code implements Cloneable { }*/ } - public List toGraphTargetItems(ConvertData convertData, String path, int methodIndex, boolean isStatic, int scriptIndex, int classIndex, ABC abc, MethodBody body, HashMap localRegNames, ScopeStack scopeStack, int initializerType, List fullyQualifiedNames, List initTraits, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs) throws InterruptedException { + public List toGraphTargetItems(boolean thisHasDefaultToPrimitive, ConvertData convertData, String path, int methodIndex, boolean isStatic, int scriptIndex, int classIndex, ABC abc, MethodBody body, HashMap localRegNames, ScopeStack scopeStack, int initializerType, List fullyQualifiedNames, List initTraits, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs) throws InterruptedException { initToSource(); List list; HashMap localRegs = new HashMap<>(); @@ -1955,7 +1955,7 @@ public class AVM2Code implements Cloneable { } //try { - list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs); + list = AVM2Graph.translateViaGraph(path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive); if (initTraits != null) { loopi: diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 239af183b..d71e9b2fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -105,10 +105,11 @@ public class AVM2Graph extends Graph { } - public static List translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, ScopeStack scopeStack, HashMap localRegNames, List fullyQualifiedNames, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs) throws InterruptedException { + public static List translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, ScopeStack scopeStack, HashMap localRegNames, List fullyQualifiedNames, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs, boolean thisHasDefaultToPrimitive) throws InterruptedException { AVM2Graph g = new AVM2Graph(code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs); AVM2LocalData localData = new AVM2LocalData(); + localData.thisHasDefaultToPrimitive = thisHasDefaultToPrimitive; localData.isStatic = isStatic; localData.classIndex = classIndex; localData.localRegs = localRegs; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java index fbe5aea20..39b5e073f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java @@ -105,7 +105,7 @@ public class AVM2GraphSource extends GraphSource { List ret = new ArrayList<>(); ScopeStack newstack = ((AVM2LocalData) localData).scopeStack; Reference lineStartItem = new Reference<>(localData.lineStartInstruction); - ConvertOutput co = code.toSourceOutput(lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, newstack, abc, body, start, end, localRegNames, fullyQualifiedNames, new boolean[size()], localRegAssigmentIps, refs); + ConvertOutput co = code.toSourceOutput(((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, newstack, abc, body, start, end, localRegNames, fullyQualifiedNames, new boolean[size()], localRegAssigmentIps, refs); localData.lineStartInstruction = lineStartItem.getVal(); ret.addAll(co.output); return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java index cc4583715..5b4d54372 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java @@ -40,6 +40,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.decompiler.graph.TranslateStack; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -145,7 +146,7 @@ public abstract class InstructionDefinition implements Serializable { public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List output, String path) throws InterruptedException { } - public void translate(Reference lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2Instruction ins, List output, MethodBody body, ABC abc, HashMap localRegNames, List fullyQualifiedNames, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) throws InterruptedException { + public void translate(Reference lineStartItem, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, TranslateStack stack, ScopeStack scopeStack, AVM2Instruction ins, List output, MethodBody body, ABC abc, HashMap localRegNames, List fullyQualifiedNames, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code, boolean thisHasDefaultToPrimitive) throws InterruptedException { AVM2LocalData localData = new AVM2LocalData(); localData.isStatic = isStatic; localData.scriptIndex = scriptIndex; @@ -161,6 +162,7 @@ public abstract class InstructionDefinition implements Serializable { localData.ip = ip; localData.refs = refs; localData.code = code; + localData.thisHasDefaultToPrimitive = thisHasDefaultToPrimitive; translate(localData, stack, ins, output, path); lineStartItem.setVal(localData.lineStartInstruction); } @@ -198,7 +200,7 @@ public abstract class InstructionDefinition implements Serializable { } } - return new FullMultinameAVM2Item(property, ins, localData.lineStartInstruction, multinameIndex, name, ns); + return new FullMultinameAVM2Item(property, ins, localData.lineStartInstruction, multinameIndex, localData.abc.constants.getMultiname(multinameIndex).getName(localData.getConstants(), new ArrayList<>(), true), name, ns); } protected int getMultinameRequiredStackSize(AVM2ConstantPool constants, int multinameIndex) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/arithmetic/AddIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/arithmetic/AddIns.java index e046de835..f2abdf771 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/arithmetic/AddIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/arithmetic/AddIns.java @@ -41,8 +41,8 @@ public class AddIns extends InstructionDefinition { @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - Object right = lda.operandStack.pop(); - Object left = lda.operandStack.pop(); + Object right = EcmaScript.toPrimitive(lda.operandStack.pop(), ""); + Object left = EcmaScript.toPrimitive(lda.operandStack.pop(), ""); if (EcmaScript.type(left) == EcmaType.STRING || EcmaScript.type(right) == EcmaType.STRING) { String ret = EcmaScript.toString(left) + EcmaScript.toString(right); lda.operandStack.push(ret); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java index 10f8a619e..1c2833e48 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java @@ -69,22 +69,7 @@ public abstract class GetLocalTypeIns extends InstructionDefinition { } else { List ts = localData.getInstanceInfo().get(localData.classIndex).instance_traits.traits; - boolean isBasicObject = true; - if (!"Object".equals(localData.getConstants().getMultiname(localData.getInstanceInfo().get(localData.classIndex).super_index).getNameWithNamespace(localData.getConstants()).toRawString())) { - //TODO: check for toString and valueOf in parent object - isBasicObject = false; - } else { - for (Trait t : ts) { - if (t instanceof TraitMethodGetterSetter) { - if ("toString".equals(t.getName(localData.abc).getName(localData.getConstants(), new ArrayList<>(), true))) { - isBasicObject = false; - } - if ("valueOf".equals(t.getName(localData.abc).getName(localData.getConstants(), new ArrayList<>(), true))) { - isBasicObject = false; - } - } - } - } + boolean isBasicObject = localData.thisHasDefaultToPrimitive; Multiname m = localData.getInstanceInfo().get(localData.classIndex).getName(localData.getConstants()); stack.push(new ThisAVM2Item(ins, localData.lineStartInstruction, m, m.getNameWithNamespace(localData.getConstants()), isBasicObject)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/GetPropertyIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/GetPropertyIns.java index 3dfe6a39d..5830690d3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/GetPropertyIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/GetPropertyIns.java @@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.ecma.ArrayType; import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.EcmaType; import com.jpexs.decompiler.flash.ecma.ObjectType; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -50,6 +51,7 @@ public class GetPropertyIns extends InstructionDefinition { if (constants.getMultiname(ins.operands[0]).kind == Multiname.MULTINAMEL) { String name = EcmaScript.toString(lda.operandStack.pop()); Object obj = lda.operandStack.pop(); + if (obj == ArrayType.EMPTY_ARRAY) { if ("length".equals(name)) { lda.operandStack.push(0L); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java index 85c3d81b1..0256e9a6a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java @@ -26,8 +26,10 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.AsTypeAVM2Item; import com.jpexs.decompiler.flash.ecma.NotCompileTime; +import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; +import java.util.ArrayList; import java.util.List; /** @@ -55,7 +57,7 @@ public class AsTypeIns extends InstructionDefinition { public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List output, String path) { GraphTargetItem val = stack.pop(); - stack.push(new AsTypeAVM2Item(ins, localData.lineStartInstruction, val, new FullMultinameAVM2Item(false, ins, localData.lineStartInstruction, ins.operands[0]))); + stack.push(new AsTypeAVM2Item(ins, localData.lineStartInstruction, val, new FullMultinameAVM2Item(false, ins, localData.lineStartInstruction, ins.operands[0], localData.abc.constants.getMultiname(ins.operands[0]).getName(localData.getConstants(), new ArrayList<>(), true)))); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/IsTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/IsTypeIns.java index b8047c19b..b50019d7a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/IsTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/IsTypeIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.IsTypeAVM2Item; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; +import java.util.ArrayList; import java.util.List; /** @@ -41,7 +42,7 @@ public class IsTypeIns extends InstructionDefinition { public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List output, String path) { int multinameIndex = ins.operands[0]; GraphTargetItem value = stack.pop(); - stack.push(new IsTypeAVM2Item(ins, localData.lineStartInstruction, value, new FullMultinameAVM2Item(false, ins, localData.lineStartInstruction, multinameIndex))); + stack.push(new IsTypeAVM2Item(ins, localData.lineStartInstruction, value, new FullMultinameAVM2Item(false, ins, localData.lineStartInstruction, multinameIndex, localData.abc.constants.getMultiname(multinameIndex).getName(localData.getConstants(), new ArrayList<>(), true)))); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CallAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CallAVM2Item.java index 10892e0de..5035304f2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CallAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CallAVM2Item.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.graph.model.Callable; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.GraphSourceItem; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CoerceAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CoerceAVM2Item.java index 7d28c1408..63c72bb1f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CoerceAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/CoerceAVM2Item.java @@ -67,7 +67,7 @@ public class CoerceAVM2Item extends AVM2Item { return false; } dependencies.add(value); - return value.isCompileTime(dependencies); + return value.isConvertedCompileTime(dependencies); } @Override @@ -81,10 +81,7 @@ public class CoerceAVM2Item extends AVM2Item { if (ret == Undefined.INSTANCE) { return Null.INSTANCE; } - if (ret == null) { - return null; - } - return ret.toString(); + return value.getResultAsString(); case "*": break; } 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 b5248f3c0..fcefb3b73 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 @@ -66,7 +66,7 @@ public class ConvertAVM2Item extends AVM2Item { case "uint": return EcmaScript.toUint32(value.getResult()); case "String": - return value.getResult().toString(); + return value.getResultAsString(); case "Object": return value.getResult(); //if not object throw TypeError default: @@ -80,7 +80,7 @@ public class ConvertAVM2Item extends AVM2Item { return false; } dependencies.add(value); - return value.isCompileTime(dependencies); + return value.isConvertedCompileTime(dependencies); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java index 821f80fdd..c0e12d4dc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java @@ -42,28 +42,33 @@ public class FullMultinameAVM2Item extends AVM2Item { public boolean property; - public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex, GraphTargetItem name) { + public String resolvedMultinameName; + + public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex, String resolvedMultinameName, GraphTargetItem name) { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); this.multinameIndex = multinameIndex; this.name = name; this.namespace = null; this.property = property; + this.resolvedMultinameName = resolvedMultinameName; } - public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex) { + public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex, String resolvedMultinameName) { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); this.multinameIndex = multinameIndex; + this.resolvedMultinameName = resolvedMultinameName; this.name = null; this.namespace = null; this.property = property; } - public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex, GraphTargetItem name, GraphTargetItem namespace) { + public FullMultinameAVM2Item(boolean property, GraphSourceItem instruction, GraphSourceItem lineStartIns, int multinameIndex, String resolvedMultinameName, GraphTargetItem name, GraphTargetItem namespace) { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); this.multinameIndex = multinameIndex; this.name = name; this.namespace = namespace; this.property = property; + this.resolvedMultinameName = resolvedMultinameName; } public boolean isRuntime() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/GetPropertyAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/GetPropertyAVM2Item.java index c29ee8f3d..f3f062d8f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/GetPropertyAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/GetPropertyAVM2Item.java @@ -20,11 +20,15 @@ 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.parser.script.AVM2SourceGenerator; +import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.EcmaType; +import com.jpexs.decompiler.flash.ecma.ObjectType; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.CompilationException; 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; @@ -41,8 +45,30 @@ public class GetPropertyAVM2Item extends AVM2Item { public GraphTargetItem propertyName; + @Override + public boolean isConvertedCompileTime(Set dependencies) { + if (object != null && object.isCompileTime() && (propertyName instanceof FullMultinameAVM2Item) && (((FullMultinameAVM2Item) propertyName).name != null) && (((FullMultinameAVM2Item) propertyName).name.isCompileTime()) && "constructor".equals(((FullMultinameAVM2Item) propertyName).name.getResult())) { + Object obj = object.getResult(); + EcmaType t = EcmaScript.type(obj); + if (t != EcmaType.OBJECT) { + if (t.getClassName() != null) { + //Note: it's for toString only :-( + return true; + } + } + if (obj instanceof ObjectType) { + //Note: it's for toString only :-( + return true; + } + } + return isCompileTime(dependencies); + } + @Override public boolean isCompileTime(Set dependencies) { + if ((object instanceof SimpleValue) && (((SimpleValue) object).isSimpleValue())) { + return true; + } if (object instanceof NewArrayAVM2Item) { if (((NewArrayAVM2Item) object).values.isEmpty()) { return true; @@ -56,8 +82,30 @@ public class GetPropertyAVM2Item extends AVM2Item { return false; } + @Override + public String getResultAsString() { + if (object.isCompileTime() && (propertyName instanceof FullMultinameAVM2Item) && (((FullMultinameAVM2Item) propertyName).name.isCompileTime()) && "constructor".equals(((FullMultinameAVM2Item) propertyName).name.getResult())) { + Object obj = object.getResult(); + EcmaType t = EcmaScript.type(obj); + if (t != EcmaType.OBJECT) { + if (t.getClassName() != null) { + return "[class " + t.getClassName() + "]"; + } + } + if (obj instanceof ObjectType) { + return "[class " + ((ObjectType) obj).getTypeName() + "]"; + } + } + return super.getResultAsString(); + } + @Override public Object getResult() { + Object ores = object.getResult(); + EcmaType type = EcmaScript.type(ores); + if (type != EcmaType.OBJECT && (propertyName instanceof FullMultinameAVM2Item) && (((FullMultinameAVM2Item) propertyName).resolvedMultinameName != null)) { + return type.getProperty(ores, ((FullMultinameAVM2Item) propertyName).resolvedMultinameName); + } if (object instanceof NewArrayAVM2Item) { if (((NewArrayAVM2Item) object).values.isEmpty()) { return Undefined.INSTANCE; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/RegExpAvm2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/RegExpAvm2Item.java index bebbd4618..d5580f43d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/RegExpAvm2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/RegExpAvm2Item.java @@ -1,5 +1,6 @@ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.graph.model.Callable; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/AddAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/AddAVM2Item.java index afb25072f..76b4f9ed0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/AddAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/operations/AddAVM2Item.java @@ -68,8 +68,10 @@ public class AddAVM2Item extends BinaryOpItem { public Object getResult() { Object leftResult = leftSide.getResult(); Object rightResult = rightSide.getResult(); + leftResult = EcmaScript.toPrimitive(leftResult, ""); + rightResult = EcmaScript.toPrimitive(rightResult, ""); if (EcmaScript.type(leftResult) == EcmaType.STRING || EcmaScript.type(rightResult) == EcmaType.STRING) { - return "" + leftResult + rightResult; + return EcmaScript.toString(leftResult) + EcmaScript.toString(rightResult); } return EcmaScript.toNumber(leftResult) + EcmaScript.toNumber(rightResult); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java index 5127497a3..bc7b64e7c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java @@ -31,6 +31,8 @@ public class ConvertData { public Map assignedValues = new HashMap<>(); + public boolean thisHasDefaultToPrimitive; + public ConvertData() { deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 3c758bdf1..8be0aca69 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -310,7 +310,7 @@ public final class MethodBody implements Cloneable { HashMap localRegNames = getLocalRegNames(abc); List convertedItems1; try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) { - convertedItems1 = converted.getCode().toGraphTargetItems(convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted)); + convertedItems1 = converted.getCode().toGraphTargetItems(convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted)); } try (Statistics s = new Statistics("Graph.graphToString")) { Graph.graphToString(convertedItems1, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java index 75d4e11b8..e3bccdfa9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.abc.types.traits; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing; import com.jpexs.decompiler.flash.abc.types.ClassInfo; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.abc.types.InstanceInfo; @@ -28,6 +29,7 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.NulWriter; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.helpers.Helper; import java.util.ArrayList; import java.util.List; @@ -219,6 +221,10 @@ public class TraitClass extends Trait implements TraitWithSlot { String instanceInfoName = instanceInfo.getName(abc.constants).getName(abc.constants, fullyQualifiedNames, false); ClassInfo classInfo = abc.class_info.get(class_info); + AbcIndexing index = new AbcIndexing(abc.getSwf()); + //for simplification of String(this) + convertData.thisHasDefaultToPrimitive = null == index.findProperty(new AbcIndexing.PropertyDef("toString", new TypeItem(instanceInfo.getName(abc.constants).getNameWithNamespace(abc.constants)), abc, abc.constants.getNamespaceId(Namespace.KIND_PACKAGE, DottedChain.TOPLEVEL, abc.constants.getStringId("", true), true)), false, true); + //class initializer int bodyIndex = abc.findBodyIndex(classInfo.cinit_index); if (bodyIndex != -1) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java index c58556dca..1986fe97b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java @@ -112,9 +112,10 @@ public class EcmaScript { //TODO: logic similar to 8.12.8 return o.call("toString", new ArrayList<>()); case "Number": - default: //TODO: logic similar to 8.12.8 return o.call("valueOf", new ArrayList<>()); + default: + return o.toPrimitive(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaType.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaType.java index 4d8b58842..e920b7944 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaType.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaType.java @@ -12,19 +12,46 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.ecma; +import com.jpexs.decompiler.graph.model.Callable; + /** * * @author JPEXS */ public enum EcmaType { - NULL, - STRING, - NUMBER, - UNDEFINED, - OBJECT, - BOOLEAN + NULL(null), + STRING("String"), + NUMBER("Number"), + UNDEFINED(null), + OBJECT("Object"), + BOOLEAN("Boolean"); + + private String clsName; + + private EcmaType(String clsName) { + this.clsName = clsName; + } + + public String getClassName() { + return clsName; + } + + public Object getProperty(Object val, String propName) { + String cls = getClassName(); + if (cls == null) { + return null; + } + if ("String".equals(cls)) { + switch (propName) { + case "length": + return EcmaScript.toString(val).length(); + } + } + return null; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/ObjectType.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/ObjectType.java index 6b8e53bb2..cd4432b7d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/ObjectType.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/ObjectType.java @@ -16,7 +16,7 @@ */ package com.jpexs.decompiler.flash.ecma; -import com.jpexs.decompiler.flash.abc.avm2.model.Callable; +import com.jpexs.decompiler.graph.model.Callable; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,7 +57,15 @@ public class ObjectType implements Callable { @Override public String toString() { - return "[object Object]"; + return "[object " + getTypeName() + "]"; + } + + public String getTypeName() { + return "Object"; + } + + public Object toPrimitive() { + return toString(); } @Override 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 769b193bf..8a3e1073a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java @@ -386,6 +386,10 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { return EcmaScript.toNumberAs2(getResult()); } + public String getResultAsString() { + return EcmaScript.toString(getResult()); + } + public String toStringNoQuotes(LocalData localData) { // todo: honfika: this method should not be called, maybe we should throw an exception return toString(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/Callable.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/Callable.java similarity index 94% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/Callable.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/Callable.java index ae0e339e8..c3549fc26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/Callable.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/Callable.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library. */ -package com.jpexs.decompiler.flash.abc.avm2.model; +package com.jpexs.decompiler.graph.model; import java.util.List;