Fix chained assignments, also reorganized TestIncDec tests

This commit is contained in:
Jindra Petřík
2025-08-17 13:15:35 +02:00
parent 8bbdd415bd
commit b2442438d4
12 changed files with 583 additions and 798 deletions

View File

@@ -21,7 +21,9 @@ import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.helpers.Reference;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**

View File

@@ -20,12 +20,19 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.DecrementAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.GetPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IncrementAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreDecrementAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.DuplicateItem;
import com.jpexs.decompiler.graph.model.DuplicateSourceItem;
import com.jpexs.decompiler.graph.model.SetTemporaryItem;
import java.util.List;
/**
@@ -65,15 +72,48 @@ public interface SetTypeIns {
* @param type Type
*/
public static void handleResult(GraphTargetItem value, TranslateStack stack, List<GraphTargetItem> output, AVM2LocalData localData, GraphTargetItem result, int regId, GraphTargetItem type) {
GraphTargetItem notCoercedValue = value;
if ((value instanceof CoerceAVM2Item) || (value instanceof ConvertAVM2Item)) {
notCoercedValue = value.value;
}
//TestChainedAssignments1 both AIR and nonair
if (notCoercedValue instanceof DuplicateItem) {
DuplicateItem d = (DuplicateItem) notCoercedValue;
stack.moveToStack(output);
if (!stack.isEmpty() && stack.peek() instanceof DuplicateSourceItem) {
DuplicateSourceItem ds = (DuplicateSourceItem) stack.peek();
if (ds.tempIndex == d.tempIndex) {
GraphTargetItem newValue = d.value;
if (!output.isEmpty() && output.get(output.size() - 1) instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 1);
if (st.tempIndex == ds.tempIndex) {
output.remove(output.size() - 1);
}
}
if ((value instanceof CoerceAVM2Item) || (value instanceof ConvertAVM2Item)) {
result.value.value = newValue;
} else {
result.value = newValue;
}
stack.pop();
stack.moveToStack(output);
stack.push(result);
return;
}
}
stack.finishBlock(output);
}
stack.addToOutput(result);
if (true) { //FIXME??
return;
}
//
GraphTargetItem notCoercedValue = value;
if ((value instanceof CoerceAVM2Item) || (value instanceof ConvertAVM2Item)) {
notCoercedValue = value.value;
}
if (notCoercedValue instanceof DuplicateItem) {
GraphTargetItem insideDup = notCoercedValue.value;

View File

@@ -124,189 +124,8 @@ public abstract class GetLocalTypeIns extends InstructionDefinition {
LocalRegAVM2Item result = new LocalRegAVM2Item(ins, localData.lineStartInstruction, regId, computedValue, type);
//TestIncDec5 with result AIR
/*
//var _temp_4:* = trace;
//var _temp_3:* = global;
var _temp_1:* = a;
var _temp_2:* = _temp_1.attrib + 1;
var _loc2_:* = _temp_2;
_temp_1.attrib = _temp_2;
_temp_4(_loc2_);
*/
stack.finishBlock(output);
Class[] expectedClasses = new Class[]{
SetTemporaryItem.class,
SetTemporaryItem.class,
SetLocalAVM2Item.class,
SetPropertyAVM2Item.class
};
if (output.size() >= expectedClasses.length) {
loopout: do {
for (int i = 0; i < expectedClasses.length; i++) {
if (!expectedClasses[expectedClasses.length - 1 - i].isAssignableFrom(output.get(output.size() - 1 - i).getClass())) {
break loopout;
}
}
SetPropertyAVM2Item setProperty = (SetPropertyAVM2Item) output.get(output.size() - 1);
SetLocalAVM2Item setLocalValue = (SetLocalAVM2Item) output.get(output.size() - 2);
SetTemporaryItem setTempValue = (SetTemporaryItem) output.get(output.size() - 3);
SetTemporaryItem setTempObj = (SetTemporaryItem) output.get(output.size() - 4);
if (setLocalValue.regIndex != result.regIndex) {
break;
}
if (!(setLocalValue.value instanceof DuplicateItem)) {
break;
}
if (!(setLocalValue.value.value instanceof IncrementAVM2Item
|| setLocalValue.value.value instanceof DecrementAVM2Item)) {
break;
}
if (!(setLocalValue.value.value.value instanceof GetPropertyAVM2Item)) {
break;
}
boolean isIncrement = setLocalValue.value.value instanceof IncrementAVM2Item;
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) setLocalValue.value.value.value;
if (!(getProp.object instanceof DuplicateItem)) {
break;
}
if (!(getProp.propertyName instanceof FullMultinameAVM2Item)) {
break;
}
FullMultinameAVM2Item fm = (FullMultinameAVM2Item) getProp.propertyName;
FullMultinameAVM2Item setFm = (FullMultinameAVM2Item) setProperty.propertyName;
if (!fm.compareSame(setFm)) {
break;
}
DuplicateItem dupObj = (DuplicateItem) getProp.object;
if (dupObj.tempIndex != setTempObj.tempIndex) {
break;
}
DuplicateItem dupValue = (DuplicateItem) setLocalValue.value;
if (dupValue.tempIndex != setTempValue.tempIndex) {
break;
}
getProp.object = setTempObj.value;
for (int i = 0; i < expectedClasses.length; i++) {
output.remove(output.size() - 1);
}
stack.moveToStack(output);
if (isIncrement) {
stack.push(new PreIncrementAVM2Item(setLocalValue.value.value.getSrc(), setLocalValue.value.value.lineStartItem, getProp));
} else {
stack.push(new PreDecrementAVM2Item(setLocalValue.value.value.getSrc(), setLocalValue.value.value.lineStartItem, getProp));
}
return;
} while(false);
}
//TestIncDec6 with result AIR
/*
//var _temp_4:* = trace;
//var _temp_3:* = global;
var _temp_1:* = a;
var _temp_2:* = _temp_1.attrib;
var _loc2_:* = _temp_2;
_temp_1.attrib = _temp_2 + 1;
_temp_4(_loc2_);
*/
expectedClasses = new Class[] {
SetTemporaryItem.class,
SetTemporaryItem.class,
SetLocalAVM2Item.class,
SetPropertyAVM2Item.class
};
if (output.size() >= expectedClasses.length) {
loopout: do {
for (int i = 0; i < expectedClasses.length; i++) {
if (!expectedClasses[expectedClasses.length - 1 - i].isAssignableFrom(output.get(output.size() - 1 - i).getClass())) {
break loopout;
}
}
SetPropertyAVM2Item setProperty = (SetPropertyAVM2Item) output.get(output.size() - 1);
SetLocalAVM2Item setLocalValue = (SetLocalAVM2Item) output.get(output.size() - 2);
SetTemporaryItem setTempValue = (SetTemporaryItem) output.get(output.size() - 3);
SetTemporaryItem setTempObj = (SetTemporaryItem) output.get(output.size() - 4);
if (setLocalValue.regIndex != result.regIndex) {
break;
}
if (!(setProperty.object instanceof DuplicateSourceItem)) {
break;
}
if (!(setProperty.value instanceof IncrementAVM2Item
|| setProperty.value instanceof DecrementAVM2Item)) {
break;
}
if (!(setProperty.value.value instanceof DuplicateSourceItem)) {
break;
}
if (!(setProperty.value.value.value.getNotCoercedNoDup() instanceof GetPropertyAVM2Item)) {
break;
}
boolean isIncrement = setProperty.value instanceof IncrementAVM2Item;
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) setProperty.value.value.value.getNotCoercedNoDup();
if (!(getProp.object instanceof DuplicateItem)) {
break;
}
if (!(getProp.propertyName instanceof FullMultinameAVM2Item)) {
break;
}
FullMultinameAVM2Item fm = (FullMultinameAVM2Item) getProp.propertyName;
FullMultinameAVM2Item setFm = (FullMultinameAVM2Item) setProperty.propertyName;
if (!fm.compareSame(setFm)) {
break;
}
if (!(setLocalValue.value instanceof DuplicateItem)) {
break;
}
DuplicateSourceItem dupSourceObj = (DuplicateSourceItem) setProperty.object;
DuplicateItem dupObj = (DuplicateItem) getProp.object;
if (dupObj.tempIndex != setTempObj.tempIndex
|| dupSourceObj.tempIndex != setTempObj.tempIndex) {
break;
}
DuplicateSourceItem dupValue = (DuplicateSourceItem) setProperty.value.value;
DuplicateItem dupSourceValue = (DuplicateItem) setLocalValue.value;
if (dupValue.tempIndex != setTempValue.tempIndex
|| dupSourceValue.tempIndex != setTempValue.tempIndex) {
break;
}
getProp.object = setTempObj.value;
for (int i = 0; i < expectedClasses.length; i++) {
output.remove(output.size() - 1);
}
stack.moveToStack(output);
if (isIncrement) {
stack.push(new PreIncrementAVM2Item(setLocalValue.value.value.getSrc(), setLocalValue.value.value.lineStartItem, getProp));
} else {
stack.push(new PreDecrementAVM2Item(setLocalValue.value.value.getSrc(), setLocalValue.value.value.lineStartItem, getProp));
}
return;
} while(false);
}
//TestIncDec7 AIR
if (!output.isEmpty()) {
GraphTargetItem lastOutput = output.get(output.size() - 1);
@@ -324,6 +143,137 @@ public abstract class GetLocalTypeIns extends InstructionDefinition {
}
}
//TestIncDec6 with result AIR
if (!output.isEmpty() && output.get(output.size() - 1) instanceof SetPropertyAVM2Item) {
SetPropertyAVM2Item setProp = (SetPropertyAVM2Item) output.get(output.size() - 1);
if (setProp.value instanceof IncrementAVM2Item
|| setProp.value instanceof DecrementAVM2Item) {
boolean isIncrement = setProp.value instanceof IncrementAVM2Item;
if (setProp.value.value instanceof SetLocalAVM2Item) {
SetLocalAVM2Item setLoc = (SetLocalAVM2Item) setProp.value.value;
if (setLoc.regIndex == regId) {
if (setLoc.getSrc() instanceof AVM2Instruction) {
AVM2Instruction src = (AVM2Instruction) setLoc.getSrc();
if (localData.getSetLocalUsages(localData.code.adr2pos(src.getAddress())).size() == 1) {
if (setLoc.value instanceof ConvertAVM2Item) {
if (setLoc.value.value instanceof GetPropertyAVM2Item) {
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) setLoc.value.value;
if (setProp.object instanceof DuplicateSourceItem) {
DuplicateSourceItem ds = (DuplicateSourceItem) setProp.object;
if (getProp.object instanceof DuplicateItem) {
DuplicateItem d = (DuplicateItem) getProp.object;
if (output.size() >= 2 && output.get(output.size() - 2) instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 2);
if (st.tempIndex == d.tempIndex) {
getProp.object = st.value;
output.remove(output.size() - 1);
output.remove(output.size() - 1);
stack.moveToStack(output);
if (isIncrement) {
stack.push(new PostIncrementAVM2Item(setProp.value.getSrc(), setProp.value.getLineStartItem(), getProp));
} else {
stack.push(new PostDecrementAVM2Item(setProp.value.getSrc(), setProp.value.getLineStartItem(), getProp));
}
return;
}
}
}
}
}
}
}
}
}
}
}
}
//TestChainedAssignments1
/*
trace("c = b = a = 5;");
var a:int = 0;
var b:int = 0;
var c:int = 0;
var _loc4_:*;
a = _loc4_ = 5;
b = _loc4_ = _loc4_;
c = _loc4_;
*/
stack.moveToStack(output);
if (!output.isEmpty()) {
//chained assignments
if ((output.get(output.size() - 1) instanceof SetTypeAVM2Item)) {
GraphTargetItem setItem = output.get(output.size() - 1);
if (setItem.value.getNotCoercedNoDup() instanceof SetLocalAVM2Item) {
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) setItem.value.getNotCoercedNoDup();
if (setLocal.regIndex == regId) {
int setLocalIp = localData.code.adr2pos(setLocal.getSrc().getAddress());
if (localData.getSetLocalUsages(setLocalIp).size() == 1) {
//TestIncDec5 with result AIR
if (setItem instanceof SetPropertyAVM2Item
&& (setLocal.value instanceof IncrementAVM2Item
|| setLocal.value instanceof DecrementAVM2Item
)) {
SetPropertyAVM2Item setProp = (SetPropertyAVM2Item) setItem;
boolean isIncrement = setLocal.value instanceof IncrementAVM2Item;
if (setLocal.value.value instanceof GetPropertyAVM2Item) {
//TestIncDec6 with result AIR
/*
var _temp_4:* = trace;
var _temp_3:* = global;
var _temp_1:* = a;
var _loc2_:Number;
_temp_1.attrib = (_loc2_ = _temp_1.attrib) + 1;
_temp_4(_loc2_);
*/
GetPropertyAVM2Item getProp = (GetPropertyAVM2Item) setLocal.value.value;
if (getProp.object instanceof DuplicateItem) {
DuplicateItem d = (DuplicateItem) getProp.object;
if (setProp.object instanceof DuplicateSourceItem) {
DuplicateSourceItem ds = (DuplicateSourceItem) setProp.object;
if (ds.tempIndex == d.tempIndex) {
if (output.size() >= 2 && output.get(output.size() - 2) instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 2);
if (st.tempIndex == d.tempIndex) {
getProp.object = st.value;
output.remove(output.size() - 1);
output.remove(output.size() - 1);
stack.moveToStack(output);
if (isIncrement) {
stack.push(new PreIncrementAVM2Item(setLocal.value.getSrc(), setLocal.value.getLineStartItem(), getProp));
} else {
stack.push(new PreDecrementAVM2Item(setLocal.value.getSrc(), setLocal.value.getLineStartItem(), getProp));
}
return;
}
}
}
}
}
}
}
if ((setItem.value instanceof CoerceAVM2Item) || (setItem.value instanceof ConvertAVM2Item)) {
setItem.value.value = setLocal.value;
} else {
setItem.value = setLocal.value;
}
output.remove(output.size() - 1);
stack.moveToStack(output);
stack.push(setItem);
return;
}
}
}
}
stack.finishBlock(output);
}
stack.moveToStack(output);
stack.push(result);

View File

@@ -24,6 +24,7 @@ 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.NewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;