Fixed #2437 AS1 P-code - do not group pushes automatically,

AS1 Direct editation - group pushes on FP5+,
AS1 - use Constant pool only on FP5+
This commit is contained in:
Jindra Petřík
2025-04-06 11:54:44 +02:00
parent 187364a2e4
commit c145a76df7
7 changed files with 130 additions and 119 deletions

View File

@@ -728,20 +728,14 @@ public abstract class Action implements GraphSourceItem {
}
} else {
//if (!(a instanceof ActionNop)) {
String add = "";
// honfika: commented out the following lines, because it makes no sense
/*if (a instanceof ActionIf) {
add = " change: " + ((ActionIf) a).getJumpOffset();
}
if (a instanceof ActionJump) {
add = " change: " + ((ActionJump) a).getJumpOffset();
}
add = "; ofs" + Helper.formatAddress(offset) + add;
add = "";*/
if ((a instanceof ActionPush) && lastPush) {
String add = "";
//Flash player 4 does not allow more than 1 item in ActionPush, so I commented this out
/*if ((a instanceof ActionPush) && lastPush) {
writer.appendNoHilight(", ");
((ActionPush) a).paramsToStringReplaced(list, importantOffsets, exportMode, writer);
} else {
} else
*/
{
if (lastPush) {
writer.newLine();
//lastPush = false;

View File

@@ -422,10 +422,12 @@ public class ASMParser {
ActionList list = new ActionList(charset);
Stack<GraphSourceItemContainer> containers = new Stack<>();
ActionConstantPool cpool = new ActionConstantPool(constantPool, charset);
cpool.setAddress(address);
address += cpool.getTotalActionLength();
list.add(cpool);
if (!constantPool.isEmpty()) {
ActionConstantPool cpool = new ActionConstantPool(constantPool, charset);
cpool.setAddress(address);
address += cpool.getTotalActionLength();
list.add(cpool);
}
while (true) {
ASMParsedSymbol symb = lexer.lex();

View File

@@ -2147,6 +2147,12 @@ public class ActionScript2Parser {
}
private DirectValueActionItem pushConst(String s) throws IOException, ActionParseException {
//ActionConstantPool was introduced in SWF 5
if (swfVersion < 5) {
return new DirectValueActionItem(null, null, 0, s, constantPool);
}
int index = constantPool.indexOf(s);
if (index == -1) {
if (ActionConstantPool.calculateSize(constantPool) + ActionConstantPool.calculateSize(s) <= 0xffff) {
@@ -2467,7 +2473,9 @@ public class ActionScript2Parser {
ret.add((Action) s);
}
}
ret.add(0, new ActionConstantPool(constantPool, charset));
if (!constantPool.isEmpty()) {
ret.add(0, new ActionConstantPool(constantPool, charset));
}
return ret;
}

View File

@@ -135,11 +135,35 @@ public class ActionSourceGenerator implements SourceGenerator {
* @return List of Action
*/
public List<Action> toActionList(List<GraphSourceItem> items) {
items = groupPushes(items);
List<Action> ret = new ArrayList<>();
for (GraphSourceItem s : items) {
for (GraphSourceItem s : items) {
if (s instanceof Action) {
ret.add((Action) s);
ret.add((Action) s);
}
}
return ret;
}
private List<GraphSourceItem> groupPushes(List<GraphSourceItem> items) {
if (swfVersion <= 4) {
return items;
}
List<GraphSourceItem> ret = new ArrayList<>();
ActionPush prevPush = null;
for (GraphSourceItem s : items) {
if (s instanceof ActionPush) {
if (prevPush == null) {
prevPush = (ActionPush) s;
ret.add(prevPush);
} else {
prevPush.values.addAll(((ActionPush) s).values);
((ActionPush) s).values.clear();
}
} else {
ret.add(s);
prevPush = null;
}
}
return ret;
}
@@ -988,6 +1012,7 @@ public class ActionSourceGenerator implements SourceGenerator {
for (GraphTargetItem item : commands) {
ret.addAll(item.toSourceIgnoreReturnValue(localData, this));
}
ret = groupPushes(ret);
return ret;
}

View File

@@ -171,8 +171,7 @@ public class ActionScript2CompilerTest extends ActionScript2TestBase {
@Test
public void stopUndefined() {
testCompilation("trace(stop());", "ConstantPool\n"
+ "Stop\n"
testCompilation("trace(stop());", "Stop\n"
+ "Push undefined, undefined\n"
+ "Trace");
}

View File

@@ -174,8 +174,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
@Test
public void testRemoveJumpAction() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "Return\n"
+ "}\n"
@@ -184,20 +183,19 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ // remove this action
"label_1:Push 3";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "Return\n"
+ "}\n"
+ "Push 2, 3";
testRemoveAction(actionsString, expectedResult, new int[]{5});
+ "Push 2\n"
+ "Push 3";
testRemoveAction(actionsString, expectedResult, new int[]{4});
}
@Test
public void testRemoveActionFromContainer() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n" // remove this action
+ "Return\n"
+ "}\n"
@@ -205,43 +203,39 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Jump label_1\n"
+ "label_1:Push 3";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Return\n"
+ "}\n"
+ "Push 2\n"
+ "Jump label_1\n"
+ "label_1:Push 3";
testRemoveAction(actionsString, expectedResult, new int[]{1});
}
@Test
public void testRemoveLastActionFromContainer() {
String actionsString
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n" // remove this action
+ "}\n"
+ "Push 2\n"
+ "Jump label_1\n"
+ "label_1:Push 3";
String expectedResult
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "}\n"
+ "Push 2\n"
+ "Jump label_1\n"
+ "label_1:Push 3";
testRemoveAction(actionsString, expectedResult, new int[]{2});
}
@Test
public void testRemoveLastActionFromContainer() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n" // remove this action
+ "}\n"
+ "Push 2\n"
+ "Jump label_1\n"
+ "label_1:Push 3";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "}\n"
+ "Push 2\n"
+ "Jump label_1\n"
+ "label_1:Push 3";
testRemoveAction(actionsString, expectedResult, new int[]{3});
}
@Test
public void testRemoveIfTargetAction() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -251,8 +245,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "label_1:Push 4\n" // remove this action
+ "Push 5"; // after removing the previous action the if action should jump here
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -260,14 +253,13 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 5";
testRemoveAction(actionsString, expectedResult, new int[]{7});
testRemoveAction(actionsString, expectedResult, new int[]{6});
}
@Test
public void testRemoveIfTargetLastAction() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -276,8 +268,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Push 3\n"
+ "label_1:Push 4"; // remove this action
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -285,14 +276,13 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:";
testRemoveAction(actionsString, expectedResult, new int[]{7});
testRemoveAction(actionsString, expectedResult, new int[]{6});
}
@Test
public void testAddActionFirst() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -302,7 +292,6 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "label_1:Push 4";
String expectedResult
= "GetMember\n"
+ "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
@@ -318,8 +307,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
@Test
public void testAddAction1() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -328,8 +316,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Push 3\n"
+ "label_1:Push 4";
String expectedResult
= "ConstantPool\n"
+ "GetMember\n"
= "GetMember\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
@@ -338,42 +325,39 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 0);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 0);
}
@Test
public void testAddActionToContainer() {
String actionsString
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
+ "Push 2\n"
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
String expectedResult
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "GetMember\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
+ "Push 2\n"
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 1);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 1);
}
@Test
public void testAddActionToContainer() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
+ "Push 2\n"
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
+ "GetMember\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
+ "Push 2\n"
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 2);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 2);
}
@Test
public void testAddActionIf() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -382,8 +366,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Push 3\n"
+ "label_1:Push 4";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -392,15 +375,14 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Push 3\n"
+ "GetMember\n"
+ "label_1:Push 4";
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 7);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 7);
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 6);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 6);
}
@Test
public void testAddActionAfterContainer() {
String actionsString
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -409,8 +391,7 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "Push 3\n"
+ "label_1:Push 4";
String expectedResult
= "ConstantPool\n"
+ "DefineFunction \"test\", 1, \"p1\" {\n"
= "DefineFunction \"test\", 1, \"p1\" {\n"
+ "Push 1\n"
+ "GetVariable\n"
+ "}\n"
@@ -419,23 +400,21 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "If label_1\n"
+ "Push 3\n"
+ "label_1:Push 4";
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 4);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 4);
testAddActionNormal(actionsString, expectedResult, new ActionGetMember(), 3);
testAddActionFast(actionsString, expectedResult, new ActionGetMember(), 3);
}
@Test
public void testAddToJumpTarget() {
String actionsString
= "ConstantPool\n"
+ "If label_1\n"
= "If label_1\n"
+ "GetMember\n"
+ "label_1:Jump label_2\n" // address 9
+ "label_1:Jump label_2\n" // address 6
+ "label_2:Jump label_3\n"
+ "label_3:Jump labelend\n"
+ "labelend:End"; // address 24
+ "labelend:End"; // address 21
String expectedResult
= "ConstantPool\n"
+ "If label_1\n"
= "If label_1\n"
+ "GetMember\n"
+ "Jump label_4\n"
+ "label_1:Jump label_2\n"
@@ -443,9 +422,9 @@ public class ActionScript2ModificationTest extends ActionScript2TestBase {
+ "label_3:Jump label_4\n"
+ "label_4:";
ActionJump jump = new ActionJump(0, Utf8Helper.charsetName);
jump.setAddress(9);
jump.setJumpOffset(24 - 9 - 5);
testAddActionNormal(actionsString, expectedResult, jump, 3);
testAddActionFast(actionsString, expectedResult, jump, 3);
jump.setAddress(6);
jump.setJumpOffset(21 - 6 - 5);
testAddActionNormal(actionsString, expectedResult, jump, 2);
testAddActionFast(actionsString, expectedResult, jump, 2);
}
}