Fixed: #2636 ActionScript 3 - type coercion / convert, local registers type propagation

This commit is contained in:
Jindra Petřík
2026-02-18 22:37:55 +01:00
parent fab6defe9c
commit 0a4e53f455
21 changed files with 158 additions and 80 deletions

View File

@@ -2201,6 +2201,11 @@ public class AVM2Code implements Cloneable {
vtype = assignment.value.returnType();
} else if (assignment.value instanceof LocalRegAVM2Item) {
vtype = assignment.value.returnType();
} else {
vtype = assignment.value.returnType();
if (vtype == TypeItem.UNKNOWN) {
vtype = TypeItem.UNBOUNDED;
}
}
}
@@ -2435,12 +2440,21 @@ public class AVM2Code implements Cloneable {
handleDeclareReg(minreg, subItem, declaredRegisters, declaredSlots, reg);
}
}
/*
if (subItem instanceof LocalRegAVM2Item) {
LocalRegAVM2Item getLocal = (LocalRegAVM2Item) subItem;
if (declaredRegisters[getLocal.regIndex] != null) {
getLocal.type = declaredRegisters[getLocal.regIndex].type;
}
}
if (subItem instanceof SetLocalAVM2Item) {
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) subItem;
if (declaredRegisters[setLocal.regIndex] != null) {
setLocal.type = declaredRegisters[setLocal.regIndex].type;
}
}
*/
if (subItem instanceof SetPropertyAVM2Item) {
SetPropertyAVM2Item sp = (SetPropertyAVM2Item) subItem;
if (sp.object instanceof FindPropertyAVM2Item) {
@@ -2952,9 +2966,44 @@ public class AVM2Code implements Cloneable {
paramNamesList.add(AVM2Item.localRegName(abc.getSwf(), localRegNames, ir, usedDeobfuscations));
}
injectDeclarations(usedDeobfuscations, 0, paramNamesList, list, 1, d, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), abc, body);
uniteLocalsDeclarationTypes(d, list);
return list;
}
private void uniteLocalsDeclarationTypes(DeclarationAVM2Item[] declaredRegs, List<GraphTargetItem> items) {
for (int i = 0; i < items.size(); i++) {
GraphTargetItem currentItem = items.get(i);
List<GraphTargetItem> itemsOnLine = new ArrayList<>();
itemsOnLine.add(currentItem);
currentItem.visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() {
@Override
public void visit(GraphTargetItem item, Stack<GraphTargetItem> parentStack) {
itemsOnLine.add(item);
}
});
for (GraphTargetItem item : itemsOnLine) {
if (item instanceof SetLocalAVM2Item) {
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) item;
if (declaredRegs[setLocal.regIndex] != null) {
setLocal.type = declaredRegs[setLocal.regIndex].type;
}
}
if (item instanceof LocalRegAVM2Item) {
LocalRegAVM2Item getLocal = (LocalRegAVM2Item) item;
if (declaredRegs[getLocal.regIndex] != null) {
getLocal.type = declaredRegs[getLocal.regIndex].type;
}
}
}
if (currentItem instanceof Block) {
Block block = (Block) currentItem;
for (List<GraphTargetItem> sub : block.getSubs()) {
uniteLocalsDeclarationTypes(declaredRegs, sub);
}
}
}
}
/**
* Updates instruction byte count at given address.

View File

@@ -43,20 +43,33 @@ import java.util.List;
public interface SetTypeIns {
/**
* Handles number to int conversion.
* Handles setting value with coerce
*
* @param value Value to convert
* @param type Type to convert to
* @return Value
*/
public static GraphTargetItem handleNumberToInt(GraphTargetItem value, GraphTargetItem type) {
if ((value instanceof ConvertAVM2Item) || (value instanceof CoerceAVM2Item)) {
if (type != null && (type.equals(TypeItem.INT) || type.equals(TypeItem.UINT))) {
if (value.value.returnType().equals(TypeItem.NUMBER)) {
return value.value;
}
public static GraphTargetItem handleSetCoerce(GraphTargetItem value, GraphTargetItem type) {
if (type == null) {
return value;
}
if (!(value instanceof ConvertAVM2Item) && !(value instanceof CoerceAVM2Item)) {
return value;
}
GraphTargetItem convertType = value.returnType();
GraphTargetItem insideConvertType = value.value.returnType();
if (type.equals(convertType)) {
if (insideConvertType.equals(TypeItem.UNBOUNDED) && !type.equals(TypeItem.UNBOUNDED)) {
return value.value;
}
}
if ((type.equals(TypeItem.INT) || type.equals(TypeItem.UINT)) && insideConvertType.equals(TypeItem.NUMBER)) {
return value.value;
}
return value;
}

View File

@@ -22,6 +22,8 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
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.instructions.SetTypeIns;
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.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IncrementAVM2Item;
@@ -35,6 +37,7 @@ 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.CommaExpressionItem;
import com.jpexs.decompiler.graph.model.CompoundableBinaryOp;
import com.jpexs.decompiler.graph.model.DuplicateItem;

View File

@@ -79,30 +79,30 @@ public class CoerceAVM2Item extends AVM2Item {
break;
case "Boolean":
displayCoerce = !valueReturnType.equals(TypeItem.BOOLEAN)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "Number":
displayCoerce = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(TypeItem.NUMBER)
&& !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "float":
displayCoerce = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(new TypeItem("float"))
&& !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "int":
displayCoerce = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "uint":
if (valueReturnType.equals(TypeItem.INT) && (value instanceof IntegerValueAVM2Item)) {
displayCoerce = (((IntegerValueAVM2Item) value).value < 0);
} else {
displayCoerce = !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;// && !valueReturnType.equals(TypeItem.UNBOUNDED);
}
break;
case "String":

View File

@@ -67,30 +67,30 @@ public class ConvertAVM2Item extends AVM2Item {
switch (type.toString()) {
case "Boolean":
displayConvert = !valueReturnType.equals(TypeItem.BOOLEAN)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "Number":
displayConvert = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(TypeItem.NUMBER)
&& !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "float":
displayConvert = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(new TypeItem("float"))
&& !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "int":
displayConvert = !valueReturnType.equals(TypeItem.INT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
case "uint":
if (valueReturnType.equals(TypeItem.INT) && (value instanceof IntegerValueAVM2Item)) {
displayConvert = (((IntegerValueAVM2Item) value).value < 0);
} else {
displayConvert = !valueReturnType.equals(TypeItem.UINT)
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;// && !valueReturnType.equals(TypeItem.UNBOUNDED);
}
break;
case "String":
@@ -98,7 +98,7 @@ public class ConvertAVM2Item extends AVM2Item {
//&& !valueReturnType.equals(new TypeItem("XML"))
//&& !valueReturnType.equals(new TypeItem("XMLList"))
&& !valueReturnType.equals(new TypeItem("null"))
&& !valueReturnType.equals(TypeItem.UNBOUNDED);
;//&& !valueReturnType.equals(TypeItem.UNBOUNDED);
break;
}
if (displayConvert) {

View File

@@ -120,7 +120,7 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig
/*if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) {
return value.value.toString(writer, localData);
}*/
return SetTypeIns.handleNumberToInt(value, type).toString(writer, localData);
return SetTypeIns.handleSetCoerce(value, type).toString(writer, localData);
}
@Override

View File

@@ -140,7 +140,7 @@ public class SetPropertyAVM2Item extends AVM2Item implements SetTypeAVM2Item, As
/*if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) {
return value.value.toString(writer, localData);
}*/
return SetTypeIns.handleNumberToInt(value, type).toString(writer, localData);
return SetTypeIns.handleSetCoerce(value, type).toString(writer, localData);
}
@Override
@@ -167,7 +167,7 @@ public class SetPropertyAVM2Item extends AVM2Item implements SetTypeAVM2Item, As
@Override
public GraphTargetItem returnType() {
return value.returnType();
return type;
//return TypeItem.UNBOUNDED;
}

View File

@@ -139,7 +139,7 @@ public class SetSlotAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assign
/*if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) {
return value.value.toString(writer, localData);
}*/
return SetTypeIns.handleNumberToInt(value, type).toString(writer, localData);
return SetTypeIns.handleSetCoerce(value, type).toString(writer, localData);
}
/**
@@ -183,7 +183,7 @@ public class SetSlotAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assign
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
return type;
}
@Override

View File

@@ -135,7 +135,7 @@ public class SetSuperAVM2Item extends AVM2Item implements SetTypeAVM2Item {
return compoundValue.toString(writer, localData);
}
writer.append(" = ");
return SetTypeIns.handleNumberToInt(value, type).toString(writer, localData);
return SetTypeIns.handleSetCoerce(value, type).toString(writer, localData);
}
@Override

View File

@@ -130,7 +130,7 @@ public class DeclarationAVM2Item extends AVM2Item {
type.appendTry(writer, localData);
if (showValue) {
writer.append(" = ");
SetTypeIns.handleNumberToInt(val, type).toString(writer, localData);
SetTypeIns.handleSetCoerce(val, type).toString(writer, localData);
}
return writer;
}
@@ -149,7 +149,7 @@ public class DeclarationAVM2Item extends AVM2Item {
type.appendTry(writer, localData);
if (showValue) {
writer.append(" = ");
SetTypeIns.handleNumberToInt(val, type).toString(writer, localData);
SetTypeIns.handleSetCoerce(val, type).toString(writer, localData);
}
return writer;
}
@@ -169,7 +169,7 @@ public class DeclarationAVM2Item extends AVM2Item {
type.appendTry(writer, localData);
if (showValue) {
writer.append(" = ");
SetTypeIns.handleNumberToInt(val, type).toString(writer, localData);
SetTypeIns.handleSetCoerce(val, type).toString(writer, localData);
}
return writer;
}