ABC merging

This commit is contained in:
Jindra Petřík
2016-08-15 21:15:53 +02:00
parent b750780cd9
commit 9262eff627
8 changed files with 575 additions and 71 deletions

View File

@@ -1237,7 +1237,7 @@ public class ABC {
for (int i = 0; i < ins.definition.operands.length; i++) {
if (ins.definition.operands[i] == AVM2Code.DAT_CLASS_INDEX) {
if (ins.operands[i] >= index) {
ins.operands[i]++;
ins.setOperand(i, ins.operands[i] + 1, b.getCode(), b);
}
}
}
@@ -1272,8 +1272,7 @@ public class ABC {
for (int i = 0; i < ins.definition.operands.length; i++) {
if (ins.definition.operands[i] == AVM2Code.DAT_CLASS_INDEX) {
if (ins.operands[i] > index) {
ins.operands[i]--;
b.setModified();
ins.setOperand(i, ins.operands[i] - 1, b.getCode(), b);
}
}
}
@@ -1330,8 +1329,7 @@ public class ABC {
for (int i = 0; i < ins.definition.operands.length; i++) {
if (ins.definition.operands[i] == AVM2Code.DAT_METHOD_INDEX) {
if (ins.operands[i] > index) {
ins.operands[i]--;
b.setModified();
ins.setOperand(i, ins.operands[i] - 1, b.getCode(), b);
}
}
}
@@ -1453,24 +1451,137 @@ public class ABC {
getMethodIndexing();
}
/**
* Merges second ABC to this one.
*
* @param secondABC
*/
public void mergeABC(ABC secondABC) {
Map<Integer, Integer> namespaceMap = new HashMap<>();
Map<Integer, Integer> namespaceSetMap = new HashMap<>();
Map<Integer, Integer> multinameMap = new HashMap<>();
Map<Integer, Integer> methodInfoMap = new HashMap<>();
Map<Integer, Integer> mergeStringMap = new HashMap<>();
Map<Integer, Integer> mergeIntMap = new HashMap<>();
Map<Integer, Integer> mergeUIntMap = new HashMap<>();
Map<Integer, Integer> mergeDoubleMap = new HashMap<>();
Map<Integer, Integer> mergeFloatMap = new HashMap<>();
Map<Integer, Integer> mergeFloat4Map = new HashMap<>();
Map<Integer, Integer> mergeDecimalMap = new HashMap<>();
constants.merge(secondABC.constants, namespaceMap, namespaceSetMap, multinameMap);
Map<Integer, Integer> mergeNamespaceMap = new HashMap<>();
Map<Integer, Integer> mergeNamespaceSetMap = new HashMap<>();
Map<Integer, Integer> mergeMultinameMap = new HashMap<>();
Map<Integer, Integer> mergeMethodInfoMap = new HashMap<>();
Map<Integer, Integer> mergeMethodBodyMap = new HashMap<>();
Map<Integer, Integer> mergeClassIndexMap = new HashMap<>();
Map<Integer, Integer> mergeMetaDataMap = new HashMap<>();
Map<Integer, Integer> mergeScriptInfoMap = new HashMap<>();
mergeABC(secondABC, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeNamespaceSetMap, mergeMultinameMap, mergeMethodInfoMap, mergeMethodBodyMap, mergeClassIndexMap, mergeMetaDataMap, mergeScriptInfoMap);
}
/**
* Merges second ABC to this one. Gets mapping of indices.
*
* @param secondABC
* @param mergeStringMap
* @param mergeIntMap
* @param mergeUIntMap
* @param mergeDoubleMap
* @param mergeFloatMap
* @param mergeFloat4Map
* @param mergeDecimalMap
* @param mergeNamespaceMap
* @param mergeNamespaceSetMap
* @param mergeMultinameMap
* @param mergeMethodInfoMap
* @param mergeMethodBodyMap
* @param mergeClassIndexMap
* @param mergeMetaDataMap
* @param mergeScriptInfoMap
*/
public void mergeABC(ABC secondABC,
Map<Integer, Integer> mergeStringMap,
Map<Integer, Integer> mergeIntMap,
Map<Integer, Integer> mergeUIntMap,
Map<Integer, Integer> mergeDoubleMap,
Map<Integer, Integer> mergeFloatMap,
Map<Integer, Integer> mergeFloat4Map,
Map<Integer, Integer> mergeDecimalMap,
Map<Integer, Integer> mergeNamespaceMap,
Map<Integer, Integer> mergeNamespaceSetMap,
Map<Integer, Integer> mergeMultinameMap,
Map<Integer, Integer> mergeMethodInfoMap,
Map<Integer, Integer> mergeMethodBodyMap,
Map<Integer, Integer> mergeClassIndexMap,
Map<Integer, Integer> mergeMetaDataMap,
Map<Integer, Integer> mergeScriptInfoMap
) {
if (!version.equals(secondABC.version)) {
throw new RuntimeException("ABC versions mismatch");
}
//Constants
constants.merge(secondABC.constants, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeNamespaceSetMap, mergeMultinameMap);
//Metadata
for (int m = 0; m < secondABC.metadata_info.size(); m++) {
MetadataInfo secondMetadataInfo = secondABC.metadata_info.get(m);
MetadataInfo newMetadataInfo = new MetadataInfo();
newMetadataInfo.name_index = mergeStringMap.get(secondMetadataInfo.name_index);
newMetadataInfo.keys = new int[secondMetadataInfo.keys.length];
newMetadataInfo.values = new int[secondMetadataInfo.values.length];
for (int i = 0; i < secondMetadataInfo.keys.length; i++) {
newMetadataInfo.keys[i] = mergeStringMap.get(secondMetadataInfo.keys[i]);
newMetadataInfo.values[i] = mergeStringMap.get(secondMetadataInfo.values[i]);
}
int newIndex = metadata_info.size();
metadata_info.add(newMetadataInfo);
mergeMetaDataMap.put(m, newIndex);
}
//Method Info
for (int i = 0; i < secondABC.method_info.size(); i++) {
MethodInfo secondMethodInfo = secondABC.method_info.get(i);
int newParamTypes[] = new int[secondMethodInfo.param_types.length];
for (int t = 0; t < secondMethodInfo.param_types.length; t++) {
newParamTypes[t] = mergeMultinameMap.get(secondMethodInfo.param_types[t]);
}
int newParamNames[] = new int[secondMethodInfo.paramNames.length];
int newRetType = multinameMap.get(secondMethodInfo.ret_type);
int newNameIndex = constants.getStringId(secondABC.constants.getString(secondMethodInfo.name_index), true);
for (int n = 0; n < secondMethodInfo.paramNames.length; n++) {
newParamNames[n] = mergeStringMap.get(secondMethodInfo.paramNames[n]);
}
int newRetType = mergeMultinameMap.get(secondMethodInfo.ret_type);
int newNameIndex = mergeStringMap.get(secondMethodInfo.name_index);
ValueKind newOptional[] = new ValueKind[secondMethodInfo.optional.length];
for (int k = 0; k < secondMethodInfo.optional.length; k++) {
int vkind = secondMethodInfo.optional[k].value_kind;
int newValueIndex;
Map<Integer, Integer> valueMergeMap = null;
switch (vkind) {
case ValueKind.CONSTANT_Utf8:
valueMergeMap = mergeStringMap;
break;
case ValueKind.CONSTANT_Int:
valueMergeMap = mergeIntMap;
break;
case ValueKind.CONSTANT_UInt:
valueMergeMap = mergeUIntMap;
break;
case ValueKind.CONSTANT_Double:
valueMergeMap = mergeDoubleMap;
break;
case ValueKind.CONSTANT_DecimalOrFloat:
//assuming the second ABC has same decimal/float support
if (hasDecimalSupport()) {
valueMergeMap = mergeDecimalMap;
} else if (hasFloatSupport()) {
valueMergeMap = mergeFloatMap;
} else {
//should not happen
}
break;
case ValueKind.CONSTANT_Float4:
if (hasFloatSupport()) {
valueMergeMap = mergeFloat4Map;
}
break;
case ValueKind.CONSTANT_ExplicitNamespace:
case ValueKind.CONSTANT_Namespace:
case ValueKind.CONSTANT_PackageInternalNs:
@@ -1478,25 +1589,264 @@ public class ABC {
case ValueKind.CONSTANT_ProtectedNamespace:
case ValueKind.CONSTANT_PrivateNs:
case ValueKind.CONSTANT_StaticProtectedNs:
newValueIndex = namespaceMap.get(secondMethodInfo.optional[k].value_index);
valueMergeMap = mergeNamespaceMap;
break;
default:
newValueIndex = secondMethodInfo.optional[k].value_index;
}
int newValueIndex = valueMergeMap != null ? valueMergeMap.get(secondMethodInfo.optional[k].value_index) : secondMethodInfo.optional[k].value_index;
newOptional[k] = new ValueKind(newValueIndex, vkind);
}
MethodInfo newMethodInfo = new MethodInfo(newParamTypes, newRetType, newNameIndex, secondMethodInfo.flags, newOptional, newParamNames);
int newIndex = addMethodInfo(newMethodInfo);
methodInfoMap.put(i, newIndex);
mergeMethodInfoMap.put(i, newIndex);
}
for (MethodBody secondBody : secondABC.bodies) {
//TODO!!!
//MethodBody newBody = new MethodBody(this, mergeTraits(secondBody.traits), codeBytes, exceptions)
int classFirstIndex = class_info.size();
//Class/Instance
for (int c = 0; c < secondABC.class_info.size(); c++) {
ClassInfo secondClassInfo = secondABC.class_info.get(c);
ClassInfo newClassInfo = new ClassInfo();
int newIndex = class_info.size();
class_info.add(newClassInfo);
mergeClassIndexMap.put(c, newIndex);
newClassInfo.cinit_index = mergeMethodInfoMap.get(secondClassInfo.cinit_index);
newClassInfo.lastDispId = secondClassInfo.lastDispId;
InstanceInfo secondInstanceInfo = secondABC.instance_info.get(c);
InstanceInfo newInstanceInfo = new InstanceInfo();
newInstanceInfo.iinit_index = mergeMethodInfoMap.get(secondInstanceInfo.iinit_index);
newInstanceInfo.super_index = mergeMultinameMap.get(secondInstanceInfo.super_index);
newInstanceInfo.interfaces = new int[secondInstanceInfo.interfaces.length];
for (int i = 0; i < secondInstanceInfo.interfaces.length; i++) {
newInstanceInfo.interfaces[i] = mergeMultinameMap.get(secondInstanceInfo.interfaces[i]);
}
newInstanceInfo.protectedNS = mergeNamespaceMap.get(secondInstanceInfo.protectedNS);
newInstanceInfo.name_index = mergeMultinameMap.get(secondInstanceInfo.name_index);
newInstanceInfo.flags = secondInstanceInfo.flags;
instance_info.add(newInstanceInfo);
//do traits in second step as some classes may depend on other classes
}
//Class/Instance traits
for (int c = 0; c < secondABC.class_info.size(); c++) {
ClassInfo secondClassInfo = secondABC.class_info.get(c);
InstanceInfo secondInstanceInfo = secondABC.instance_info.get(c);
ClassInfo newClassInfo = class_info.get(classFirstIndex + c);
InstanceInfo newInstanceInfo = instance_info.get(classFirstIndex + c);
newClassInfo.static_traits = mergeTraits(secondClassInfo.static_traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
newInstanceInfo.instance_traits = mergeTraits(secondInstanceInfo.instance_traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
}
//Scripts
for (int s = 0; s < secondABC.script_info.size(); s++) {
ScriptInfo secondScriptInfo = secondABC.script_info.get(s);
ScriptInfo newScriptInfo = new ScriptInfo();
newScriptInfo.init_index = mergeMethodInfoMap.get(secondScriptInfo.init_index);
newScriptInfo.traits = mergeTraits(secondScriptInfo.traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
int newIndex = script_info.size();
script_info.add(newScriptInfo);
mergeScriptInfoMap.put(s, newIndex);
}
//Method bodies
for (int b = 0; b < secondABC.bodies.size(); b++) {
MethodBody secondBody = secondABC.bodies.get(b);
MethodBody newBody = secondBody.clone(true);
newBody.method_info = mergeMethodInfoMap.get(secondBody.method_info);
for (int e = 0; e < secondBody.exceptions.length; e++) {
newBody.exceptions[e].name_index = mergeMultinameMap.get(secondBody.exceptions[e].name_index);
newBody.exceptions[e].type_index = mergeMultinameMap.get(secondBody.exceptions[e].type_index);
}
AVM2Code newCode = newBody.getCode();
for (AVM2Instruction newIns : newCode.code) {
int newOperands[] = newIns.operands == null ? null : newIns.operands.clone();
boolean modified = false;
if (newIns.operands != null) {
for (int i = 0; i < newIns.definition.operands.length; i++) {
Map<Integer, Integer> mergeMap = null;
switch (newIns.definition.operands[i]) {
case AVM2Code.DAT_CLASS_INDEX:
mergeMap = mergeClassIndexMap;
break;
case AVM2Code.DAT_STRING_INDEX:
mergeMap = mergeStringMap;
break;
case AVM2Code.DAT_INT_INDEX:
mergeMap = mergeIntMap;
break;
case AVM2Code.DAT_UINT_INDEX:
mergeMap = mergeUIntMap;
break;
case AVM2Code.DAT_DOUBLE_INDEX:
mergeMap = mergeDoubleMap;
break;
case AVM2Code.DAT_DECIMAL_INDEX:
mergeMap = mergeDecimalMap;
break;
case AVM2Code.DAT_FLOAT_INDEX:
mergeMap = mergeFloatMap;
break;
case AVM2Code.DAT_FLOAT4_INDEX:
mergeMap = mergeFloat4Map;
break;
case AVM2Code.DAT_NAMESPACE_INDEX:
mergeMap = mergeNamespaceMap;
break;
case AVM2Code.DAT_METHOD_INDEX:
mergeMap = mergeMethodInfoMap;
break;
case AVM2Code.DAT_MULTINAME_INDEX:
mergeMap = mergeMultinameMap;
break;
}
if (mergeMap != null) {
newOperands[i] = mergeMap.get(newIns.operands[i]);
modified = true;
}
}
}
if (modified) {
newIns.setOperands(newOperands, newCode, newBody);
}
newBody.traits = mergeTraits(secondBody.traits, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap, mergeMethodInfoMap, mergeClassIndexMap);
}
newBody.setModified();
int newIndex = bodies.size();
bodies.add(newBody);
mergeMethodBodyMap.put(b, newIndex);
}
//clear caches
abcMethodIndexing = null;
getSwf().clearScriptCache();
((Tag) parentTag).setModified(true);
}
private Traits mergeTraits(Traits secondTraits) {
return null; //TODO
private Traits mergeTraits(Traits secondTraits, Map<Integer, Integer> mergeMultinameMap,
Map<Integer, Integer> mergeStringMap,
Map<Integer, Integer> mergeIntMap,
Map<Integer, Integer> mergeUIntMap,
Map<Integer, Integer> mergeDoubleMap,
Map<Integer, Integer> mergeFloatMap,
Map<Integer, Integer> mergeFloat4Map,
Map<Integer, Integer> mergeDecimalMap,
Map<Integer, Integer> mergeNamespaceMap,
Map<Integer, Integer> mergeMetaDataMap,
Map<Integer, Integer> mergeMethodInfoMap,
Map<Integer, Integer> mergeClassIndexMap) {
Traits newTraits = new Traits();
for (Trait t : secondTraits.traits) {
Trait newTrait = null;
if (t instanceof TraitMethodGetterSetter) {
newTrait = mergeTrait((TraitMethodGetterSetter) t, mergeMultinameMap, mergeMethodInfoMap, mergeMetaDataMap);
} else if (t instanceof TraitSlotConst) {
newTrait = mergeTrait((TraitSlotConst) t, mergeMultinameMap, mergeStringMap, mergeIntMap, mergeUIntMap, mergeDoubleMap, mergeFloatMap, mergeFloat4Map, mergeDecimalMap, mergeNamespaceMap, mergeMetaDataMap);
} else if (t instanceof TraitFunction) {
newTrait = mergeTrait((TraitFunction) t, mergeMultinameMap, mergeMethodInfoMap, mergeMetaDataMap);
} else if (t instanceof TraitClass) {
newTrait = mergeTrait((TraitClass) t, mergeClassIndexMap, mergeMultinameMap, mergeMetaDataMap);
} else {
//should not happen
}
newTraits.addTrait(newTrait);
}
return newTraits;
}
private TraitMethodGetterSetter mergeTrait(TraitMethodGetterSetter secondTrait, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMethodInfoMap, Map<Integer, Integer> mergeMetaDataMap) {
TraitMethodGetterSetter newTrait = secondTrait.clone();
newTrait.method_info = mergeMethodInfoMap.get(secondTrait.method_info);
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
for (int m = 0; m < secondTrait.metadata.length; m++) {
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
}
return newTrait;
}
private TraitSlotConst mergeTrait(TraitSlotConst secondTrait, Map<Integer, Integer> mergeMultinameMap,
Map<Integer, Integer> mergeStringMap,
Map<Integer, Integer> mergeIntMap,
Map<Integer, Integer> mergeUIntMap,
Map<Integer, Integer> mergeDoubleMap,
Map<Integer, Integer> mergeFloatMap,
Map<Integer, Integer> mergeFloat4Map,
Map<Integer, Integer> mergeDecimalMap,
Map<Integer, Integer> mergeNamespaceMap,
Map<Integer, Integer> mergeMetaDataMap
) {
TraitSlotConst newTrait = secondTrait.clone();
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
for (int m = 0; m < secondTrait.metadata.length; m++) {
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
}
newTrait.type_index = mergeMultinameMap.get(secondTrait.type_index);
Map<Integer, Integer> valueMergeMap = null;
switch (newTrait.value_kind) {
case ValueKind.CONSTANT_Utf8:
valueMergeMap = mergeStringMap;
break;
case ValueKind.CONSTANT_Int:
valueMergeMap = mergeIntMap;
break;
case ValueKind.CONSTANT_UInt:
valueMergeMap = mergeUIntMap;
break;
case ValueKind.CONSTANT_Double:
valueMergeMap = mergeDoubleMap;
break;
case ValueKind.CONSTANT_DecimalOrFloat:
//assuming the second ABC has same decimal/float support
if (hasDecimalSupport()) {
valueMergeMap = mergeDecimalMap;
} else if (hasFloatSupport()) {
valueMergeMap = mergeFloatMap;
} else {
//should not happen
}
break;
case ValueKind.CONSTANT_Float4:
if (hasFloatSupport()) {
valueMergeMap = mergeFloat4Map;
}
break;
case ValueKind.CONSTANT_ExplicitNamespace:
case ValueKind.CONSTANT_Namespace:
case ValueKind.CONSTANT_PackageInternalNs:
case ValueKind.CONSTANT_PackageNamespace:
case ValueKind.CONSTANT_PrivateNs:
case ValueKind.CONSTANT_ProtectedNamespace:
case ValueKind.CONSTANT_StaticProtectedNs:
valueMergeMap = mergeNamespaceMap;
break;
}
if (valueMergeMap != null) {
newTrait.value_index = valueMergeMap.get(secondTrait.value_index);
}
return newTrait; //TODO
}
private TraitFunction mergeTrait(TraitFunction secondTrait, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMethodInfoMap, Map<Integer, Integer> mergeMetaDataMap) {
TraitFunction newTrait = secondTrait.clone();
newTrait.method_info = mergeMethodInfoMap.get(secondTrait.method_info);
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
for (int m = 0; m < secondTrait.metadata.length; m++) {
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
}
return newTrait;
}
private TraitClass mergeTrait(TraitClass secondTrait, Map<Integer, Integer> mergeClassMap, Map<Integer, Integer> mergeMultinameMap, Map<Integer, Integer> mergeMetaDataMap) {
TraitClass newTrait = secondTrait.clone();
newTrait.class_info = mergeClassMap.get(secondTrait.class_info);
newTrait.name_index = mergeMultinameMap.get(secondTrait.name_index);
for (int m = 0; m < secondTrait.metadata.length; m++) {
newTrait.metadata[m] = mergeMetaDataMap.get(secondTrait.metadata[m]);
}
return newTrait;
}
}

View File

@@ -27,4 +27,27 @@ public class ABCVersion implements Comparable<ABCVersion> {
return "" + major + "." + minor;
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + this.major;
hash = 53 * hash + this.minor;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ABCVersion other = (ABCVersion) obj;
return true;
}
}

View File

@@ -1100,6 +1100,11 @@ public class AVM2Code implements Cloneable {
}
}
public void setInstructionOperand(int ip, int operandIndex, int value, MethodBody body) {
int oldVal = code.get(ip).operands[ip];
code.get(ip).operands[ip] = value;
}
public byte[] getBytes() {
return getBytes(null);
}
@@ -2145,6 +2150,38 @@ public class AVM2Code implements Cloneable {
return list;
}
public void updateInstructionByteCountByAddr(long instructionAddress, int byteDelta, MethodBody body) {
if (byteDelta != 0) {
updateOffsets(new OffsetUpdater() {
@Override
public long updateInstructionOffset(long address) {
if (address > instructionAddress) {
return address + byteDelta;
}
return address;
}
@Override
public int updateOperandOffset(long insAddr, long targetAddress, int offset) {
if (targetAddress > instructionAddress && insAddr <= instructionAddress) {
return offset + byteDelta;
}
if (targetAddress <= instructionAddress && insAddr > instructionAddress) {
return offset - byteDelta;
}
return offset;
}
}, body);
body.setModified();
}
}
public void updateInstructionByteCount(int pos, int byteDelta, MethodBody body) {
AVM2Instruction instruction = code.get(pos);
updateInstructionByteCountByAddr(instruction.getAddress(), byteDelta, body);
}
public void updateOffsets(OffsetUpdater updater, MethodBody body) {
for (int i = 0; i < code.size(); i++) {
AVM2Instruction ins = code.get(i);
@@ -2172,6 +2209,7 @@ public class AVM2Code implements Cloneable {
}
}
ins.setAddress(updater.updateInstructionOffset(ins.getAddress()));
//Note: changing operands here does not change instruction byte length as offsets are always S24 (not variable length)
}
for (ABCException ex : body.exceptions) {

View File

@@ -772,50 +772,68 @@ public class AVM2ConstantPool implements Cloneable {
* Merges second constantpool into this one
*
* @param secondPool
* @param namespaceMap Output map of merged namespaces. Index in second pool
* to index in this pool.
* @param namespaceSetMap Output map of merged namespace sets. Index in
* second pool to index in this pool.
* @param multinameMap Output map of merged multinames. Index in second pool
* to index in this pool.
* @param stringMap
* @param intMap
* @param uintMap
* @param doubleMap
* @param floatMap
* @param float4Map
* @param decimalMap
* @param namespaceMap
* @param namespaceSetMap
* @param multinameMap
*/
public void merge(AVM2ConstantPool secondPool, Map<Integer, Integer> namespaceMap, Map<Integer, Integer> namespaceSetMap, Map<Integer, Integer> multinameMap) {
for (String val : secondPool.constant_string) {
getStringId(val, true);
public void merge(AVM2ConstantPool secondPool, Map<Integer, Integer> stringMap, Map<Integer, Integer> intMap, Map<Integer, Integer> uintMap, Map<Integer, Integer> doubleMap, Map<Integer, Integer> floatMap, Map<Integer, Integer> float4Map, Map<Integer, Integer> decimalMap, Map<Integer, Integer> namespaceMap, Map<Integer, Integer> namespaceSetMap, Map<Integer, Integer> multinameMap) {
stringMap.put(0, 0);
for (int i = 1; i < secondPool.constant_string.size(); i++) {
String val = secondPool.constant_string.get(i);
stringMap.put(i, getStringId(val, true));
}
for (Long val : secondPool.constant_int) {
getIntId(val, true);
intMap.put(0, 0);
for (int i = 1; i < secondPool.constant_int.size(); i++) {
Long val = secondPool.constant_int.get(i);
intMap.put(i, getIntId(val, true));
}
for (Long val : secondPool.constant_uint) {
getUIntId(val, true);
uintMap.put(0, 0);
for (int i = 1; i < secondPool.constant_uint.size(); i++) {
Long val = secondPool.constant_uint.get(i);
uintMap.put(i, getUIntId(val, true));
}
for (Double val : secondPool.constant_double) {
getDoubleId(val, true);
doubleMap.put(0, 0);
for (int i = 1; i < secondPool.constant_double.size(); i++) {
Double val = secondPool.constant_double.get(i);
doubleMap.put(i, getDoubleId(val, true));
}
for (Float val : secondPool.constant_float) {
getFloatId(val, true);
floatMap.put(0, 0);
for (int i = 1; i < secondPool.constant_float.size(); i++) {
Float val = secondPool.constant_float.get(i);
floatMap.put(i, getFloatId(val, true));
}
for (Float4 val : secondPool.constant_float4) {
getFloat4Id(val, true);
float4Map.put(0, 0);
for (int i = 1; i < secondPool.constant_float4.size(); i++) {
Float4 val = secondPool.constant_float4.get(i);
float4Map.put(i, getFloat4Id(val, true));
}
for (Decimal val : secondPool.constant_decimal) {
getDecimalId(val, true);
decimalMap.put(0, 0);
for (int i = 1; i < secondPool.constant_decimal.size(); i++) {
Decimal val = secondPool.constant_decimal.get(i);
decimalMap.put(i, getDecimalId(val, true));
}
namespaceMap.put(0, 0);
for (int i = 1; i < secondPool.constant_namespace.size(); i++) {
Namespace secondNamespace = secondPool.getNamespace(i);
String secondNsNameStr = secondNamespace.name_index == 0 ? null : secondPool.getString(secondNamespace.name_index);
Namespace secondNamespace = secondPool.constant_namespace.get(i);
int mappedId;
int newNameIndex = stringMap.get(secondNamespace.name_index);
if (secondNamespace.kind == Namespace.KIND_PRIVATE) {//always add, this does not exists in this ABC. Conflicting private namespaces can have same names.
mappedId = addNamespace(secondNamespace.kind, getStringId(secondNsNameStr, true));
mappedId = addNamespace(secondNamespace.kind, newNameIndex);
} else {
mappedId = getNamespaceId(secondNamespace.kind, secondNsNameStr, 0, true);
mappedId = getNamespaceId(secondNamespace.kind, newNameIndex, 0, true);
}
namespaceMap.put(i, mappedId);
}
namespaceSetMap.put(0, 0);
for (int i = 1; i < secondPool.constant_namespace_set.size(); i++) {
NamespaceSet secondNamespaceSet = secondPool.getNamespaceSet(i);
NamespaceSet secondNamespaceSet = secondPool.constant_namespace_set.get(i);
int mappedsNss[] = new int[secondNamespaceSet.namespaces.length];
for (int n = 0; n < secondNamespaceSet.namespaces.length; n++) {
mappedsNss[n] = namespaceMap.get(secondNamespaceSet.namespaces[n]);
@@ -825,42 +843,42 @@ public class AVM2ConstantPool implements Cloneable {
}
multinameMap.put(0, 0);
for (int i = 1; i < secondPool.constant_multiname.size(); i++) {
Multiname secondMultiname = secondPool.getMultiname(i);
Multiname importedMultiname = null;
int newNameIndex = secondMultiname.name_index <= 0 ? secondMultiname.name_index : getStringId(secondPool.getString(secondMultiname.name_index), true);
Multiname secondMultiname = secondPool.constant_multiname.get(i);
Multiname newMultiname = null;
int newNameIndex = secondMultiname.name_index <= 0 ? secondMultiname.name_index : stringMap.get(secondMultiname.name_index);
int newNsIndex = secondMultiname.namespace_index <= 0 ? secondMultiname.namespace_index : namespaceMap.get(secondMultiname.namespace_index);
int newNssIndex = secondMultiname.namespace_set_index <= 0 ? secondMultiname.namespace_set_index : namespaceSetMap.get(secondMultiname.namespace_set_index);
switch (secondMultiname.kind) {
case Multiname.MULTINAME:
importedMultiname = Multiname.createMultiname(false, newNameIndex, newNssIndex);
newMultiname = Multiname.createMultiname(false, newNameIndex, newNssIndex);
break;
case Multiname.MULTINAMEA:
importedMultiname = Multiname.createMultiname(true, newNameIndex, newNssIndex);
newMultiname = Multiname.createMultiname(true, newNameIndex, newNssIndex);
break;
case Multiname.MULTINAMEL:
importedMultiname = Multiname.createMultinameL(false, newNssIndex);
newMultiname = Multiname.createMultinameL(false, newNssIndex);
break;
case Multiname.MULTINAMELA:
importedMultiname = Multiname.createMultinameL(true, newNssIndex);
newMultiname = Multiname.createMultinameL(true, newNssIndex);
break;
case Multiname.QNAME:
importedMultiname = Multiname.createQName(false, newNameIndex, newNsIndex);
newMultiname = Multiname.createQName(false, newNameIndex, newNsIndex);
break;
case Multiname.QNAMEA:
importedMultiname = Multiname.createQName(true, newNameIndex, newNsIndex);
newMultiname = Multiname.createQName(true, newNameIndex, newNsIndex);
break;
case Multiname.RTQNAME:
importedMultiname = Multiname.createRTQName(false, newNameIndex);
newMultiname = Multiname.createRTQName(false, newNameIndex);
break;
case Multiname.RTQNAMEA:
importedMultiname = Multiname.createRTQName(true, newNameIndex);
newMultiname = Multiname.createRTQName(true, newNameIndex);
break;
case Multiname.RTQNAMEL:
importedMultiname = Multiname.createRTQNameL(false);
newMultiname = Multiname.createRTQNameL(false);
break;
case Multiname.RTQNAMELA:
importedMultiname = Multiname.createRTQNameL(true);
newMultiname = Multiname.createRTQNameL(true);
break;
case Multiname.TYPENAME:
int newQnameIndex = multinameMap.get(secondMultiname.qname_index);
@@ -868,11 +886,11 @@ public class AVM2ConstantPool implements Cloneable {
for (int p = 0; p < secondMultiname.params.length; p++) {
newParams[p] = multinameMap.get(secondMultiname.params[p]);
}
importedMultiname = Multiname.createTypeName(newQnameIndex, newParams);
newMultiname = Multiname.createTypeName(newQnameIndex, newParams);
break;
}
int mappedId = getMultinameId(importedMultiname, true);
int mappedId = getMultinameId(newMultiname, true);
multinameMap.put(i, mappedId);
}

View File

@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.types.Float4;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
@@ -488,4 +489,42 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem {
public String getFile() {
return file;
}
/**
* Set operand value the right way - update offsets neccessarily. Because
* some operand types are variable length (like U30)
*
* @param operandIndex
* @param newValue
* @param code
* @param body
*/
public void setOperand(int operandIndex, int newValue, AVM2Code code, MethodBody body) {
int oldByteCount = getBytesLength();
operands[operandIndex] = newValue;
int newByteCount = getBytesLength();
int byteDelta = newByteCount - oldByteCount;
if (byteDelta != 0) {
code.updateInstructionByteCountByAddr(address, byteDelta, body);
}
}
/**
* Set operand values the right way - update offsets neccessarily. Because
* some operand types are variable length (like U30)
*
* @param operands
* @param code
* @param body
*/
public void setOperands(int operands[], AVM2Code code, MethodBody body) {
int oldByteCount = getBytesLength();
this.operands = operands;
int newByteCount = getBytesLength();
int byteDelta = newByteCount - oldByteCount;
if (byteDelta != 0) {
code.updateInstructionByteCountByAddr(address, byteDelta, body);
}
}
}

View File

@@ -424,6 +424,10 @@ public final class MethodBody implements Cloneable {
@Override
public MethodBody clone() {
return clone(false);
}
public MethodBody clone(boolean deepTraits) {
try {
MethodBody ret = (MethodBody) super.clone();
if (code != null) {
@@ -437,10 +441,9 @@ public final class MethodBody implements Cloneable {
}
}
// maybe deep clone traits
/*if (traits != null) {
ret.traits = traits.clone();
}*/
if (deepTraits && traits != null) {
ret.traits = traits.clone();
}
ret.convertedItems = null;
ret.convertException = null;

View File

@@ -25,7 +25,7 @@ import com.jpexs.helpers.Helper;
*/
public class ValueKind {
public static final int CONSTANT_Decimal = 0x02; //decimal
public static final int CONSTANT_DecimalOrFloat = 0x02; //decimal or float depending on ABC version
public static final int CONSTANT_Int = 0x03;// integer
@@ -57,6 +57,8 @@ public class ValueKind {
public static final int CONSTANT_PrivateNs = 0x05;// namespace
public static final int CONSTANT_Float4 = 0x1E;// float4
private static final int[] optionalKinds = new int[]{0x03, 0x04, 0x06, 0x02, 0x01, 0x0B, 0x0A, 0x0C, 0x00, 0x08, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x05};
private static final String[] optionalKindNames = new String[]{"Int", "UInt", "Double", "Decimal", "Utf8", "True", "False", "Null", "Undefined", "Namespace", "PackageNamespace", "PackageInternalNs", "ProtectedNamespace", "ExplicitNamespace", "StaticProtectedNs", "PrivateNamespace"};
@@ -137,7 +139,7 @@ public class ValueKind {
case CONSTANT_Double:
ret = "" + constants.getDouble(value_index);
break;
case CONSTANT_Decimal:
case CONSTANT_DecimalOrFloat:
ret = "" + constants.getDecimal(value_index);
break;
case CONSTANT_Utf8:
@@ -179,7 +181,7 @@ public class ValueKind {
case CONSTANT_Double:
ret = "Double(" + constants.getDouble(value_index) + ")";
break;
case CONSTANT_Decimal:
case CONSTANT_DecimalOrFloat:
ret = "Decimal(" + constants.getDecimal(value_index) + ")";
break;
case CONSTANT_Utf8: