2497 Swap instruction handling. WIP

This commit is contained in:
Jindra Petřík
2025-07-31 19:34:24 +02:00
parent 14dc0f9e08
commit b3a693e4e3
55 changed files with 366 additions and 36 deletions

View File

@@ -1390,6 +1390,7 @@ public class AVM2Graph extends Graph {
//should not happen
finallyCommands.clear();
}
stack.pop(); //duplicated switched value
stack.pop(); //value switched by lookupswitch
}
}

View File

@@ -62,6 +62,8 @@ import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.helpers.LinkedIdentityHashSet;
import com.jpexs.helpers.Reference;
import java.io.Serializable;
@@ -377,7 +379,8 @@ public abstract class InstructionDefinition implements Serializable {
* @param ins Instruction
* @return Resolved multiname
*/
protected FullMultinameAVM2Item resolveMultiname(AVM2LocalData localData, boolean property, TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) {
protected FullMultinameAVM2Item resolveMultiname(AVM2LocalData localData, boolean property, TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins, List<GraphTargetItem> output) {
stack.allowSwap(output);
GraphTargetItem ns = null;
GraphTargetItem name = null;
if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) {
@@ -543,15 +546,17 @@ public abstract class InstructionDefinition implements Serializable {
* @param path Path
*/
public void handleSetProperty(boolean init, AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.allowSwap(output);
int multinameIndex = ins.operands[0];
GraphTargetItem value = stack.pop();
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
//assembled/TestIncrement
if ((value instanceof IncrementAVM2Item) || (value instanceof DecrementAVM2Item)) {
boolean isIncrement = (value instanceof IncrementAVM2Item);
if (value.value instanceof DuplicateItem) {
GraphTargetItem duplicated = value.value.value;
stack.moveToStack(output);
if (!stack.isEmpty()) {
if (stack.peek() == duplicated) {
GraphTargetItem notCoerced = duplicated.getNotCoerced();
@@ -602,6 +607,7 @@ public abstract class InstructionDefinition implements Serializable {
GetLexAVM2Item getLex = (GetLexAVM2Item) value.value.getNotCoercedNoDup();
if (localData.abc.constants.getMultiname(multinameIndex).equals(getLex.propertyName)
&& (obj instanceof FindPropertyAVM2Item)) {
stack.moveToOutput(output, false);
if (hasConvert) {
if (isIncrement) {
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, getLex));
@@ -629,6 +635,7 @@ public abstract class InstructionDefinition implements Serializable {
}
}
if (Objects.equals(getProp.object, obj)) {
stack.moveToOutput(output, false);
if (hasConvert) {
if (isIncrement) {
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, getProp));
@@ -652,6 +659,7 @@ public abstract class InstructionDefinition implements Serializable {
GraphTargetItem duplicated = value.value;
if ((duplicated instanceof IncrementAVM2Item) || (duplicated instanceof DecrementAVM2Item)) {
boolean isIncrement = (duplicated instanceof IncrementAVM2Item);
stack.moveToStack(output);
if (!stack.isEmpty()) {
if (stack.peek() == duplicated) {
GraphTargetItem incrementedProp = duplicated.value;
@@ -702,7 +710,8 @@ public abstract class InstructionDefinition implements Serializable {
boolean isIncrement = (valueSetLocalReg.value instanceof IncrementAVM2Item);
if (valueSetLocalReg.value.value instanceof DuplicateItem) {
GraphTargetItem duplicated = valueSetLocalReg.value.value.value;
if (!stack.isEmpty() && stack.peek() == duplicated) {
if (output.size() >= 2 && output.get(output.size() - 2) instanceof PushItem && ((PushItem) output.get(output.size() - 2)).value == duplicated) {
//if (!stack.isEmpty() && stack.peek() == duplicated) {
GraphTargetItem notCoerced = duplicated.getNotCoerced();
if (notCoerced instanceof GetPropertyAVM2Item) {
GetPropertyAVM2Item getProperty = (GetPropertyAVM2Item) notCoerced;
@@ -723,7 +732,9 @@ public abstract class InstructionDefinition implements Serializable {
}
getProperty.object = objSetLocalReg.value;
output.remove(output.size() - 1);
stack.pop();
output.remove(output.size() - 1);
stack.moveToStack(output);
//stack.pop();
if (isIncrement) {
stack.push(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, getProperty));
} else {
@@ -739,6 +750,7 @@ public abstract class InstructionDefinition implements Serializable {
}
}
stack.moveToStack(output);
if (!stack.isEmpty()) {
GraphTargetItem checked = checkIncDec(false, multinameIndex, ins, localData, stack.peek(), valueLocalReg, nameLocalReg, objLocalReg);
if (checked != null) {
@@ -758,6 +770,29 @@ public abstract class InstructionDefinition implements Serializable {
}
}
if (obj instanceof PopItem) {
if (output.size() >= 2
&& output.get(output.size() - 1) instanceof SetLocalAVM2Item
&& output.get(output.size() - 2) instanceof PushItem
&& multiname.name instanceof LocalRegAVM2Item) {
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(output.size() - 1);
LocalRegAVM2Item localReg = (LocalRegAVM2Item) multiname.name;
PushItem pi = (PushItem) output.get(output.size() - 2);
if (setLocal.regIndex == localReg.regIndex) {
GraphSourceItem src = setLocal.getSrc();
if (src != null) {
if (localData.getSetLocalUsages(localData.code.adr2pos(src.getAddress())).size() == 1) {
output.remove(output.size() - 1);
output.remove(output.size() - 1);
stack.moveToStack(output);
obj = pi.value;
multiname.name = setLocal.value;
}
}
}
}
}
if (obj.getThroughDuplicate() instanceof ConstructAVM2Item) {
ConstructAVM2Item c = (ConstructAVM2Item) obj.getThroughDuplicate();
if (c.object instanceof ApplyTypeAVM2Item) {

View File

@@ -73,6 +73,7 @@ public interface SetTypeIns {
if (notCoercedValue instanceof DuplicateItem) {
GraphTargetItem insideDup = notCoercedValue.value;
if (!AVM2Item.mustStayIntact1(insideDup.getNotCoercedNoDup())) {
stack.moveToStack(output);
if (!stack.isEmpty() && stack.peek() == insideDup) {
stack.pop();
@@ -89,6 +90,7 @@ public interface SetTypeIns {
value = insideDup;
}
result.value = value;
stack.moveToOutput(output, false);
output.add(result);
for (int i = 0; i < numDups; i++) {
stack.push(new LocalRegAVM2Item(null, localData.lineStartInstruction, regId, value, localData.localRegTypes.containsKey(regId) ? localData.localRegTypes.get(regId) : value.returnType()));
@@ -109,6 +111,7 @@ public interface SetTypeIns {
}
if (regId > -1 && AVM2Item.mustStayIntact2(insideDup.getNotCoerced())) { //hack
stack.moveToOutput(output, false);
output.add(result);
stack.push(new LocalRegAVM2Item(null, localData.lineStartInstruction, regId, value, localData.localRegTypes.containsKey(regId) ? localData.localRegTypes.get(regId) : TypeItem.UNBOUNDED));
return;
@@ -120,6 +123,7 @@ public interface SetTypeIns {
}
}
}
stack.moveToOutput(output, false);
output.add(result);
}
}

View File

@@ -62,6 +62,7 @@ public class Sf32Ins extends InstructionDefinition implements AlchemyTypeIns {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem ofs = stack.pop();
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, false);
output.add(new AlchemyStoreAVM2Item(ins, localData.lineStartInstruction, value, ofs, "f", 32));
}

View File

@@ -62,6 +62,7 @@ public class Sf64Ins extends InstructionDefinition implements AlchemyTypeIns {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem ofs = stack.pop();
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, false);
output.add(new AlchemyStoreAVM2Item(ins, localData.lineStartInstruction, value, ofs, "f", 64));
}

View File

@@ -62,6 +62,7 @@ public class Si16Ins extends InstructionDefinition implements AlchemyTypeIns {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem ofs = stack.pop();
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, false);
output.add(new AlchemyStoreAVM2Item(ins, localData.lineStartInstruction, value, ofs, "i", 16));
}

View File

@@ -62,6 +62,7 @@ public class Si32Ins extends InstructionDefinition implements AlchemyTypeIns {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem ofs = stack.pop();
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, false);
output.add(new AlchemyStoreAVM2Item(ins, localData.lineStartInstruction, value, ofs, "i", 32));
}

View File

@@ -62,6 +62,7 @@ public class Si8Ins extends InstructionDefinition implements AlchemyTypeIns {
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem ofs = stack.pop();
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, false);
output.add(new AlchemyStoreAVM2Item(ins, localData.lineStartInstruction, value, ofs, "i", 8));
}

View File

@@ -74,7 +74,7 @@ public class ConstructPropIns extends InstructionDefinition {
for (int a = 0; a < argCount; a++) {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
if (multiname.isXML(localData.abc, localData.localRegNames, localData.fullyQualifiedNames, localData.seenMethods)) {

View File

@@ -72,6 +72,7 @@ public class ConstructSuperIns extends InstructionDefinition {
args.add(0, stack.pop());
}
GraphTargetItem obj = stack.pop();
stack.moveToOutput(output, false);
output.add(new ConstructSuperAVM2Item(ins, localData.lineStartInstruction, obj, args));
}

View File

@@ -80,6 +80,7 @@ public class CallIns extends InstructionDefinition {
for (int a = 0; a < argCount; a++) {
args.add(0, stack.pop());
}
stack.allowSwap(output);
GraphTargetItem receiver = stack.pop();
GraphTargetItem function = stack.pop();

View File

@@ -82,7 +82,7 @@ public class CallPropLexIns extends CallPropertyIns {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);

View File

@@ -82,13 +82,14 @@ public class CallPropVoidIns extends InstructionDefinition {
for (int a = 0; a < argCount; a++) {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);
Reference<GraphTargetItem> type = new Reference<>(null);
Reference<GraphTargetItem> callType = new Reference<>(null);
GetPropertyIns.resolvePropertyType(localData, obj, multiname, isStatic, type, callType);
stack.moveToOutput(output, false);
output.add(new CallPropertyAVM2Item(ins, localData.lineStartInstruction, true, obj, multiname, args, callType.getVal(), isStatic.getVal()));
}

View File

@@ -83,7 +83,7 @@ public class CallPropertyIns extends InstructionDefinition {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);
Reference<GraphTargetItem> type = new Reference<>(null);

View File

@@ -80,7 +80,7 @@ public class CallSuperIns extends InstructionDefinition {
for (int a = 0; a < argCount; a++) {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem receiver = stack.pop();
stack.push(new CallSuperAVM2Item(ins, localData.lineStartInstruction, false, receiver, multiname, args));

View File

@@ -79,9 +79,10 @@ public class CallSuperVoidIns extends InstructionDefinition {
for (int a = 0; a < argCount; a++) {
args.add(0, stack.pop());
}
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem receiver = stack.pop();
stack.moveToOutput(output, false);
output.add(new CallSuperAVM2Item(ins, localData.lineStartInstruction, true, receiver, multiname, args));
}

View File

@@ -73,6 +73,7 @@ public class DecLocalIIns extends InstructionDefinition {
}
}
if (!isPostDec) {
stack.moveToOutput(output, false);
output.add(new DecLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -74,6 +74,7 @@ public class DecLocalIns extends InstructionDefinition {
}
}
if (!isPostDec) {
stack.moveToOutput(output, false);
output.add(new DecLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -134,6 +134,7 @@ public abstract class GetLocalTypeIns extends InstructionDefinition {
result = new PostDecrementAVM2Item(setProp.getSrc(), localData.lineStartInstruction, getProp);
}
output.remove(output.size() - 1);
stack.moveToStack(output);
stack.add(result);
return;
}
@@ -153,6 +154,7 @@ public abstract class GetLocalTypeIns extends InstructionDefinition {
}
output.remove(output.size() - 1);
stack.moveToStack(output);
if (setItem instanceof SetPropertyAVM2Item) {
if ((setItem.value instanceof IncrementAVM2Item) || (setItem.value instanceof DecrementAVM2Item)) {
@@ -176,7 +178,7 @@ public abstract class GetLocalTypeIns extends InstructionDefinition {
}
}
stack.add(setItem);
stack.push(setItem);
return;
}
}

View File

@@ -73,6 +73,7 @@ public class IncLocalIIns extends InstructionDefinition {
}
}
if (!isPostInc) {
stack.moveToOutput(output, false);
output.add(new IncLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -74,6 +74,7 @@ public class IncLocalIns extends InstructionDefinition {
}
}
if (!isPostInc) {
stack.moveToOutput(output, false);
output.add(new IncLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -83,6 +83,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
localData.localRegAssignmentIps.put(regId, localData.localRegAssignmentIps.get(regId) + 1);
//localRegsAssignmentIps.put(regId, ip);
if (value.getThroughDuplicate() instanceof NewActivationAVM2Item) {
stack.moveToOutput(output, false);
output.add(new StoreNewActivationAVM2Item(ins, localData.lineStartInstruction, regId));
return;
}
@@ -102,9 +103,11 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
stack.pop();
stack.push(new PreIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
} else {
stack.moveToOutput(output, false);
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
} else {
stack.moveToOutput(output, false);
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
return;
@@ -125,9 +128,11 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S
stack.pop();
stack.push(new PreDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
} else {
stack.moveToOutput(output, false);
output.add(new PostDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
} else {
stack.moveToOutput(output, false);
output.add(new PostDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
return;

View File

@@ -58,7 +58,7 @@ public class DeletePropertyIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);
Reference<GraphTargetItem> type = new Reference<>(null);

View File

@@ -63,7 +63,7 @@ public class FindPropertyIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
stack.push(new FindPropertyAVM2Item(ins, localData.lineStartInstruction, multiname)); //resolve right object
}

View File

@@ -63,7 +63,7 @@ public class FindPropertyStrictIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
stack.push(new FindPropertyAVM2Item(ins, localData.lineStartInstruction, multiname));
}

View File

@@ -55,7 +55,7 @@ public class GetDescendantsIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
stack.push(new GetDescendantsAVM2Item(ins, localData.lineStartInstruction, obj, multiname));
}

View File

@@ -91,8 +91,8 @@ public class GetPropertyIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
//remove dups
if (obj instanceof FindPropertyAVM2Item) {

View File

@@ -45,7 +45,7 @@ public class GetSuperIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int multinameIndex = ins.operands[0];
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);

View File

@@ -55,6 +55,7 @@ public class ReturnValueIns extends InstructionDefinition {
if (value instanceof SetLocalAVM2Item) {
value = value.value;
}
stack.moveToOutput(output, true);
output.add(new ReturnValueAVM2Item(ins, localData.lineStartInstruction, value));
}

View File

@@ -49,6 +49,7 @@ public class ReturnVoidIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.moveToOutput(output, true);
output.add(new ReturnVoidAVM2Item(ins, localData.lineStartInstruction));
}

View File

@@ -44,6 +44,7 @@ public class SetGlobalSlotIns extends InstructionDefinition implements SetTypeIn
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int slotIndex = ins.operands[0];
stack.allowSwap(output);
GraphTargetItem value = stack.pop();
GraphTargetItem obj = new GlobalAVM2Item(ins, localData.lineStartInstruction);
SetSlotIns.handleSetSlot(localData, stack, ins, output, slotIndex, obj, value);

View File

@@ -61,6 +61,7 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
int slotIndex = ins.operands[0];
stack.allowSwap(output);
GraphTargetItem value = stack.pop();
GraphTargetItem obj = stack.pop(); //scopeId
if (obj.getThroughRegister() instanceof NewActivationAVM2Item) {
@@ -100,7 +101,8 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
&& (slotItem.slotName == slotname)) {
if (stack.size() > 0) {
stack.moveToStack(output);
if (!stack.isEmpty()) {
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
if (top == inside) {
stack.pop();
@@ -109,9 +111,11 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
stack.pop();
stack.push(new PreIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
} else {
stack.moveToOutput(output, false);
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
} else {
stack.moveToOutput(output, false);
output.add(new PostIncrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
return;
@@ -125,7 +129,8 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside;
if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister())
&& (slotItem.slotName == slotname)) {
if (stack.size() > 0) {
stack.moveToStack(output);
if (!stack.isEmpty()) {
GraphTargetItem top = stack.peek().getNotCoerced().getThroughDuplicate();
if (top == inside) {
stack.pop();
@@ -134,9 +139,11 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns {
stack.pop();
stack.push(new PreDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
} else {
stack.moveToOutput(output, false);
output.add(new PostDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
} else {
stack.moveToOutput(output, false);
output.add(new PostDecrementAVM2Item(ins, localData.lineStartInstruction, inside));
}
return;

View File

@@ -48,11 +48,13 @@ public class SetSuperIns extends InstructionDefinition implements SetTypeIns {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.allowSwap(output);
int multinameIndex = ins.operands[0];
GraphTargetItem value = stack.pop();
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins);
FullMultinameAVM2Item multiname = resolveMultiname(localData, true, stack, localData.getConstants(), multinameIndex, ins, output);
GraphTargetItem obj = stack.pop();
Reference<Boolean> isStatic = new Reference<>(false);

View File

@@ -51,7 +51,9 @@ public class ThrowIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
output.add(new ThrowAVM2Item(ins, localData.lineStartInstruction, stack.pop()));
GraphTargetItem value = stack.pop();
stack.moveToOutput(output, true);
output.add(new ThrowAVM2Item(ins, localData.lineStartInstruction, value));
}
@Override

View File

@@ -84,6 +84,7 @@ public class DecLocalPIns extends InstructionDefinition {
}
}
if (!isPostDec) {
stack.moveToOutput(output, false);
output.add(new DecLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -84,6 +84,7 @@ public class IncLocalPIns extends InstructionDefinition {
}
}
if (!isPostInc) {
stack.moveToOutput(output, false);
output.add(new IncLocalAVM2Item(ins, localData.lineStartInstruction, regId));
}
if (localData.localRegs.containsKey(regId)) {

View File

@@ -63,6 +63,7 @@ public class PopIns extends InstructionDefinition {
return;
}
stack.moveToOutput(output, false);
output.add(top);
}

View File

@@ -53,6 +53,7 @@ public class PopScopeIns extends InstructionDefinition {
GraphTargetItem scope = localData.localScopeStack.pop();
if (scope instanceof WithObjectAVM2Item) {
scope = ((WithObjectAVM2Item) scope).scope;
stack.moveToOutput(output, false);
output.add(new WithEndAVM2Item(ins, localData.lineStartInstruction, scope));
}
}

View File

@@ -45,6 +45,7 @@ public class PushWithIns extends InstructionDefinition {
GraphTargetItem w = stack.pop();
WithObjectAVM2Item wot = new WithObjectAVM2Item(ins, localData.lineStartInstruction, w);
localData.localScopeStack.push(wot);
stack.moveToOutput(output, false);
output.add(new WithAVM2Item(ins, localData.lineStartInstruction, w));
}

View File

@@ -20,11 +20,18 @@ import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea;
import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2GraphTargetDialect;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.model.EscapeXAttrAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
import com.jpexs.decompiler.graph.GraphSourceItemPos;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import java.util.List;
/**
@@ -55,10 +62,35 @@ public class SwapIns extends InstructionDefinition {
GraphTargetItem o1 = stack.pop();
GraphTargetItem o2 = stack.pop();
stack.push(o1);
stack.push(o2);
o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
if (((o1 instanceof ExceptionAVM2Item) && (o2 instanceof ExceptionAVM2Item))
||
(
(
((o1 instanceof SimpleValue) && ((SimpleValue) o1).isSimpleValue() && !(o1 instanceof DuplicateItem))
||
(o1 instanceof EscapeXAttrAVM2Item)
)
&&
(
((o2 instanceof SimpleValue) && ((SimpleValue) o2).isSimpleValue() && !(o2 instanceof DuplicateItem))
||
(o2 instanceof EscapeXAttrAVM2Item)
)
)
) {
stack.push(o1);
stack.push(o2);
o1.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
o2.getMoreSrc().add(new GraphSourceItemPos(ins, 0));
return;
}
stack.moveToOutput(output, false);
output.add(new PushItem(o2));
output.add(new PushItem(o1));
output.add(new SwapItem(AVM2GraphTargetDialect.INSTANCE, ins, localData.lineStartInstruction));
}
@Override

View File

@@ -52,6 +52,7 @@ public class DXNSIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
stack.moveToOutput(output, false);
//FIXME!!! - search namespace
output.add(new DefaultXMLNamespace(ins, localData.lineStartInstruction, new StringAVM2Item(ins, localData.lineStartInstruction, localData.getConstants().getString(ins.operands[0]))));
}

View File

@@ -52,6 +52,7 @@ public class DXNSLateIns extends InstructionDefinition {
@Override
public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List<GraphTargetItem> output, String path) {
GraphTargetItem xmlns = stack.pop();
stack.moveToOutput(output, false);
output.add(new DefaultXMLNamespace(ins, localData.lineStartInstruction, xmlns));
}

View File

@@ -104,6 +104,7 @@ import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
@@ -3580,6 +3581,13 @@ public class AVM2SourceGenerator implements SourceGenerator {
return ret;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, SwapItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.add(ins(AVM2Instructions.Swap));
return ret;
}
/**
* For some strange reasons, &amp;&amp; and || operators must have coerced
* both sides when there is specific type expected.

View File

@@ -118,6 +118,7 @@ import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.ParenthesisItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
@@ -2460,6 +2461,9 @@ public class ActionScript3Parser {
ret = new PopItem(DIALECT, null, null);
allowMemberOrCall = true;
break;
case "swap":
ret = new SwapItem(DIALECT, null, null);
break;
case "goto": //TODO
case "multiname":
throw new AVM2ParseException("Compiling §§" + s.value + " is not available, sorry", lexer.yyline());

View File

@@ -1886,6 +1886,9 @@ public class ActionScript3SimpleParser implements SimpleParser {
ret = true;
allowMemberOrCall = true;
break;
case "swap":
ret = true;
break;
case "goto":
expectedType(errors, SymbolGroup.IDENTIFIER);
//errors.add(new SimpleParseException("Compiling §§" + s.value + " is not available, sorry", lexer.yyline(), s.position));

View File

@@ -164,6 +164,7 @@ import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.ParenthesisItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
@@ -1878,6 +1879,9 @@ public class ActionScript2Parser {
ret = new PopItem(DIALECT, null, null);
allowMemberOrCall = true;
break;
case "swap":
ret = new SwapItem(DIALECT, null, null);
break;
case "strict":
s = lex();
expected(s, lexer.yyline(), SymbolType.INTEGER);

View File

@@ -1342,6 +1342,9 @@ public class ActionScript2SimpleParser implements SimpleParser {
ret = true;
allowMemberOrCall = true;
break;
case "swap":
ret = true;
break;
case "strict":
s = lexer.lex();
expected(errors, s, lexer.yyline(), SymbolType.INTEGER);

View File

@@ -40,6 +40,7 @@ import com.jpexs.decompiler.flash.action.swf5.ActionGetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionNewObject;
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStackSwap;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
import com.jpexs.decompiler.flash.action.swf7.ActionExtends;
@@ -65,6 +66,7 @@ import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
@@ -1191,7 +1193,6 @@ public class ActionSourceGenerator implements SourceGenerator {
return ret;
}
private int checkOffsetBounds(int offset, String errorItem, int errorLine) throws CompilationException {
if (offset < -32768) {
throw new CompilationException("Generated offset for " + errorItem + " is lower than mininum allowed for SI16.", errorLine);
@@ -1201,4 +1202,10 @@ public class ActionSourceGenerator implements SourceGenerator {
}
return offset;
}
@Override
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, SwapItem item) throws CompilationException {
List<GraphSourceItem> ret = new ArrayList<>();
ret.add(new ActionStackSwap());
return ret;
}
}

View File

@@ -3369,6 +3369,7 @@ public class Graph {
if (code.size() <= part.start) {
if (!(!ret.isEmpty() && ret.get(ret.size() - 1) instanceof ExitItem)) {
stack.moveToOutput(ret, true);
ret.add(new ScriptEndItem(dialect));
}
return ret;
@@ -3533,6 +3534,7 @@ public class Graph {
} while (exHappened);
if ((part.end >= code.size() - 1) && getNextParts(localData, part).isEmpty()) {
if (!(!output.isEmpty() && output.get(output.size() - 1) instanceof ExitItem)) {
stack.moveToOutput(output, true);
output.add(new ScriptEndItem(dialect));
}
}

View File

@@ -30,6 +30,7 @@ import com.jpexs.decompiler.graph.model.NotItem;
import com.jpexs.decompiler.graph.model.OrItem;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.SwitchItem;
import com.jpexs.decompiler.graph.model.TernarOpItem;
import com.jpexs.decompiler.graph.model.TrueItem;
@@ -243,4 +244,14 @@ public interface SourceGenerator {
* @throws CompilationException On compilation error
*/
public List<GraphSourceItem> generateDiscardValue(SourceGeneratorLocalData localData, GraphTargetItem item) throws CompilationException;
/**
* Generates source code for SwapItem.
*
* @param localData Local data
* @param item SwapItem
* @return List of GraphSourceItem
* @throws CompilationException On compilation error
*/
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, SwapItem item) throws CompilationException;
}

View File

@@ -16,7 +16,12 @@
*/
package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
import com.jpexs.decompiler.graph.model.BranchStackResistant;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -144,6 +149,10 @@ public class TranslateStack extends Stack<GraphTargetItem> {
public synchronized GraphTargetItem peek() {
if (path != null) {
if (this.isEmpty()) {
/*if (connectedOutput != null && !connectedOutput.isEmpty() && connectedOutput.get(connectedOutput.size() - 1) instanceof PushItem) {
PushItem pi = (PushItem) connectedOutput.get(connectedOutput.size() - 1);
return pi.value;
}*/
Logger.getLogger(TranslateStack.class.getName()).log(Level.FINE, "{0}: Attempt to Peek empty stack", path);
return getPop();
}
@@ -160,6 +169,10 @@ public class TranslateStack extends Stack<GraphTargetItem> {
public synchronized GraphTargetItem peek(int index) {
if (path != null) {
if (index > this.size()) {
/*if (connectedOutput != null && connectedOutput.size() >= index - this.size() && connectedOutput.get(connectedOutput.size() - (index - this.size())) instanceof PushItem) {
PushItem pi = (PushItem) connectedOutput.get(connectedOutput.size() - (index - this.size()));
return pi.value;
}*/
Logger.getLogger(TranslateStack.class.getName()).log(Level.FINE, "{0}: Attempt to Peek item from stack", path);
return getPop();
}
@@ -176,6 +189,11 @@ public class TranslateStack extends Stack<GraphTargetItem> {
public synchronized GraphTargetItem pop() {
if (path != null) {
if (this.isEmpty()) {
/*if (connectedOutput != null && !connectedOutput.isEmpty() && connectedOutput.get(connectedOutput.size() - 1) instanceof PushItem) {
PushItem pi = (PushItem) connectedOutput.remove(connectedOutput.size() - 1);
return pi.value;
}*/
PopItem oldpop = getPop();
pop = null;
Logger.getLogger(TranslateStack.class.getName()).log(Level.FINE, "{0}: Attempt to Pop empty stack", path);
@@ -184,4 +202,68 @@ public class TranslateStack extends Stack<GraphTargetItem> {
}
return super.pop();
}
public void moveToStack(List<GraphTargetItem> output) {
if (!isEmpty()) {
return;
}
int i = output.size() - 1;
for (; i >= 0; i--) {
if (!(output.get(i) instanceof PushItem)) {
break;
}
}
i++;
while(i < output.size()) {
PushItem pi = (PushItem) output.remove(i);
push(pi.value);
}
}
public void moveToOutput(List<GraphTargetItem> output, boolean beforeExit) {
if (true) {
//return;
}
int pos = output.size();
for (int i = size() - 1; i >= 0; i--) {
GraphTargetItem item = get(i);
if (item instanceof BranchStackResistant) {
continue;
}
if (item instanceof NewActivationAVM2Item) {
break;
}
if (item instanceof ExceptionAVM2Item) {
break;
}
remove(i);
output.add(pos, beforeExit ? item : new PushItem(item));
}
}
public void allowSwap(List<GraphTargetItem> output) {
if (!isEmpty()) {
return;
}
if (output.size() < 3) {
return;
}
if (!(output.get(output.size() - 1) instanceof SwapItem)) {
return;
}
if (!(output.get(output.size() - 2) instanceof PushItem)) {
return;
}
if (!(output.get(output.size() - 3) instanceof PushItem)) {
return;
}
output.remove(output.size() - 1);
push(((PushItem)output.remove(output.size() - 1)).value);
push(((PushItem)output.remove(output.size() - 1)).value);
//moveToStack(output);
}
}

View File

@@ -59,9 +59,9 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
/*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
return value.appendTry(writer, localData);
}
}*/
writer.append("§§dup(");
value.appendTry(writer, localData);
return writer.append(")");

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetDialect;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import java.util.List;
/**
* Pop item from the stack.
*
* @author JPEXS
*/
public class SwapItem extends GraphTargetItem {
/**
* Constructor.
*
* @param dialect Dialect
* @param src Source
* @param lineStartIns Line start instruction
*/
public SwapItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns) {
super(dialect, src, lineStartIns, PRECEDENCE_PRIMARY);
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.append("§§swap()");
return writer;
}
@Override
public boolean hasReturnValue() {
return false;
}
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
}
@Override
public Object getResult() {
return Null.INSTANCE;
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return generator.generate(localData, this);
}
@Override
public boolean hasSideEffect() {
return true; //?
}
}