diff --git a/CHANGELOG.md b/CHANGELOG.md index 06be157ff..748a0c4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Fixed - #1114 Script search results dialogs closing on swf close - #1159 Regexp syntax hilight when not a regexp (only division) +- #1227 AS3 avoid recursion (stackoverflow) caused by newfunction instruction ## [13.0.2] - 2021-02-10 ### Changed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 3e0d91c73..22fa3336d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -3635,7 +3635,7 @@ public final class SWF implements SWFContainerItem, Timelined { int mi = ((TraitMethodGetterSetter) t).method_info; try { - documentPack.abc.findBody(mi).convert(new ConvertData(), "??", ScriptExportMode.AS, true, mi, documentPack.scriptIndex, cindex, documentPack.abc, t, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + documentPack.abc.findBody(mi).convert(new ConvertData(), "??", ScriptExportMode.AS, true, mi, documentPack.scriptIndex, cindex, documentPack.abc, t, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); List infos = documentPack.abc.findBody(mi).convertedItems; if (!infos.isEmpty()) { if (infos.get(0) instanceof IfItem) { @@ -3711,7 +3711,7 @@ public final class SWF implements SWFContainerItem, Timelined { if (tr instanceof TraitClass) { int ci = ((TraitClass) tr).class_info; int cinit = p.abc.class_info.get(ci).cinit_index; - p.abc.findBody(cinit).convert(new ConvertData(), "??", ScriptExportMode.AS, true, cinit, p.scriptIndex, cindex, p.abc, t, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + p.abc.findBody(cinit).convert(new ConvertData(), "??", ScriptExportMode.AS, true, cinit, p.scriptIndex, cindex, p.abc, t, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); List cinitBody = p.abc.findBody(cinit).convertedItems; for (GraphTargetItem cit : cinitBody) { if (cit instanceof SetPropertyAVM2Item) { 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 79a65900a..eb5cab1af 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 @@ -118,6 +118,8 @@ public class AVM2LocalData extends BaseLocalData { public boolean inGetLoops = false; + public Set seenMethods = new HashSet<>(); + public AVM2LocalData() { } @@ -165,6 +167,7 @@ public class AVM2LocalData extends BaseLocalData { finallyTargetParts = localData.finallyTargetParts; pushDefaultPart = localData.pushDefaultPart; finallyKinds = localData.finallyKinds; + seenMethods = localData.seenMethods; } public AVM2ConstantPool getConstants() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 6485f5c8e..aa93f6c8d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -176,7 +176,7 @@ public class ScriptPack extends AS3ClassTreeItem { } ts.add(abc.script_info.get(scriptIndex).traits); writer.mark(); - abc.bodies.get(sinit_bodyIndex).convert(convertData, path +/*packageName +*/ "/.scriptinitializer", exportMode, true, sinit_index, scriptIndex, -1, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_SCRIPT_INITIALIZER, writer, new ArrayList<>(), ts, true); + abc.bodies.get(sinit_bodyIndex).convert(convertData, path +/*packageName +*/ "/.scriptinitializer", exportMode, true, sinit_index, scriptIndex, -1, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_SCRIPT_INITIALIZER, writer, new ArrayList<>(), ts, true, new HashSet<>()); scriptInitializerIsEmpty = !writer.getMark(); } @@ -205,7 +205,7 @@ public class ScriptPack extends AS3ClassTreeItem { if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!scriptInitializerIsEmpty) { writer.startBlock(); - abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/.scriptinitializer", exportMode, abc, null, writer, new ArrayList<>()); + abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/.scriptinitializer", exportMode, abc, null, writer, new ArrayList<>(), new HashSet<>()); writer.endBlock(); } else { writer.append(" "); 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 8465055be..544187a84 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 @@ -802,10 +802,10 @@ public class AVM2Code implements Cloneable { } public void calculateDebugFileLine(ABC abc) { - calculateDebugFileLine(null, 0, 0, abc, new HashSet<>()); + calculateDebugFileLine(null, 0, 0, abc, new HashSet<>(), new HashSet<>()); } - private boolean calculateDebugFileLine(String debugFile, int debugLine, int pos, ABC abc, Set seen) { + private boolean calculateDebugFileLine(String debugFile, int debugLine, int pos, ABC abc, Set seen, Set seenMethods) { while (pos < code.size()) { AVM2Instruction ins = code.get(pos); if (seen.contains(pos)) { @@ -828,10 +828,15 @@ public class AVM2Code implements Cloneable { //Only analyze NewFunction objects that are not immediately discarded by Pop. //This avoids bogus functions used in obfuscation or special compilers that can lead to infinite recursion. if ((pos + 1 < code.size()) && !(code.get(pos + 1).definition instanceof PopIns)) { - MethodBody innerBody = abc.findBody(ins.operands[0]); - if (innerBody != null) { //Ignore functions without body - innerBody.getCode().calculateDebugFileLine(debugFile, debugLine, 0, abc, new HashSet<>()); + int newMethodInfo = ins.operands[0]; + if (!seenMethods.contains(newMethodInfo)) { //avoid recursion + MethodBody innerBody = abc.findBody(newMethodInfo); + if (innerBody != null) { //Ignore functions without body + seenMethods.add(newMethodInfo); + innerBody.getCode().calculateDebugFileLine(debugFile, debugLine, 0, abc, new HashSet<>(), seenMethods); + } } + } } @@ -851,7 +856,7 @@ public class AVM2Code implements Cloneable { } else if (ins.definition instanceof IfTypeIns) { try { int newpos = adr2pos(ins.getTargetAddress()); - calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen); + calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen, seenMethods); } catch (ConvertException ex) { return false; } @@ -863,7 +868,7 @@ public class AVM2Code implements Cloneable { } try { int newpos = adr2pos(pos2adr(pos) + ins.operands[i]); - if (!calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen)) { + if (!calculateDebugFileLine(debugFile, debugLine, newpos, abc, seen, seenMethods)) { return false; } } catch (ConvertException ex) { @@ -1990,7 +1995,6 @@ public class AVM2Code implements Cloneable { } } }*/ - if (value instanceof NewFunctionAVM2Item) { NewFunctionAVM2Item f = (NewFunctionAVM2Item) value; f.functionName = tsc.getName(abc).getName(abc.constants, fullyQualifiedNames, true, true); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java index 32574cab0..e9f6464d0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/CodeStats.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.HashSet; import java.util.List; /** @@ -51,7 +52,7 @@ public class CodeStats { if (stats.stackpos > ms) { ms = stats.stackpos; } - writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(abc, null, fullyQualifiedNames))).newLine(); + writer.appendNoHilight(i + ":" + stats.stackpos + (deltastack >= 0 ? "+" + deltastack : deltastack) + "," + stats.scopepos + " " + stats.ins.toString(writer, LocalData.create(abc, null, fullyQualifiedNames, new HashSet<>()))).newLine(); i++; } return writer; 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 8d9ba6e84..3f78f2156 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 @@ -1643,8 +1643,8 @@ public class AVM2Graph extends Graph { FullMultinameAVM2Item gptXmlMult = (FullMultinameAVM2Item) gpt.propertyName; try { - isXMLList = fptXmlMult.isTopLevel("XMLList", aLocalData.abc, aLocalData.localRegNames, aLocalData.fullyQualifiedNames) - && gptXmlMult.isTopLevel("XMLList", aLocalData.abc, aLocalData.localRegNames, aLocalData.fullyQualifiedNames); + isXMLList = fptXmlMult.isTopLevel("XMLList", aLocalData.abc, aLocalData.localRegNames, aLocalData.fullyQualifiedNames, aLocalData.seenMethods) + && gptXmlMult.isTopLevel("XMLList", aLocalData.abc, aLocalData.localRegNames, aLocalData.fullyQualifiedNames, aLocalData.seenMethods); } catch (InterruptedException ex) { //ignore } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java index 96f490432..af27a2ebf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java @@ -107,8 +107,8 @@ public class ConstructIns extends InstructionDefinition { FullMultinameAVM2Item fptXmlMult = (FullMultinameAVM2Item) fpt.propertyName; FullMultinameAVM2Item gptXmlMult = (FullMultinameAVM2Item) gpt.propertyName; - isXML = fptXmlMult.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames) - && gptXmlMult.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames); + isXML = fptXmlMult.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods) + && gptXmlMult.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods); } } if (obj instanceof GetLexAVM2Item) { @@ -135,8 +135,8 @@ public class ConstructIns extends InstructionDefinition { FullMultinameAVM2Item fptRegExpMult = (FullMultinameAVM2Item) fpt.propertyName; FullMultinameAVM2Item gptRegExpMult = (FullMultinameAVM2Item) gpt.propertyName; - isRegExp = fptRegExpMult.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames) - && gptRegExpMult.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames); + isRegExp = fptRegExpMult.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods) + && gptRegExpMult.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods); } } if (obj instanceof GetLexAVM2Item) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java index 3857be2f0..39a63deda 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java @@ -74,7 +74,7 @@ public class ConstructPropIns extends InstructionDefinition { multiname.property = false; //can be type } - if (multiname.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames)) { + if (multiname.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods)) { if (args.size() == 1) { GraphTargetItem arg = args.get(0); List xmlLines = new ArrayList<>(); @@ -85,7 +85,7 @@ public class ConstructPropIns extends InstructionDefinition { } }// boolean isRegExp = false; - if (multiname.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames)) { + if (multiname.isTopLevel("RegExp", localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods)) { isRegExp = true; } if (isRegExp && (args.size() >= 1) && (args.get(0) instanceof StringAVM2Item) && (args.size() == 1 || (args.size() == 2 && args.get(1) instanceof StringAVM2Item))) { 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 90554d33d..9134bbea3 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 @@ -29,6 +29,7 @@ import com.jpexs.decompiler.graph.model.LocalData; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; /** * @@ -87,16 +88,16 @@ public class FullMultinameAVM2Item extends AVM2Item { return (name != null) || (namespace != null); } - public boolean isTopLevel(String tname, ABC abc, HashMap localRegNames, List fullyQualifiedNames) throws InterruptedException { + public boolean isTopLevel(String tname, ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods) throws InterruptedException { String cname; if (name != null) { - cname = name.toString(LocalData.create(abc, localRegNames, fullyQualifiedNames)); + cname = name.toString(LocalData.create(abc, localRegNames, fullyQualifiedNames, seenMethods)); } else { cname = (abc.constants.getMultiname(multinameIndex).getName(abc.constants, fullyQualifiedNames, true, true)); } String cns = ""; if (namespace != null) { - cns = namespace.toString(LocalData.create(abc, localRegNames, fullyQualifiedNames)); + cns = namespace.toString(LocalData.create(abc, localRegNames, fullyQualifiedNames, seenMethods)); } else { Namespace ns = abc.constants.getMultiname(multinameIndex).getNamespace(abc.constants); if ((ns != null) && (ns.name_index != 0)) { @@ -106,8 +107,8 @@ public class FullMultinameAVM2Item extends AVM2Item { return cname.equals(tname) && cns.isEmpty(); } - public boolean isXML(ABC abc, HashMap localRegNames, List fullyQualifiedNames) throws InterruptedException { - return isTopLevel("XML", abc, localRegNames, fullyQualifiedNames); + public boolean isXML(ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods) throws InterruptedException { + return isTopLevel("XML", abc, localRegNames, fullyQualifiedNames, seenMethods); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java index efd7454fa..b2d1b8780 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java @@ -29,6 +29,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; +import java.util.HashSet; import java.util.List; /** @@ -70,6 +71,10 @@ public class NewFunctionAVM2Item extends AVM2Item { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + if (localData.seenMethods.contains(methodIndex)) { + return writer.append("§§method(").append(methodIndex).append(")"); + } + //if (methodIndex == 9141) MethodBody body = abc.findBody(methodIndex); writer.append("function"); writer.startMethod(methodIndex); @@ -87,8 +92,8 @@ public class NewFunctionAVM2Item extends AVM2Item { abc.method_info.get(methodIndex).getReturnTypeStr(writer, abc.constants, fullyQualifiedNames); writer.startBlock(); if (body != null) { - body.convert(new ConvertData(), path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, new ScopeStack(), 0, new NulWriter(), fullyQualifiedNames, null, false); - body.toString(path + "/inner", ScriptExportMode.AS, abc, null, writer, fullyQualifiedNames); + body.convert(new ConvertData(), path + "/inner", ScriptExportMode.AS, isStatic, methodIndex, scriptIndex, classIndex, abc, null, new ScopeStack(), 0, new NulWriter(), fullyQualifiedNames, null, false, new HashSet<>(localData.seenMethods)); + body.toString(path + "/inner", ScriptExportMode.AS, abc, null, writer, fullyQualifiedNames, new HashSet<>(localData.seenMethods)); } writer.endBlock(); writer.endMethod(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java index 535a41e3e..97fab6a1f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/parser/script/AVM2SourceGenerator.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.abc.avm2.parser.script; import com.jpexs.helpers.Reference; @@ -107,6 +108,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -1234,7 +1236,7 @@ public class AVM2SourceGenerator implements SourceGenerator { initt.add(ci.abc.class_info.get(ci.index).static_traits); try { - pcinit.convert(d, "-", ScriptExportMode.AS, true, mi, -1, ci.index, ci.abc, null, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, new NulWriter(), new ArrayList<>(), initt, false); + pcinit.convert(d, "-", ScriptExportMode.AS, true, mi, -1, ci.index, ci.abc, null, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, new NulWriter(), new ArrayList<>(), initt, false, new HashSet<>()); //FIXME! Add skinparts from _skinParts attribute of parent class!!! } catch (InterruptedException ex) { Logger.getLogger(AVM2SourceGenerator.class.getName()).log(Level.SEVERE, "Getting parent skinparts interrupted", ex); 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 bf362eef6..3a672f9e8 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 @@ -50,6 +50,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -285,7 +286,8 @@ public final class MethodBody implements Cloneable { return ret; } - public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List fullyQualifiedNames, final List initTraits, boolean firstLevel) throws InterruptedException { + public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List fullyQualifiedNames, final List initTraits, boolean firstLevel, Set seenMethods) throws InterruptedException { + seenMethods.add(this.method_info); if (debugMode) { System.err.println("Decompiling " + path); } @@ -310,7 +312,7 @@ public final class MethodBody implements Cloneable { 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, localRegNames, fullyQualifiedNames)); + Graph.graphToString(convertedItems1, writer, LocalData.create(abc, localRegNames, fullyQualifiedNames, seenMethods)); } convertedItems = convertedItems1; } @@ -326,6 +328,7 @@ public final class MethodBody implements Cloneable { throw ex; } catch (Exception | OutOfMemoryError | StackOverflowError ex) { convertException = ex; + ex.printStackTrace(); Throwable cause = ex.getCause(); if (ex instanceof ExecutionException && cause instanceof Exception) { convertException = (Exception) cause; @@ -340,7 +343,9 @@ public final class MethodBody implements Cloneable { } } - public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames) throws InterruptedException { + public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List fullyQualifiedNames, Set seenMethods) throws InterruptedException { + seenMethods.add(method_info); + if (exportMode != ScriptExportMode.AS) { getCode().toASMSource(abc, abc.constants, abc.method_info.get(this.method_info), this, exportMode, writer); } else { @@ -363,7 +368,7 @@ public final class MethodBody implements Cloneable { writer.appendNoHilight(this.method_info); writer.newLine(); } - Graph.graphToString(convertedItems, writer, LocalData.create(abc, localRegNames, fullyQualifiedNames)); + Graph.graphToString(convertedItems, writer, LocalData.create(abc, localRegNames, fullyQualifiedNames, seenMethods)); //writer.endMethod(); } else if (convertException instanceof TimeoutException) { // exception was logged in convert method @@ -413,14 +418,14 @@ public final class MethodBody implements Cloneable { return body; } - public String toSource(int scriptIndex) { + public String toSource(int scriptIndex, Set seenMethods) { ConvertData convertData = new ConvertData(); convertData.deobfuscationMode = 0; try { - convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, seenMethods); HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); writer.indent().indent().indent(); - toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>()); + toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), seenMethods); writer.unindent().unindent().unindent(); return writer.toString(); } catch (InterruptedException ex) { 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 5163a0636..1cb18b8e4 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 @@ -37,6 +37,7 @@ import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.helpers.Helper; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -136,7 +137,7 @@ public class TraitClass extends Trait implements TraitWithSlot { if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!classInitializerIsEmpty) { writer.startBlock(); - abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames); + abc.bodies.get(bodyIndex).toString(path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); writer.endBlock(); } else { //Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly @@ -184,7 +185,7 @@ public class TraitClass extends Trait implements TraitWithSlot { writer.appendNoHilight(")").startBlock(); if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (body != null) { - body.toString(path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, abc, this, writer, fullyQualifiedNames); + body.toString(path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); } } @@ -224,7 +225,7 @@ public class TraitClass extends Trait implements TraitWithSlot { writer.mark(); List ts = new ArrayList<>(); ts.add(classInfo.static_traits); - abc.bodies.get(bodyIndex).convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, true, classInfo.cinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, writer, fullyQualifiedNames, ts, true); + abc.bodies.get(bodyIndex).convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".staticinitializer", exportMode, true, classInfo.cinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_CLASS_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>()); classInitializerIsEmpty = !writer.getMark(); } @@ -234,7 +235,7 @@ public class TraitClass extends Trait implements TraitWithSlot { if (bodyIndex != -1) { List ts = new ArrayList<>(); ts.add(instanceInfo.instance_traits); - abc.bodies.get(bodyIndex).convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true); + abc.bodies.get(bodyIndex).convert(convertData, path +/*packageName +*/ "/" + instanceInfoName + ".initializer", exportMode, false, instanceInfo.iinit_index, scriptIndex, class_info, abc, this, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, writer, fullyQualifiedNames, ts, true, new HashSet<>()); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java index 12502d73e..a84d08f16 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -88,7 +89,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { writer.startBlock(); int bodyIndex = abc.findBodyIndex(method_info); if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false, true), exportMode, abc, this, writer, fullyQualifiedNames); + abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false, true), exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); } writer.endBlock(); @@ -105,7 +106,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); int bodyIndex = abc.findBodyIndex(method_info); if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false, true), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true); + abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false, true), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true, new HashSet<>()); } writer.endMethod(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index db6138605..5518e37a6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -33,6 +33,7 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -116,7 +117,7 @@ public class TraitMethodGetterSetter extends Trait { if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!(classIndex != -1 && abc.instance_info.get(classIndex).isInterface() || bodyIndex == -1)) { if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).convert(convertData, path, exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true); + abc.bodies.get(bodyIndex).convert(convertData, path, exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true, new HashSet<>()); } } } @@ -143,7 +144,7 @@ public class TraitMethodGetterSetter extends Trait { convertTraitHeader(abc, writer); } if (bodyIndex != -1) { - abc.bodies.get(bodyIndex).toString(path, exportMode, abc, this, writer, fullyQualifiedNames); + abc.bodies.get(bodyIndex).toString(path, exportMode, abc, this, writer, fullyQualifiedNames, new HashSet<>()); } } else { String retTypeRaw = abc.method_info.get(method_info).getReturnTypeRaw(abc.constants, fullyQualifiedNames); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java index a9291b3c0..ec5e9f24d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java @@ -39,6 +39,7 @@ import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.Helper; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; /** @@ -121,7 +122,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { writer.newLine(); } if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { - assignment.value.toString(writer, LocalData.create(abc, new HashMap<>(), fullyQualifiedNames)); + assignment.value.toString(writer, LocalData.create(abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>())); } writer.endMethod(); writer.endTrait(); @@ -161,7 +162,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { if (convertData.assignedValues.containsKey(this)) { GraphTargetItem val = convertData.assignedValues.get(this).value; if (val instanceof NewFunctionAVM2Item) { - return val.toString(writer, LocalData.create(abc, new HashMap<>(), fullyQualifiedNames)); + return val.toString(writer, LocalData.create(abc, new HashMap<>(), fullyQualifiedNames, new HashSet<>())); } } getNameStr(writer, abc, fullyQualifiedNames); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java index a95dd3ed4..97bc755c2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS3ScriptExporter.java @@ -106,7 +106,7 @@ public class AS3ScriptExporter { StringBuilder out = new StringBuilder(); int method = t.method_info; try { - pack.abc.findBody(method).convert(new ConvertData(), "??", ScriptExportMode.AS, false, method, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + pack.abc.findBody(method).convert(new ConvertData(), "??", ScriptExportMode.AS, false, method, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); List ci = pack.abc.findBody(method).convertedItems; if (!ci.isEmpty()) { @@ -179,7 +179,7 @@ public class AS3ScriptExporter { StringBuilder out = new StringBuilder(); int method = t.method_info; try { - pack.abc.findBody(method).convert(new ConvertData(), "??", ScriptExportMode.AS, false, method, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + pack.abc.findBody(method).convert(new ConvertData(), "??", ScriptExportMode.AS, false, method, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()/*??*/); List ci = pack.abc.findBody(method).convertedItems; if (!ci.isEmpty() && (ci.get(0) instanceof DeclarationAVM2Item)) { @@ -270,7 +270,7 @@ public class AS3ScriptExporter { int iinit = pack.abc.instance_info.get(cindex).iinit_index; try { - pack.abc.findBody(iinit).convert(new ConvertData(), "??", ScriptExportMode.AS, false, iinit, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + pack.abc.findBody(iinit).convert(new ConvertData(), "??", ScriptExportMode.AS, false, iinit, pack.scriptIndex, cindex, pack.abc, t, new ScopeStack(), 0/*?*/, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); List iinitBody = pack.abc.findBody(iinit).convertedItems; for (GraphTargetItem it : iinitBody) { if (it instanceof InitPropertyAVM2Item) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 296cc732e..360f95a8a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -2455,7 +2455,7 @@ public class XFLConverter { MethodBody constructorBody = abc.findBody(constructorMethodIndex); try { if (constructorBody.convertedItems == null) { - constructorBody.convert(new ConvertData(), "??", ScriptExportMode.AS, true, constructorMethodIndex, pack.scriptIndex, classIndex, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + constructorBody.convert(new ConvertData(), "??", ScriptExportMode.AS, true, constructorMethodIndex, pack.scriptIndex, classIndex, abc, null, new ScopeStack(), GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); } Map frameToTraitMultiname = new HashMap<>(); @@ -2518,9 +2518,9 @@ public class XFLConverter { MethodBody frameBody = abc.findBody(methodIndex); StringBuilder scriptBuilder = new StringBuilder(); - frameBody.convert(new ConvertData(), "??", ScriptExportMode.AS, false, methodIndex, pack.scriptIndex, classIndex, abc, methodTrait, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); + frameBody.convert(new ConvertData(), "??", ScriptExportMode.AS, false, methodIndex, pack.scriptIndex, classIndex, abc, methodTrait, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true, new HashSet<>()); StringBuilderTextWriter writer = new StringBuilderTextWriter(Configuration.getCodeFormatting(), scriptBuilder); - frameBody.toString("??", ScriptExportMode.AS, abc, methodTrait, writer, new ArrayList<>()); + frameBody.toString("??", ScriptExportMode.AS, abc, methodTrait, writer, new ArrayList<>(), new HashSet<>()); String script = scriptBuilder.toString(); ret.put(frame, script); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index a5511e574..f29ea1f75 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1759,9 +1759,6 @@ public class Graph { boolean vCanHandleVisited = canHandleVisited(localData, part); - /*if (part.start == 25) { - new RuntimeException().printStackTrace(); - }*/ if (vCanHandleVisited) { if (visited.contains(part)) { String labelName = "addr" + part.start; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java index 70f5b3a90..dfa132813 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/LocalData.java @@ -21,7 +21,9 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; import com.jpexs.decompiler.flash.action.model.ConstantPool; import com.jpexs.decompiler.graph.DottedChain; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * @@ -39,6 +41,8 @@ public class LocalData { public List fullyQualifiedNames; + public Set seenMethods = new HashSet<>(); + public ABC abc; public static LocalData create(ConstantPool constants) { @@ -47,12 +51,13 @@ public class LocalData { return localData; } - public static LocalData create(ABC abc, HashMap localRegNames, List fullyQualifiedNames) { + public static LocalData create(ABC abc, HashMap localRegNames, List fullyQualifiedNames, Set seenMethods) { LocalData localData = new LocalData(); localData.abc = abc; localData.constantsAvm2 = abc.constants; localData.localRegNames = localRegNames; localData.fullyQualifiedNames = fullyQualifiedNames; + localData.seenMethods = seenMethods; return localData; } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java index cef4bb645..f954c9c26 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DecompileTestBase.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import static org.testng.Assert.assertEquals; @@ -93,9 +94,9 @@ public abstract class ActionScript3DecompileTestBase extends ActionScriptTestBas Configuration.autoDeobfuscate.set(methodName.toLowerCase().contains("obfus")); - abc.bodies.get(bodyIndex).convert(new ConvertData(), "run", ScriptExportMode.AS, isStatic, abc.bodies.get(bodyIndex).method_info, scriptIndex, clsIndex, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), ts, true); + abc.bodies.get(bodyIndex).convert(new ConvertData(), "run", ScriptExportMode.AS, isStatic, abc.bodies.get(bodyIndex).method_info, scriptIndex, clsIndex, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), ts, true, new HashSet<>()); writer = new HighlightedTextWriter(new CodeFormatting(), false); - abc.bodies.get(bodyIndex).toString("run", ScriptExportMode.AS, abc, null, writer, new ArrayList<>()); + abc.bodies.get(bodyIndex).toString("run", ScriptExportMode.AS, abc, null, writer, new ArrayList<>(), new HashSet<>()); } catch (InterruptedException ex) { fail(); return; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java index 9b699fc7a..938498906 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/generators/AS3Generator.java @@ -38,6 +38,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -144,8 +145,8 @@ public class AS3Generator { Configuration.autoDeobfuscate.set(clsName.toLowerCase().contains("obfus")); - b.convert(new ConvertData(), "", ScriptExportMode.AS, false, ((TraitMethodGetterSetter) t).method_info, pack.scriptIndex, classId, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), ts, true); - b.toString("", ScriptExportMode.AS, abc, null, src, new ArrayList<>()); + b.convert(new ConvertData(), "", ScriptExportMode.AS, false, ((TraitMethodGetterSetter) t).method_info, pack.scriptIndex, classId, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), ts, true, new HashSet<>()); + b.toString("", ScriptExportMode.AS, abc, null, src, new ArrayList<>(), new HashSet<>()); String[] srcs = src.toString().split("[\r\n]+"); for (int i = 0; i < srcs.length; i++) { String ss = srcs[i];