AS3 parser: try..catch, activation, slots

This commit is contained in:
Jindra Pet��k
2014-04-06 09:36:10 +02:00
parent 95af9e9268
commit 7e19be36c8
14 changed files with 477 additions and 154 deletions
@@ -32,19 +32,9 @@ public class SourceGeneratorLocalData implements Serializable {
public Integer inFunction;
public Boolean inMethod;
public Integer forInLevel;
//public List<String> openedNamespaces = new ArrayList<>();
//public List<Integer> openedNamespacesKinds = new ArrayList<>();
public List<ABCException> exceptions = new ArrayList<>();
public String currentClass;
/*
public void addNamespace(int kind, String ns) {
addNamespace(kind, ns, openedNamespaces.size() - 1);
}
public void addNamespace(int kind, String ns, int index) {
openedNamespaces.add(index, ns);
openedNamespacesKinds.add(index, kind);
}*/
public int activationReg = 0;
public SourceGeneratorLocalData(HashMap<String, Integer> registerVars, Integer inFunction, Boolean inMethod, Integer forInLevel) {
this.registerVars = registerVars;
@@ -1934,15 +1934,33 @@ public class AVM2Code implements Serializable {
if (!walkCode(stats, 0, 0, initScope, abc)) {
return null;
}
int scopePos = -1;
for (ABCException ex : body.exceptions) {
try {
int exStart = adr2pos(ex.start);
if (!walkCode(stats, adr2pos(ex.target), stats.instructionStats[exStart].stackpos, stats.instructionStats[exStart].scopepos, abc)) {
if(scopePos==-1){
scopePos=stats.instructionStats[adr2pos(ex.end)-1].scopepos;
}
List<Integer> visited = new ArrayList<>();
for(int i=0;i<stats.instructionStats.length;i++){
if(stats.instructionStats[i].seen){
visited.add(i);
}
}
if (!walkCode(stats, adr2pos(ex.target), 1/*exception*/, scopePos, abc)) {
return null;
}
int maxIp = 0;
//searching for visited instruction in second run which has maximum position
for(int i=0;i<stats.instructionStats.length;i++){
if(stats.instructionStats[i].seen && !visited.contains(i)){
maxIp = i;
}
}
scopePos = stats.instructionStats[maxIp].scopepos;
} catch (ConvertException ex1) {
}
}
//stats.maxscope+=initScope;
return stats;
}
@@ -16,12 +16,16 @@
*/
package com.jpexs.decompiler.flash.abc.avm2.model.clauses;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.AVM2SourceGenerator;
import com.jpexs.decompiler.flash.abc.avm2.parser.script.NameAVM2Item;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.Block;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SourceGenerator;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.LocalData;
@@ -148,4 +152,11 @@ public class TryAVM2Item extends AVM2Item implements Block {
public boolean hasReturnValue() {
return false;
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) {
return ((AVM2SourceGenerator)generator).generate(localData, this);
}
}
@@ -24,6 +24,8 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructSuperIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewActivationIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewCatchIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewClassIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfFalseIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.IfStrictNeIns;
@@ -43,16 +45,19 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextNameIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NextValueIns;
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.SetSlotIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopScopeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
@@ -101,6 +106,7 @@ import com.jpexs.decompiler.graph.model.WhileItem;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -117,6 +123,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
public final ABC abc;
public List<ABC> allABCs;
public static final int MARK_E_START = 0;
public static final int MARK_E_END = 1;
public static final int MARK_E_TARGET = 2;
private AVM2Instruction ins(InstructionDefinition def, int... operands) {
return new AVM2Instruction(0, def, operands, new byte[0]);
}
@@ -560,15 +570,76 @@ public class AVM2SourceGenerator implements SourceGenerator {
return ret;
}
private List<AVM2Instruction> shiftExc(List<AVM2Instruction> list,int shift){
for(AVM2Instruction ins:list){
if(ins instanceof ExceptionMarkAVM2Instruction){
ExceptionMarkAVM2Instruction e=(ExceptionMarkAVM2Instruction)ins;
e.exceptionId+=shift;
}
}
return list;
}
public List<GraphSourceItem> generate(SourceGeneratorLocalData localData, TryAVM2Item item) {
List<GraphSourceItem> ret = new ArrayList<>();
int firstId = 0;
List<ABCException> newex=new ArrayList<>();
for (NameAVM2Item e : item.catchExceptions2) {
ABCException aex = new ABCException();
aex.name_index = str(e.getVariableName());
aex.name_index = abc.constants.getMultinameId(new Multiname(Multiname.QNAME, abc.constants.getStringId(e.getVariableName(), true), abc.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, abc.constants.getStringId("", true)), 0, true), 0,0,new ArrayList<Integer>()),true);
aex.type_index = typeName(localData, e.type);
localData.exceptions.add(aex);
//TODO
newex.add(aex);
}
List<AVM2Instruction> tryCmds=generateToActionList(localData, item.tryCommands);
List<List<AVM2Instruction>> catchCmds=new ArrayList<>();
for(int c=0;c<item.catchCommands.size();c++){
catchCmds.add(generateToActionList(localData, item.catchCommands.get(c)));
}
firstId = localData.exceptions.size();
for (int i=firstId;i<firstId+item.catchExceptions2.size();i++) {
ret.add(new ExceptionMarkAVM2Instruction(i, MARK_E_START));
}
ret.addAll(tryCmds);
for (int i=firstId;i<firstId+item.catchExceptions2.size();i++) {
ret.add(new ExceptionMarkAVM2Instruction(i, MARK_E_END));
}
int i=firstId+item.catchCommands.size()-1;
List<AVM2Instruction> catches=new ArrayList<>();
Reference<Integer> tempReg=new Reference<>(0);
for (int c=item.catchCommands.size()-1;c>=0;c--) {
List<AVM2Instruction> preCatches=new ArrayList<>();
preCatches.add(ins(new GetLocal0Ins()));
preCatches.add(ins(new PushScopeIns()));
preCatches.add(AssignableAVM2Item.generateGetLoc(localData.activationReg));
preCatches.add(ins(new PushScopeIns()));
preCatches.add(ins(new NewCatchIns(),i));
preCatches.addAll(toInsList(AssignableAVM2Item.dupSetTemp(localData, this, tempReg)));
preCatches.add(ins(new DupIns()));
preCatches.add(ins(new PushScopeIns()));
preCatches.add(ins(new SwapIns()));
preCatches.add(ins(new SetSlotIns(),1));
preCatches.addAll(catchCmds.get(c));
preCatches.add(ins(new PopScopeIns()));
preCatches.addAll(toInsList(AssignableAVM2Item.killTemp(localData, this, Arrays.asList(tempReg))));
catches.addAll(0,preCatches);
catches.add(0,new ExceptionMarkAVM2Instruction(i, MARK_E_TARGET));
i--;
catches.add(0,ins(new JumpIns(), insToBytes(catches).length));
}
ret.addAll(catches);
localData.exceptions.addAll(newex);
//TODO: finally
return ret;
}
@@ -664,12 +735,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
generateTraitsPhase2(initScope, pkg, name, superName, false, localData, traitItems, instanceInfo.instance_traits, it);
generateTraitsPhase2(initScope, pkg, name, superName, true, localData, traitItems, classInfo.static_traits, st);
if (constructor == null) {
instanceInfo.iinit_index = method(initScope + 1, false, false, 0, name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList<GraphTargetItem>(), new ArrayList<String>(), new ArrayList<GraphTargetItem>(), new ArrayList<GraphTargetItem>(), TypeItem.UNBOUNDED/*?? FIXME*/);
instanceInfo.iinit_index = method(pkg.packageName,false,new ArrayList<NameAVM2Item>(),initScope + 1, false, 0, name, extendsVal != null ? extendsVal.toString() : null, true, localData, new ArrayList<GraphTargetItem>(), new ArrayList<String>(), new ArrayList<GraphTargetItem>(), new ArrayList<GraphTargetItem>(), TypeItem.UNBOUNDED/*?? FIXME*/);
} else {
MethodAVM2Item m = (MethodAVM2Item) constructor;
Reference<Boolean> hasArgs = new Reference<>(Boolean.FALSE);
calcRegisters(localData, m, hasArgs);
instanceInfo.iinit_index = method(initScope + 1, m.hasRest, hasArgs.getVal(), m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/);
instanceInfo.iinit_index = method(pkg.packageName,m.needsActivation,m.subvariables,initScope + 1, m.hasRest, m.line, name, extendsVal != null ? extendsVal.toString() : null, true, localData, m.paramTypes, m.paramNames, m.paramValues, m.body, TypeItem.UNBOUNDED/*?? FIXME*/);
}
//Class initializer
@@ -759,6 +828,9 @@ public class AVM2SourceGenerator implements SourceGenerator {
String pkg = "";
String name = type.toString();
if("*".equals(name)){
return 0;
}
TypeItem nameItem = (TypeItem) type;
if (name.contains(".")) {
pkg = name.substring(0, name.lastIndexOf('.'));
@@ -847,26 +919,175 @@ public class AVM2SourceGenerator implements SourceGenerator {
return false;
}
public int method(int initScope, boolean hasRest, boolean hasArguments, int line, String className, String superType, boolean constructor, SourceGeneratorLocalData localData, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, GraphTargetItem retType) throws ParseException {
public int method(String pkg,boolean needsActivation,List<NameAVM2Item> subvariables,int initScope, boolean hasRest, int line, String className, String superType, boolean constructor, SourceGeneratorLocalData localData, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, GraphTargetItem retType) throws ParseException {
//Reference<Boolean> hasArgs = new Reference<>(Boolean.FALSE);
//calcRegisters(localData,needsActivation,paramNames,subvariables,body, hasArgs);
localData.activationReg = 0;
for (NameAVM2Item n : subvariables) {
if (n.unresolved) {
GraphTargetItem resolved = null;
List<ABC> abcs = new ArrayList<>();
abcs.add(abc);
abcs.addAll(allABCs);
for (int i = 0; i < n.openedNamespaces.size(); i++) {
int nsIndex = n.openedNamespaces.get(i);
Namespace ns = abc.constants.constant_namespace.get(nsIndex);
int nsKind = ns.kind;
loopabc:
for (ABC a : abcs) {
for (int h = 0; h < a.instance_info.size(); h++) {
InstanceInfo ii = a.instance_info.get(h);
Multiname nm = a.constants.constant_multiname.get(ii.name_index);
if (nm.getNamespace(a.constants).getName(a.constants).equals(ns.getName(abc.constants)) && nm.getNamespace(a.constants).kind == nsKind) {
//found opened class
Reference<String> outName = new Reference<>("");
Reference<String> outNs = new Reference<>("");
Reference<String> outPropNs = new Reference<>("");
Reference<Integer> outPropNsKind = new Reference<>(1);
Reference<String> outPropType = new Reference<>("");
if (AVM2SourceGenerator.searchPrototypeChain(false, abcs, nm.getNamespace(a.constants).getName(a.constants), nm.getName(a.constants, new ArrayList<String>()), n.getVariableName(), outName, outNs, outPropNs, outPropNsKind, outPropType)) {
resolved = new PropertyAVM2Item(null, n.getVariableName(), n.getIndex(), abc, allABCs, n.openedNamespaces);
}
}
}
}
}
n.redirect = resolved;
if (resolved == null) {
throw new ParseException("Unknown variable or property:" + n.getVariableName(), n.line);
}
}
}
boolean hasArguments = false;
List<String> slotNames = new ArrayList<>();
List<String> slotTypes = new ArrayList<>();
slotNames.add("--first");
slotTypes.add("-");
List<String> registerNames = new ArrayList<>();
List<String> registerTypes = new ArrayList<>();
registerTypes.add(pkg.equals("")?className:pkg+"."+className);
registerNames.add("this");
for(GraphTargetItem t:paramTypes){
registerTypes.add(t.toString());
slotTypes.add(t.toString());
}
registerNames.addAll(paramNames);
slotNames.addAll(paramNames);
localData.registerVars.clear();
for (NameAVM2Item n : subvariables) {
if (n.getVariableName().equals("arguments") & !n.isDefinition()) {
registerNames.add("arguments");
registerTypes.add("Object");
hasArguments = true;
break;
}
}
int paramRegCount = registerNames.size();
if(needsActivation){
registerNames.add("+$activation");
localData.activationReg = registerNames.size()-1;
registerTypes.add("Object");
}
for (NameAVM2Item n : subvariables) {
if (n.isDefinition()) {
if(!needsActivation || (n.getSlotScope()<=0)){
registerNames.add(n.getVariableName());
registerTypes.add(n.type.toString());
slotNames.add(n.getVariableName());
slotTypes.add(n.type.toString());
}
}
}
int slotScope = 1; //?
for (NameAVM2Item n : subvariables) {
if (n.getVariableName() != null) {
if(needsActivation){
if(n.getSlotNumber() <= 0){
n.setSlotNumber(slotNames.indexOf(n.getVariableName()));
n.setSlotScope(slotScope);
}
}else{
n.setRegNumber(registerNames.indexOf(n.getVariableName()));
}
}
}
for (int i = 0; i < registerNames.size(); i++) {
if(needsActivation && i>localData.activationReg){
break;
}
localData.registerVars.put(registerNames.get(i), i);
}
List<NameAVM2Item> declarations=new ArrayList<>();
loopn:for (NameAVM2Item n : subvariables) {
if(!n.isDefinition()){
continue;
}
if(n.getSlotScope()!=slotScope){
continue;
}
for(NameAVM2Item d:declarations){
if(n.getVariableName()!=null && n.getVariableName().equals(d.getVariableName())){
continue loopn;
}
}
for(GraphTargetItem it:body){ //search first level of commands
if(it instanceof NameAVM2Item){
NameAVM2Item n2=(NameAVM2Item)it;
if(n2.isDefinition() && n2.getAssignedValue()!=null && n2.getVariableName().equals(n.getVariableName())){
continue loopn;
}
if(!n2.isDefinition() && n2.getVariableName()!=null && n2.getVariableName().equals(n.getVariableName())){ //used earlier than defined
break;
}
}
}
NameAVM2Item d=new NameAVM2Item(n.type, n.line, n.getVariableName(), NameAVM2Item.getDefaultValue(""+n.type), true, n.openedNamespaces);
if(needsActivation){
if(d.getSlotNumber() <= 0)
{
d.setSlotNumber(n.getSlotNumber());
d.setSlotScope(n.getSlotScope());
}
}else{
d.setRegNumber(n.getRegNumber());
}
declarations.add(d);
}
int param_types[] = new int[paramTypes.size()];
ValueKind optional[] = new ValueKind[paramValues.size()];
int param_names[] = new int[paramNames.size()];
//int param_names[] = new int[paramNames.size()];
for (int i = 0; i < paramTypes.size(); i++) {
param_types[i] = typeName(localData, paramTypes.get(i));
param_names[i] = str(paramNames.get(i));
//param_names[i] = str(paramNames.get(i));
}
for (int i = 0; i < paramValues.size(); i++) {
optional[i] = getValueKind(Namespace.KIND_NAMESPACE/*FIXME*/, paramTypes.get(paramTypes.size() - paramValues.size() + i), paramTypes.get(i));
}
MethodInfo mi = new MethodInfo(param_types, constructor ? 0 : typeName(localData, retType), 0/*name_index*/, 0, optional, param_names);
MethodInfo mi = new MethodInfo(param_types, constructor ? 0 : typeName(localData, retType), 0/*name_index*/, 0, optional, new int[0]/*no param_names*/);
if (hasArguments) {
mi.setFlagNeed_Arguments();
}
//No param names like in official
/*
if (!paramNames.isEmpty()) {
mi.setFlagHas_paramnames();
}
}*/
if (!paramValues.isEmpty()) {
mi.setFlagHas_optional();
}
@@ -876,10 +1097,47 @@ public class AVM2SourceGenerator implements SourceGenerator {
MethodBody mbody = new MethodBody();
mbody.method_info = abc.addMethodInfo(mi);
mbody.traits = new Traits();
int slotId = 1;
for(int i=1;i<slotNames.size();i++){
TraitSlotConst tsc = new TraitSlotConst();
tsc.slot_id = slotId++;
tsc.name_index = abc.constants.getMultinameId(new Multiname(Multiname.QNAME, abc.constants.getStringId(slotNames.get(i), true), abc.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE_INTERNAL, abc.constants.getStringId(pkg, true)), 0, true), 0,0, new ArrayList<Integer>()), true);
tsc.type_index = typeName(localData, new TypeItem(slotTypes.get(i)));
mbody.traits.traits.add(tsc);
}
if(needsActivation){
for(int i=1;i<paramRegCount;i++){
NameAVM2Item param=new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), null, false, new ArrayList<Integer>());
param.setRegNumber(i);
NameAVM2Item d=new NameAVM2Item(new TypeItem(registerTypes.get(i)), 0, registerNames.get(i), param, true, new ArrayList<Integer>());
d.setSlotScope(slotScope);
d.setSlotNumber(slotNames.indexOf(registerNames.get(i)));
declarations.add(d);
}
}
body.addAll(0,declarations);
localData.exceptions = new ArrayList<>();
List<GraphSourceItem> src = generate(localData, body);
mbody.code = new AVM2Code();
mbody.code.code = toInsList(src);
if(needsActivation){
List<AVM2Instruction> acts=new ArrayList<>();
acts.add(ins(new NewActivationIns()));
acts.add(ins(new DupIns()));
acts.add(AssignableAVM2Item.generateSetLoc(localData.activationReg));
acts.add(ins(new PushScopeIns()));
mbody.code.code.addAll(0,acts);
}
if (constructor) {
List<ABC> abcs = new ArrayList<>();
abcs.add(abc);
@@ -927,6 +1185,26 @@ public class AVM2SourceGenerator implements SourceGenerator {
mbody.code.code.add(new AVM2Instruction(0, new ReturnValueIns(), new int[]{}, new byte[0]));
}
}
mbody.exceptions = localData.exceptions.toArray(new ABCException[localData.exceptions.size()]);
int offset = 0;
for (AVM2Instruction ins : mbody.code.code) {
if(ins instanceof ExceptionMarkAVM2Instruction){
ExceptionMarkAVM2Instruction m=(ExceptionMarkAVM2Instruction)ins;
switch(m.markType){
case MARK_E_START:
mbody.exceptions[m.exceptionId].start = offset;
break;
case MARK_E_END:
mbody.exceptions[m.exceptionId].end = offset;
break;
case MARK_E_TARGET:
mbody.exceptions[m.exceptionId].target = offset;
break;
}
}
offset+=ins.getBytes().length;
}
mbody.autoFillStats(abc, initScope);
abc.addMethodBody(mbody);
@@ -998,14 +1276,10 @@ public class AVM2SourceGenerator implements SourceGenerator {
if (mai.isStatic() != generateStatic) {
continue;
}
Reference<Boolean> hasArgs = new Reference<>(Boolean.FALSE);
calcRegisters(localData, mai, hasArgs);
((TraitMethodGetterSetter) traits[k]).method_info = method(initScope + 1/*class scope*/, mai.hasRest, hasArgs.getVal(), mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType);
((TraitMethodGetterSetter) traits[k]).method_info = method(pkg.packageName,mai.needsActivation,mai.subvariables,initScope + 1/*class scope*/, mai.hasRest,mai.line, className, superName, false, localData, mai.paramTypes, mai.paramNames, mai.paramValues, mai.body, mai.retType);
} else if (item instanceof FunctionAVM2Item) {
FunctionAVM2Item fai = (FunctionAVM2Item) item;
Reference<Boolean> hasArgs = new Reference<>(Boolean.FALSE);
calcRegisters(localData, fai, hasArgs);
((TraitFunction) traits[k]).method_info = method(initScope, fai.hasRest, hasArgs.getVal(), fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType);
((TraitFunction) traits[k]).method_info = method(pkg.packageName,fai.needsActivation,fai.subvariables,initScope, fai.hasRest, fai.line, className, superName, false, localData, fai.paramTypes, fai.paramNames, fai.paramValues, fai.body, fai.retType);
}
}
}
@@ -1318,76 +1592,9 @@ public class AVM2SourceGenerator implements SourceGenerator {
}
}
public void calcRegisters(SourceGeneratorLocalData localData, FunctionAVM2Item fun, Reference<Boolean> hasArguments) throws ParseException {
List<String> registerNames = new ArrayList<>();
registerNames.add("this");
registerNames.addAll(fun.paramNames);
localData.registerVars.clear();
for (NameAVM2Item n : fun.subvariables) {
if (n.getVariableName().equals("arguments") & !n.isDefinition()) {
registerNames.add("arguments");
hasArguments.setVal(Boolean.TRUE);
break;
}
}
for (NameAVM2Item n : fun.subvariables) {
if (n.isDefinition()) {
registerNames.add(n.getVariableName());
}
}
for (NameAVM2Item n : fun.subvariables) {
if (n.unresolved) {
GraphTargetItem resolved = null;
List<ABC> abcs = new ArrayList<>();
abcs.add(abc);
abcs.addAll(allABCs);
for (int i = 0; i < n.openedNamespaces.size(); i++) {
int nsIndex = n.openedNamespaces.get(i);
Namespace ns = abc.constants.constant_namespace.get(nsIndex);
int nsKind = ns.kind;
loopabc:
for (ABC a : abcs) {
for (int h = 0; h < a.instance_info.size(); h++) {
InstanceInfo ii = a.instance_info.get(h);
Multiname nm = a.constants.constant_multiname.get(ii.name_index);
if (nm.getNamespace(a.constants).getName(a.constants).equals(ns.getName(abc.constants)) && nm.getNamespace(a.constants).kind == nsKind) {
//found opened class
Reference<String> outName = new Reference<>("");
Reference<String> outNs = new Reference<>("");
Reference<String> outPropNs = new Reference<>("");
Reference<Integer> outPropNsKind = new Reference<>(1);
Reference<String> outPropType = new Reference<>("");
if (AVM2SourceGenerator.searchPrototypeChain(false, abcs, nm.getNamespace(a.constants).getName(a.constants), nm.getName(a.constants, new ArrayList<String>()), n.getVariableName(), outName, outNs, outPropNs, outPropNsKind, outPropType)) {
resolved = new PropertyAVM2Item(null, n.getVariableName(), n.getIndex(), abc, allABCs, n.openedNamespaces);
}
}
}
}
}
n.redirect = resolved;
if (resolved == null) {
throw new ParseException("Unknown variable or property:" + n.getVariableName(), n.line);
}
}
if (n.getVariableName() != null) {
n.setRegNumber(registerNames.indexOf(n.getVariableName()));
}
}
for (int i = 0; i < registerNames.size(); i++) {
localData.registerVars.put(registerNames.get(i), i);
}
List<NameAVM2Item> declarations=new ArrayList<>();
for (NameAVM2Item n : fun.subvariables) {
if(n.isDefinition() && n.getAssignedValue() == null){
NameAVM2Item d=new NameAVM2Item(n.type, n.line, n.getVariableName(), NameAVM2Item.getDefaultValue(""+n.type), true, n.openedNamespaces);
d.setRegNumber(n.getRegNumber());
declarations.add(d);
}
}
fun.body.addAll(0,declarations);
}
/* public void calcRegisters(Reference<Integer> activationReg, SourceGeneratorLocalData localData, boolean needsActivation, List<String> funParamNames,List<NameAVM2Item> funSubVariables,List<GraphTargetItem> funBody, Reference<Boolean> hasArguments) throws ParseException {
}*/
public int resolveType(String objType) {
if (objType.equals("*")) {
@@ -42,6 +42,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.ThrowAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForInAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.TryAVM2Item;
@@ -128,13 +129,13 @@ public class ActionScriptParser {
return uniqLast;
}
private List<GraphTargetItem> commands(List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forinlevel, List<NameAVM2Item> variables) throws IOException, ParseException {
private List<GraphTargetItem> commands(Reference<Boolean> needsActivation, List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forinlevel, List<NameAVM2Item> variables) throws IOException, ParseException {
List<GraphTargetItem> ret = new ArrayList<>();
if (debugMode) {
System.out.println("commands:");
}
GraphTargetItem cmd = null;
while ((cmd = command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables)) != null) {
while ((cmd = command(needsActivation,importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables)) != null) {
ret.add(cmd);
}
if (debugMode) {
@@ -400,7 +401,7 @@ public class ActionScriptParser {
private MethodAVM2Item method(List<String> importedClasses, boolean override, boolean isFinal, GraphTargetItem thisType, List<Integer> openedNamespaces, boolean isStatic, int namespace, boolean withBody, String functionName, boolean isMethod, List<NameAVM2Item> variables) throws IOException, ParseException {
FunctionAVM2Item f = function(importedClasses, namespace, thisType, openedNamespaces, withBody, functionName, isMethod, variables);
return new MethodAVM2Item(f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType);
return new MethodAVM2Item(f.needsActivation,f.hasRest, f.line, override, isFinal, isStatic, f.namespace, functionName, f.paramTypes, f.paramNames, f.paramValues, f.body, f.subvariables, f.retType);
}
private FunctionAVM2Item function(List<String> importedClasses, int namespace, GraphTargetItem thisType, List<Integer> openedNamespaces, boolean withBody, String functionName, boolean isMethod, List<NameAVM2Item> variables) throws IOException, ParseException {
@@ -464,17 +465,17 @@ public class ActionScriptParser {
}
subvariables.add(new NameAVM2Item(thisType, lexer.yyline(), "arguments", null, true, openedNamespaces));
int parCnt = subvariables.size();
Reference<Boolean> needsActivation = new Reference<>(false);
if (withBody) {
expectedType(SymbolType.CURLY_OPEN);
body = commands(importedClasses, openedNamespaces, new Stack<Loop>(), new HashMap<Loop, String>(), new HashMap<String, Integer>(), true, isMethod, 0, subvariables);
expectedType(SymbolType.CURLY_OPEN);
body = commands(needsActivation, importedClasses, openedNamespaces, new Stack<Loop>(), new HashMap<Loop, String>(), new HashMap<String, Integer>(), true, isMethod, 0, subvariables);
expectedType(SymbolType.CURLY_CLOSE);
}
for (int i = 0; i < parCnt; i++) {
subvariables.remove(0);
}
return new FunctionAVM2Item(namespace, hasRest, line, functionName, paramTypes, paramNames, paramValues, body, subvariables, retType);
return new FunctionAVM2Item(needsActivation.getVal(), namespace, hasRest, line, functionName, paramTypes, paramNames, paramValues, body, subvariables, retType);
}
private GraphTargetItem traits(List<String> importedClasses, int privateNs, int protectedNs, int publicNs, int packageInternalNs, int protectedStaticNs, List<Integer> openedNamespaces, String packageName, String classNameStr, boolean isInterface, List<GraphTargetItem> traits) throws ParseException, IOException {
@@ -662,13 +663,13 @@ public class ActionScriptParser {
if (!ft.paramTypes.isEmpty()) {
throw new ParseException("Getter can't have any parameters", lexer.yyline());
}
GetterAVM2Item g = new GetterAVM2Item(ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
GetterAVM2Item g = new GetterAVM2Item(ft.needsActivation,ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = g;
} else if (isSetter) {
if (ft.paramTypes.size() != 1) {
throw new ParseException("Getter must have exactly one parameter", lexer.yyline());
}
SetterAVM2Item st = new SetterAVM2Item(ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
SetterAVM2Item st = new SetterAVM2Item(ft.needsActivation,ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = st;
} else {
t = ft;
@@ -831,7 +832,7 @@ public class ActionScriptParser {
//return ret;
}
private GraphTargetItem command(List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forinlevel, boolean mustBeCommand, List<NameAVM2Item> variables) throws IOException, ParseException {
private GraphTargetItem command(Reference<Boolean> needsActivation, List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forinlevel, boolean mustBeCommand, List<NameAVM2Item> variables) throws IOException, ParseException {
LexBufferer buf = new LexBufferer();
lexer.addListener(buf);
GraphTargetItem ret = null;
@@ -868,7 +869,7 @@ public class ActionScriptParser {
}
expectedType(SymbolType.PARENT_CLOSE);
expectedType(SymbolType.CURLY_OPEN);
List<GraphTargetItem> wcmd = commands(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
List<GraphTargetItem> wcmd = commands(needsActivation,importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
expectedType(SymbolType.CURLY_CLOSE);
ret = new WithAVM2Item(null, wvar, wcmd);
break;
@@ -916,7 +917,7 @@ public class ActionScriptParser {
}
break;
case CURLY_OPEN:
ret = new BlockItem(null, commands(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
ret = new BlockItem(null, commands(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
expectedType(SymbolType.CURLY_CLOSE);
break;
/*case INCREMENT: //preincrement
@@ -945,14 +946,14 @@ public class ActionScriptParser {
expectedType(SymbolType.PARENT_OPEN);
GraphTargetItem ifExpr = (expression(importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables));
expectedType(SymbolType.PARENT_CLOSE);
GraphTargetItem onTrue = command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables);
GraphTargetItem onTrue = command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables);
List<GraphTargetItem> onTrueList = new ArrayList<>();
onTrueList.add(onTrue);
s = lex();
List<GraphTargetItem> onFalseList = null;
if (s.type == SymbolType.ELSE) {
onFalseList = new ArrayList<>();
onFalseList.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
onFalseList.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
} else {
lexer.pushback(s);
}
@@ -961,7 +962,7 @@ public class ActionScriptParser {
case WHILE:
expectedType(SymbolType.PARENT_OPEN);
List<GraphTargetItem> whileExpr = new ArrayList<>();
whileExpr.add(commaExpression(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
whileExpr.add(commaExpression(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
expectedType(SymbolType.PARENT_CLOSE);
List<GraphTargetItem> whileBody = new ArrayList<>();
Loop wloop = new Loop(uniqId(), null, null);
@@ -969,7 +970,7 @@ public class ActionScriptParser {
loopLabels.put(wloop, loopLabel);
}
loops.push(wloop);
whileBody.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
whileBody.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
ret = new WhileItem(null, wloop, whileExpr, whileBody);
break;
case DO:
@@ -979,11 +980,11 @@ public class ActionScriptParser {
if (loopLabel != null) {
loopLabels.put(dloop, loopLabel);
}
doBody.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
doBody.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
expectedType(SymbolType.WHILE);
expectedType(SymbolType.PARENT_OPEN);
List<GraphTargetItem> doExpr = new ArrayList<>();
doExpr.add(commaExpression(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
doExpr.add(commaExpression(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables));
expectedType(SymbolType.PARENT_CLOSE);
ret = new DoWhileItem(null, dloop, doBody, doExpr);
break;
@@ -998,7 +999,7 @@ public class ActionScriptParser {
s = lex();
}
expected(s, lexer.yyline(), SymbolType.PARENT_OPEN);
GraphTargetItem firstCommand=command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, false, variables);
GraphTargetItem firstCommand=command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, false, variables);
if(firstCommand instanceof NameAVM2Item){
NameAVM2Item nai=(NameAVM2Item)firstCommand;
if(nai.isDefinition() && nai.getAssignedValue() == null){
@@ -1024,17 +1025,17 @@ public class ActionScriptParser {
GraphTargetItem forExpr = null;
List<GraphTargetItem> forFirstCommands = new ArrayList<>();
if (!forin) {
//GraphTargetItem firstCommand = command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables);
//GraphTargetItem firstCommand = command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables);
if (firstCommand != null) { //can be empty command
forFirstCommands.add(firstCommand);
}
forExpr = (expression(importedClasses, openedNamespaces, registerVars, inFunction, inMethod, true, variables));
expectedType(SymbolType.SEMICOLON);
forFinalCommands.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
forFinalCommands.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
}
expectedType(SymbolType.PARENT_CLOSE);
List<GraphTargetItem> forBody = new ArrayList<>();
forBody.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forin ? forinlevel + 1 : forinlevel, true, variables));
forBody.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forin ? forinlevel + 1 : forinlevel, true, variables));
if (forin) {
if (each) {
ret = new ForEachInAVM2Item(null, floop, inexpr, forBody);
@@ -1083,14 +1084,14 @@ public class ActionScriptParser {
}
pos++;
lexer.pushback(s);
List<GraphTargetItem> caseCmd = commands(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
List<GraphTargetItem> caseCmd = commands(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
caseCmds.add(caseCmd);
s = lex();
}
List<GraphTargetItem> defCmd = new ArrayList<>();
if (s.type == SymbolType.DEFAULT) {
expectedType(SymbolType.COLON);
defCmd = commands(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
defCmd = commands(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, variables);
s = lexer.lex();
}
expected(s, lexer.yyline(), SymbolType.CURLY_CLOSE);
@@ -1163,13 +1164,15 @@ public class ActionScriptParser {
}
break;
case TRY:
needsActivation.setVal(true);
List<GraphTargetItem> tryCommands = new ArrayList<>();
tryCommands.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
tryCommands.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
s = lex();
boolean found = false;
List<List<GraphTargetItem>> catchCommands = null;
List<List<GraphTargetItem>> catchCommands = new ArrayList<>();
List<NameAVM2Item> catchExceptions = new ArrayList<>();
if (s.type == SymbolType.CATCH) {
int varCnt = variables.size();
while (s.type == SymbolType.CATCH) {
expectedType(SymbolType.PARENT_OPEN);
s = lex();
expected(s, lexer.yyline(), SymbolType.IDENTIFIER, SymbolType.THIS, SymbolType.SUPER, SymbolType.STRING_OP);
@@ -1177,20 +1180,31 @@ public class ActionScriptParser {
String enamestr = s.value.toString();
expectedType(SymbolType.COLON);
GraphTargetItem etype = type(importedClasses, openedNamespaces, variables);
NameAVM2Item e = new NameAVM2Item(etype, lexer.yyline(), enamestr, null, false/*?*/, openedNamespaces);
NameAVM2Item e = new NameAVM2Item(etype, lexer.yyline(), enamestr, new ExceptionAVM2Item(null)/*?*/, true/*?*/, openedNamespaces);
variables.add(e);
catchExceptions.add(e);
expectedType(SymbolType.PARENT_CLOSE);
catchCommands = new ArrayList<>();
e.setSlotNumber(1);
e.setSlotScope(2); //?
expectedType(SymbolType.PARENT_CLOSE);
List<GraphTargetItem> cc = new ArrayList<>();
cc.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
cc.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
catchCommands.add(cc);
s = lex();
found = true;
}
for(int i=varCnt;i<variables.size();i++){
for(NameAVM2Item e:catchExceptions){
if(variables.get(i).getVariableName().equals(e.getVariableName())){
variables.get(i).setSlotNumber(e.getSlotNumber());
variables.get(i).setSlotScope(e.getSlotScope());
}
}
}
List<GraphTargetItem> finallyCommands = null;
if (s.type == SymbolType.FINALLY) {
finallyCommands = new ArrayList<>();
finallyCommands.add(command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
finallyCommands.add(command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forinlevel, true, variables));
found = true;
s = lex();
}
@@ -1513,12 +1527,12 @@ public class ActionScriptParser {
return arrCnt;
}
private GraphTargetItem commaExpression(List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forInLevel, List<NameAVM2Item> variables) throws IOException, ParseException {
private GraphTargetItem commaExpression(Reference<Boolean> needsActivation,List<String> importedClasses, List<Integer> openedNamespaces, Stack<Loop> loops, Map<Loop, String> loopLabels, HashMap<String, Integer> registerVars, boolean inFunction, boolean inMethod, int forInLevel, List<NameAVM2Item> variables) throws IOException, ParseException {
GraphTargetItem cmd = null;
List<GraphTargetItem> expr = new ArrayList<>();
ParsedSymbol s;
do {
cmd = command(importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forInLevel, false, variables);
cmd = command(needsActivation, importedClasses, openedNamespaces, loops, loopLabels, registerVars, inFunction, inMethod, forInLevel, false, variables);
if (cmd != null) {
expr.add(cmd);
}
@@ -29,6 +29,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal1Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal2Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocal3Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetScopeObjectIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetSlotIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSlotIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -113,6 +116,8 @@ public abstract class AssignableAVM2Item extends AVM2Item {
public static AVM2Instruction generateSetLoc(int regNumber) {
switch (regNumber) {
case -1:
return null;
case 0:
return ins(new SetLocal0Ins());
case 1:
@@ -128,6 +133,8 @@ public abstract class AssignableAVM2Item extends AVM2Item {
public static AVM2Instruction generateGetLoc(int regNumber) {
switch (regNumber) {
case -1:
return null;
case 0:
return ins(new GetLocal0Ins());
case 1:
@@ -140,5 +147,25 @@ public abstract class AssignableAVM2Item extends AVM2Item {
return ins(new GetLocalIns(), regNumber);
}
}
public static List<GraphSourceItem> generateGetSlot(int slotScope,int slotNumber){
if(slotNumber==-1){
return null;
}
List<GraphSourceItem> ret = new ArrayList<>();
ret.add(ins(new GetScopeObjectIns(),slotScope));
ret.add(ins(new GetSlotIns(),slotNumber));
return ret;
}
public static List<GraphSourceItem> generateSetSlot(SourceGeneratorLocalData localData,SourceGenerator generator, GraphTargetItem val,int slotScope,int slotNumber){
if(slotNumber==-1){
return null;
}
List<GraphSourceItem> ret = new ArrayList<>();
ret.add(ins(new GetScopeObjectIns(),slotScope));
ret.addAll(val.toSource(localData, generator));
ret.add(ins(new SetSlotIns(),slotNumber));
return ret;
}
}
@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition;
/**
*
@@ -31,6 +32,7 @@ public class ExceptionMarkAVM2Instruction extends AVM2Instruction {
super(0, null, new int[0], new byte[0]);
this.markType = markType;
this.exceptionId = exceptionId;
this.definition = new InstructionDefinition(0, "--mark", new int[0]);
}
@Override
@@ -39,9 +39,11 @@ public class FunctionAVM2Item extends AVM2Item {
public GraphTargetItem retType;
public int line;
public boolean hasRest;
public boolean needsActivation;
public FunctionAVM2Item(int namespace, boolean hasRest, int line, String functionName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
public FunctionAVM2Item(boolean needsActivation, int namespace, boolean hasRest, int line, String functionName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(null, NOPRECEDENCE);
this.needsActivation = needsActivation;
this.namespace = namespace;
this.paramNames = paramNames;
this.body = body;
@@ -25,8 +25,8 @@ import java.util.List;
*/
public class GetterAVM2Item extends MethodAVM2Item {
public GetterAVM2Item(boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
public GetterAVM2Item(boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(needsActivation,hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
}
}
@@ -31,8 +31,8 @@ public class MethodAVM2Item extends FunctionAVM2Item {
private boolean isFinal;
private boolean override;
public MethodAVM2Item(boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(namespace, hasRest, line, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
public MethodAVM2Item(boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(needsActivation,namespace, hasRest, line, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
this.isStatic = isStatic;
this.override = override;
this.isFinal = isFinal;
@@ -27,7 +27,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.IncLocalIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetScopeObjectIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetPropertyIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.SetSlotIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
@@ -36,6 +38,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceSIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertDIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertSIns;
import static com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item.ins;
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NanAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item;
@@ -69,6 +72,8 @@ public class NameAVM2Item extends AssignableAVM2Item {
private GraphTargetItem ns = null;
private int regNumber = -1;
public boolean unresolved = false;
private int slotNumber = -1;
private int slotScope = 0;
public GraphTargetItem redirect;
@@ -82,6 +87,17 @@ public class NameAVM2Item extends AssignableAVM2Item {
c.setIndex(index);
return c;
}
public void setSlotScope(int slotScope) {
this.slotScope = slotScope;
}
public int getSlotScope() {
return slotScope;
}
@@ -93,6 +109,14 @@ public class NameAVM2Item extends AssignableAVM2Item {
this.regNumber = regNumber;
}
public int getSlotNumber() {
return slotNumber;
}
public void setSlotNumber(int slotNumber) {
this.slotNumber = slotNumber;
}
public int getRegNumber() {
return regNumber;
}
@@ -199,8 +223,8 @@ public class NameAVM2Item extends AssignableAVM2Item {
}
private List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator, boolean needsReturn) {
if (variableName != null && regNumber == -1 && ns == null) {
throw new RuntimeException("No register set for " + variableName);
if (variableName != null && regNumber == -1 && slotNumber == -1 && ns == null) {
throw new RuntimeException("No register or slot set for " + variableName);
}
if (definition && assignedValue == null) {
return new ArrayList<GraphSourceItem>();
@@ -252,7 +276,7 @@ public class NameAVM2Item extends AssignableAVM2Item {
if (index != null) {
if (assignedValue != null) {
return toSourceMerge(localData, generator,
generateGetLoc(regNumber), index, assignedValue,
generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), index, assignedValue,
needsReturn ? dupSetTemp(localData, generator, ret_temp) : null,
ins(new SetPropertyIns(), g.abc.constants.getMultinameId(new Multiname(Multiname.MULTINAMEL, 0, 0, allNsSet(g.abc), 0, new ArrayList<Integer>()), true)),
needsReturn ? getTemp(localData, generator, ret_temp) : null,
@@ -269,10 +293,24 @@ public class NameAVM2Item extends AssignableAVM2Item {
if (assignedValue != null) {
List<String> basicTypes = Arrays.asList("int","Number");
if(slotNumber>-1)
{
return toSourceMerge(localData, generator,
ins(new GetScopeObjectIns(),slotScope),
assignedValue, !((""+assignedValue.returnType()).equals(""+type)&&(basicTypes.contains(""+type))) ? generateCoerce(generator, "" + type) : null, needsReturn
? dupSetTemp(localData, generator, ret_temp) : null, generateSetLoc(regNumber),slotNumber>-1?
ins(new SetSlotIns(),slotNumber)
:null,
needsReturn?getTemp(localData, generator, ret_temp):null,
killTemp(localData, generator, Arrays.asList(ret_temp)));
}
else{
return toSourceMerge(localData, generator, assignedValue, !((""+assignedValue.returnType()).equals(""+type)&&(basicTypes.contains(""+type))) ? generateCoerce(generator, "" + type) : null, needsReturn
? ins(new DupIns()) : null, generateSetLoc(regNumber));
}
} else {
return toSourceMerge(localData, generator, generateGetLoc(regNumber),
return toSourceMerge(localData, generator, generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber),
needsReturn ? null : ins(new PopIns()));
}
}
@@ -393,7 +431,7 @@ public class NameAVM2Item extends AssignableAVM2Item {
if (index != null) {
return toSourceMerge(localData, generator,
generateGetLoc(regNumber), dupSetTemp(localData, generator, name_temp), index, dupSetTemp(localData, generator, index_temp),
generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber), dupSetTemp(localData, generator, name_temp), index, dupSetTemp(localData, generator, index_temp),
//Start get original
//generateGetLoc(regNumber), getTemp(localData, generator, index_temp),
ins(new GetPropertyIns(), g.abc.constants.getMultinameId(new Multiname(Multiname.MULTINAMEL, 0, 0, allNsSet(g.abc), 0, new ArrayList<Integer>()), true)),
@@ -412,19 +450,31 @@ public class NameAVM2Item extends AssignableAVM2Item {
}
if(!needsReturn){
return toSourceMerge(localData, generator,
ins(isInteger?new IncLocalIIns():new IncLocalIns(),regNumber));
if(slotNumber>-1){
return toSourceMerge(localData, generator,
ins(new GetScopeObjectIns(),slotScope),
generateGetSlot(slotScope,slotNumber),
(decrement ? ins(isInteger ? new DecrementIIns() : new DecrementIns()) : ins(isInteger ? new IncrementIIns() : new IncrementIns())),
ins(new SetSlotIns(),slotNumber)
);
}else{
return toSourceMerge(localData, generator,
ins(isInteger?new IncLocalIIns():new IncLocalIns(),regNumber));
}
}
return toSourceMerge(localData, generator,
slotNumber>-1?ins(new GetScopeObjectIns(),slotScope):null,
//Start get original
generateGetLoc(regNumber),
generateGetLoc(regNumber),generateGetSlot(slotScope,slotNumber),
//End get original
!isInteger ? ins(new ConvertDIns()) : null,
//End get original
(!post) ? (decrement ? ins(isInteger ? new DecrementIIns() : new DecrementIns()) : ins(isInteger ? new IncrementIIns() : new IncrementIns())) : null,
needsReturn ? ins(new DupIns()) : null,
(post) ? (decrement ? ins(isInteger ? new DecrementIIns() : new DecrementIns()) : ins(isInteger ? new IncrementIIns() : new IncrementIns())) : null,
generateSetLoc(regNumber));
generateSetLoc(regNumber),
slotNumber>-1?ins(new SetSlotIns(),slotNumber):null
);
}
}
@@ -25,8 +25,8 @@ import java.util.List;
*/
public class SetterAVM2Item extends MethodAVM2Item {
public SetterAVM2Item(boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
public SetterAVM2Item(boolean needsActivation, boolean hasRest, int line, boolean override, boolean isFinal, boolean isStatic, int namespace, String methodName, List<GraphTargetItem> paramTypes, List<String> paramNames, List<GraphTargetItem> paramValues, List<GraphTargetItem> body, List<NameAVM2Item> subvariables, GraphTargetItem retType) {
super(needsActivation,hasRest, line, override, isFinal, isStatic, namespace, methodName, paramTypes, paramNames, paramValues, body, subvariables, retType);
}
}
@@ -1,11 +1,10 @@
TODO List for AS3 parser/compiler:
------------------------------
- exceptions (try/catch)
- finally clause
- E4X (XML)
- typenames (Vectors)
- inner functions (activation, slots, etc.)
- with
- with (+ in catch clause)
- delete property
- default xml namespace
- custom namespace modifiers
@@ -224,8 +224,11 @@ public class MethodBody implements Cloneable, Serializable {
if (stats == null) {
return false;
}
if(stats.has_activation){
initScope++;
}
max_stack = stats.maxstack;
max_scope_depth = init_scope_depth + stats.maxscope;
max_scope_depth = stats.maxscope+(stats.has_activation?1:0);
max_regs = stats.maxlocal;
init_scope_depth = initScope;
abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns);