From db9cd78e2cafcf5f873aca58f023b195eb206a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 7 Mar 2026 19:02:24 +0100 Subject: [PATCH] fix: direct edit properties with getters/setters (#2655) Fixes #2655 --- .../as2/ActionScript2ClassDetector.java | 8 +- .../action/model/CallMethodActionItem.java | 83 ++---- .../flash/action/model/DeleteActionItem.java | 25 ++ .../action/model/GetMemberActionItem.java | 14 + .../action/model/NewMethodActionItem.java | 26 ++ .../action/model/PostDecrementActionItem.java | 29 +- .../action/model/PostIncrementActionItem.java | 29 +- .../action/model/SetMemberActionItem.java | 17 ++ .../operations/PreDecrementActionItem.java | 53 +++- .../operations/PreIncrementActionItem.java | 52 +++- .../parser/script/ActionScript2Parser.java | 256 +++++++++++++++++- .../flash/action/swf5/ActionCallMethod.java | 23 ++ .../flash/action/swf5/ActionSetMember.java | 178 +++++++----- 13 files changed, 626 insertions(+), 167 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java index 22be7266c..f0ff99598 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/as2/ActionScript2ClassDetector.java @@ -712,11 +712,9 @@ public class ActionScript2ClassDetector { } if (pos >= 0 && func.actions.get(pos) instanceof ReturnActionItem) { GraphTargetItem val = func.actions.get(pos); - if (val.value instanceof CallMethodActionItem) { - if (((CallMethodActionItem) val.value).methodName instanceof DirectValueActionItem) { - if (((CallMethodActionItem) val.value).methodName.toString().startsWith("__get__")) { - func.actions.remove(pos); - } + if (val.value instanceof GetMemberActionItem) { + if (((GetMemberActionItem) val.value).isGetter) { + func.actions.remove(pos); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/CallMethodActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/CallMethodActionItem.java index 9ccb4f1c7..aeb4fe3bf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/CallMethodActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/CallMethodActionItem.java @@ -18,6 +18,8 @@ package com.jpexs.decompiler.flash.action.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.ecma.Undefined; @@ -52,26 +54,12 @@ public class CallMethodActionItem extends ActionItem { /** * Arguments */ - public List arguments; + public List arguments; /** - * Special - getter + * Is getter */ - public static int SPECIAL_GETTER = 1; - /** - * Special - setter - */ - public static int SPECIAL_SETTER = 2; - - /** - * Special - */ - private int special = 0; - - /** - * Setter/getter variable name - */ - private String setterGetterVarName = null; + public boolean isGetter = false; @Override public void visit(GraphTargetVisitorInterface visitor) { @@ -92,51 +80,11 @@ public class CallMethodActionItem extends ActionItem { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); this.methodName = methodName; this.arguments = arguments; - this.scriptObject = scriptObject; - - if (methodName instanceof DirectValueActionItem) { - DirectValueActionItem dv = (DirectValueActionItem) methodName; - if (dv.isString()) { - String methodNameStr = dv.getAsString(); - if (methodNameStr.startsWith("__get__") && arguments.isEmpty()) { - special = SPECIAL_GETTER; - setterGetterVarName = methodNameStr.substring(7); - } else if (methodNameStr.startsWith("__set__") && arguments.size() == 1) { - special = SPECIAL_SETTER; - setterGetterVarName = methodNameStr.substring(7); - precedence = PRECEDENCE_ASSIGNMENT; - } - } - } + this.scriptObject = scriptObject; } @Override - public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - if (special == SPECIAL_GETTER) { - if (scriptObject.getPrecedence() > this.precedence) { - writer.append("("); - scriptObject.toString(writer, localData); - writer.append(")"); - } else { - scriptObject.toString(writer, localData); - } - writer.allowWrapHere().append("."); - writer.append(setterGetterVarName); - return writer; - } else if (special == SPECIAL_SETTER) { - if (scriptObject.getPrecedence() > this.precedence) { - writer.append("("); - scriptObject.toString(writer, localData); - writer.append(")"); - } else { - scriptObject.toString(writer, localData); - } - writer.allowWrapHere().append("."); - writer.append(setterGetterVarName); - writer.append(" = "); - arguments.get(0).toStringNL(writer, localData); - return writer; - } + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { if (methodName instanceof DirectValueActionItem) { boolean blankMethod = false; @@ -210,6 +158,23 @@ public class CallMethodActionItem extends ActionItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + if (isGetter) { + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; + String charset = asGenerator.getCharset(); + + String methodNameAsStr = ((DirectValueActionItem) methodName).getAsString(); + + return toSourceMerge( + localData, generator, + toSourceCall(localData, generator, arguments), + new ActionPush((Long) (long) 0, charset), + scriptObject, + asGenerator.pushConst("__get__" + methodNameAsStr), + new ActionCallMethod(), + new ActionPush(Undefined.INSTANCE, charset), + new ActionCallMethod() + ); + } return toSourceMerge(localData, generator, toSourceCall(localData, generator, arguments), scriptObject, methodName, new ActionCallMethod()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DeleteActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DeleteActionItem.java index edb7bcd6e..a40d5287d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DeleteActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DeleteActionItem.java @@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionDelete; import com.jpexs.decompiler.flash.action.swf5.ActionDelete2; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -48,6 +51,11 @@ public class DeleteActionItem extends ActionItem { */ public GraphTargetItem propertyName; + /** + * Is getter + */ + public boolean isGetter = false; + @Override public void visit(GraphTargetVisitorInterface visitor) { visitor.visit(object); @@ -108,6 +116,23 @@ public class DeleteActionItem extends ActionItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + + if (isGetter) { + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; + String charset = asGenerator.getCharset(); + + String propertyNameAsStr = ((DirectValueActionItem) propertyName).getAsString(); + + return toSourceMerge( + localData, generator, + new ActionPush((Long) (long) 0, charset), + object, + asGenerator.pushConst("__get__" + propertyNameAsStr), + new ActionCallMethod(), + new ActionDelete2() + ); + } + if (object == null) { return toSourceMerge(localData, generator, propertyName, new ActionDelete2()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/GetMemberActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/GetMemberActionItem.java index e2d0ebedb..a3f981a76 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/GetMemberActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/GetMemberActionItem.java @@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionGetMember; import com.jpexs.decompiler.flash.helpers.CodeFormatting; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -54,6 +57,11 @@ public class GetMemberActionItem extends ActionItem { */ public boolean printObfuscatedMemberName = false; + /** + * Is getter + */ + public boolean isGetter = false; + @Override public void visit(GraphTargetVisitorInterface visitor) { visitor.visit(object); @@ -148,6 +156,12 @@ public class GetMemberActionItem extends ActionItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; + String charset = asGenerator.getCharset(); + if (isGetter) { + String memberNameAsStr = ((DirectValueActionItem) memberName).getAsString(); + return toSourceMerge(localData, generator, new ActionPush((Long) (long) 0, charset), object, asGenerator.pushConst("__get__" + memberNameAsStr), new ActionCallMethod()); + } return toSourceMerge(localData, generator, object, memberName, new ActionGetMember()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/NewMethodActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/NewMethodActionItem.java index c8bcb4d29..c3c7d1788 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/NewMethodActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/NewMethodActionItem.java @@ -18,6 +18,9 @@ package com.jpexs.decompiler.flash.action.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; +import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -52,6 +55,11 @@ public class NewMethodActionItem extends ActionItem { * Arguments */ public List arguments; + + /** + * Is getter + */ + public boolean isGetter; @Override public void visit(GraphTargetVisitorInterface visitor) { @@ -132,6 +140,24 @@ public class NewMethodActionItem extends ActionItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + if (isGetter) { + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; + String charset = asGenerator.getCharset(); + + String methodNameAsStr = ((DirectValueActionItem) methodName).getAsString(); + + return toSourceMerge( + localData, generator, + toSourceCall(localData, generator, arguments), + new ActionPush((Long) (long) 0, charset), + scriptObject, + asGenerator.pushConst("__get__" + methodNameAsStr), + new ActionCallMethod(), + new ActionPush(Undefined.INSTANCE, charset), + new ActionNewMethod() + ); + } + return toSourceMerge(localData, generator, toSourceCall(localData, generator, arguments), scriptObject, methodName, new ActionNewMethod()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostDecrementActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostDecrementActionItem.java index f55306535..9ea54cb66 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostDecrementActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostDecrementActionItem.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty; import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionDecrement; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; @@ -115,7 +116,8 @@ public class PostDecrementActionItem extends ActionItem implements SetTypeAction } @Override - public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; String charset = asGenerator.getCharset(); @@ -133,13 +135,26 @@ public class PostDecrementActionItem extends ActionItem implements SetTypeAction ret.addAll(gv.toSource(localData, generator)); ret.add(new ActionDecrement()); ret.add(new ActionSetVariable()); - } else if (val instanceof GetMemberActionItem) { + } else if (val instanceof GetMemberActionItem) { GetMemberActionItem mem = (GetMemberActionItem) val; - ret.addAll(mem.toSource(localData, generator)); - ret.remove(ret.size() - 1); //ActionGetMember - ret.addAll(mem.toSource(localData, generator)); - ret.add(new ActionDecrement()); - ret.add(new ActionSetMember()); + if (mem.isGetter) { + String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString(); + ret.addAll(toSourceMerge(localData, generator, + mem, + new ActionDecrement(), + new ActionPush((Long) (long) 1, charset), + mem.object, + asGenerator.pushConst("__set__" + memberNameAsStr), + new ActionCallMethod(), + new ActionPop() + )); + } else { + ret.addAll(mem.toSource(localData, generator)); + ret.remove(ret.size() - 1); //ActionGetMember + ret.addAll(mem.toSource(localData, generator)); + ret.add(new ActionDecrement()); + ret.add(new ActionSetMember()); + } } else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) { RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value; ret.add(new ActionPush(new RegisterNumber(rn.number), charset)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostIncrementActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostIncrementActionItem.java index fa5166fd0..b0f7e007c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostIncrementActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/PostIncrementActionItem.java @@ -25,7 +25,9 @@ import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty; import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionIncrement; +import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -116,7 +118,7 @@ public class PostIncrementActionItem extends ActionItem implements SetTypeAction @Override public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { - + ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; String charset = asGenerator.getCharset(); @@ -134,13 +136,26 @@ public class PostIncrementActionItem extends ActionItem implements SetTypeAction ret.addAll(gv.toSource(localData, generator)); ret.add(new ActionIncrement()); ret.add(new ActionSetVariable()); - } else if (val instanceof GetMemberActionItem) { + } else if (val instanceof GetMemberActionItem) { GetMemberActionItem mem = (GetMemberActionItem) val; - ret.addAll(mem.toSource(localData, generator)); - ret.remove(ret.size() - 1); //ActionGetMember - ret.addAll(mem.toSource(localData, generator)); - ret.add(new ActionIncrement()); - ret.add(new ActionSetMember()); + if (mem.isGetter) { + String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString(); + ret.addAll(toSourceMerge(localData, generator, + mem, + new ActionIncrement(), + new ActionPush((Long) (long) 1, charset), + mem.object, + asGenerator.pushConst("__set__" + memberNameAsStr), + new ActionCallMethod(), + new ActionPop() + )); + } else { + ret.addAll(mem.toSource(localData, generator)); + ret.remove(ret.size() - 1); //ActionGetMember + ret.addAll(mem.toSource(localData, generator)); + ret.add(new ActionIncrement()); + ret.add(new ActionSetMember()); + } } else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) { RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value; ret.add(new ActionPush(new RegisterNumber(rn.number), charset)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/SetMemberActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/SetMemberActionItem.java index a5012492d..090ce8baa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/SetMemberActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/SetMemberActionItem.java @@ -19,8 +19,10 @@ package com.jpexs.decompiler.flash.action.model; import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SourceGeneratorLocalData; import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; +import com.jpexs.decompiler.flash.action.swf4.ActionPop; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -66,6 +68,11 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem * Compound operator */ public String compoundOperator; + + /** + * Is setter + */ + public boolean isSetter = false; @Override public void visit(GraphTargetVisitorInterface visitor) { @@ -166,6 +173,12 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; String charset = asGenerator.getCharset(); + + if (isSetter) { + String objectNameAsStr = ((DirectValueActionItem) objectName).getAsString(); + return toSourceMerge(localData, generator, value, new ActionPush((Long) (long) 1, charset), object, asGenerator.pushConst("__set__" + objectNameAsStr), new ActionCallMethod()); + } + int tmpReg = asGenerator.getTempRegister(localData); try { return toSourceMerge(localData, generator, object, objectName, value, new ActionStoreRegister(tmpReg, charset), new ActionSetMember(), new ActionPush(new RegisterNumber(tmpReg), charset)); @@ -176,6 +189,10 @@ public class SetMemberActionItem extends ActionItem implements SetTypeActionItem @Override public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + if (isSetter) { + return toSourceMerge(localData, generator, toSource(localData, generator), new ActionPop()); + } + return toSourceMerge(localData, generator, object, objectName, value, new ActionSetMember()); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreDecrementActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreDecrementActionItem.java index ba6ec879e..8a94b936d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreDecrementActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreDecrementActionItem.java @@ -24,10 +24,12 @@ import com.jpexs.decompiler.flash.action.model.GetPropertyActionItem; import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem; +import com.jpexs.decompiler.flash.action.swf4.ActionPop; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty; import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionDecrement; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; @@ -63,6 +65,15 @@ public class PreDecrementActionItem extends UnaryOpItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return toSourceBoth(localData, generator, true); + } + + @Override + public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return toSourceBoth(localData, generator, false); + } + + private List toSourceBoth(SourceGeneratorLocalData localData, SourceGenerator generator, boolean wantResult) throws CompilationException { ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; String charset = asGenerator.getCharset(); List ret = new ArrayList<>(); @@ -77,21 +88,40 @@ public class PreDecrementActionItem extends UnaryOpItem { ret.addAll(gv.toSource(localData, generator)); ret.add(new ActionDecrement()); int tmpReg = asGenerator.getTempRegister(localData); + ret.add(new ActionStoreRegister(tmpReg, charset)); ret.add(new ActionSetVariable()); ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); asGenerator.releaseTempRegister(localData, tmpReg); } else if (val instanceof GetMemberActionItem) { - GetMemberActionItem mem = (GetMemberActionItem) val; - ret.addAll(mem.toSource(localData, generator)); - ret.remove(ret.size() - 1); //ActionGetMember - ret.addAll(mem.toSource(localData, generator)); - ret.add(new ActionDecrement()); - int tmpReg = asGenerator.getTempRegister(localData); - ret.add(new ActionStoreRegister(tmpReg, charset)); - ret.add(new ActionSetMember()); - ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); - asGenerator.releaseTempRegister(localData, tmpReg); + GetMemberActionItem mem = (GetMemberActionItem) val; + if (mem.isGetter) { + String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString(); + ret.addAll(toSourceMerge(localData, generator, + mem, + new ActionDecrement() + )); + ret.addAll(toSourceMerge(localData, generator, new ActionPush((Long) (long) 1, charset), + mem.object, + asGenerator.pushConst("__set__" + memberNameAsStr), + new ActionCallMethod())); + } else { + ret.addAll(mem.toSource(localData, generator)); + ret.remove(ret.size() - 1); //ActionGetMember + ret.addAll(mem.toSource(localData, generator)); + ret.add(new ActionDecrement()); + int tmpReg = 0; + if (wantResult) { + tmpReg = asGenerator.getTempRegister(localData); + ret.add(new ActionStoreRegister(tmpReg, charset)); + } + ret.add(new ActionSetMember()); + if (wantResult) { + ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); + asGenerator.releaseTempRegister(localData, tmpReg); + } + return ret; + } } else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) { RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value; ret.add(new ActionPush(new RegisterNumber(rn.number), charset)); @@ -106,6 +136,9 @@ public class PreDecrementActionItem extends UnaryOpItem { ret.add(new ActionDecrement()); ret.add(new ActionSetProperty()); } + if (!wantResult) { + ret.add(new ActionPop()); + } return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreIncrementActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreIncrementActionItem.java index 64c527f91..03a77db66 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreIncrementActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/operations/PreIncrementActionItem.java @@ -24,10 +24,12 @@ import com.jpexs.decompiler.flash.action.model.GetPropertyActionItem; import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; import com.jpexs.decompiler.flash.action.parser.script.ActionSourceGenerator; import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem; +import com.jpexs.decompiler.flash.action.swf4.ActionPop; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty; import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; +import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod; import com.jpexs.decompiler.flash.action.swf5.ActionIncrement; import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; @@ -64,6 +66,15 @@ public class PreIncrementActionItem extends UnaryOpItem { @Override public List toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return toSourceBoth(localData, generator, true); + } + + @Override + public List toSourceIgnoreReturnValue(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException { + return toSourceBoth(localData, generator, false); + } + + private List toSourceBoth(SourceGeneratorLocalData localData, SourceGenerator generator, boolean wantResult) throws CompilationException { ActionSourceGenerator asGenerator = (ActionSourceGenerator) generator; String charset = asGenerator.getCharset(); List ret = new ArrayList<>(); @@ -84,16 +95,34 @@ public class PreIncrementActionItem extends UnaryOpItem { ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); asGenerator.releaseTempRegister(localData, tmpReg); } else if (val instanceof GetMemberActionItem) { - GetMemberActionItem mem = (GetMemberActionItem) val; - ret.addAll(mem.toSource(localData, generator)); - ret.remove(ret.size() - 1); //ActionGetMember - ret.addAll(mem.toSource(localData, generator)); - ret.add(new ActionIncrement()); - int tmpReg = asGenerator.getTempRegister(localData); - ret.add(new ActionStoreRegister(tmpReg, charset)); - ret.add(new ActionSetMember()); - ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); - asGenerator.releaseTempRegister(localData, tmpReg); + GetMemberActionItem mem = (GetMemberActionItem) val; + if (mem.isGetter) { + String memberNameAsStr = ((DirectValueActionItem) mem.memberName).getAsString(); + ret.addAll(toSourceMerge(localData, generator, + mem, + new ActionIncrement() + )); + ret.addAll(toSourceMerge(localData, generator, new ActionPush((Long) (long) 1, charset), + mem.object, + asGenerator.pushConst("__set__" + memberNameAsStr), + new ActionCallMethod())); + } else { + ret.addAll(mem.toSource(localData, generator)); + ret.remove(ret.size() - 1); //ActionGetMember + ret.addAll(mem.toSource(localData, generator)); + ret.add(new ActionIncrement()); + int tmpReg = 0; + if (wantResult) { + tmpReg = asGenerator.getTempRegister(localData); + ret.add(new ActionStoreRegister(tmpReg, charset)); + } + ret.add(new ActionSetMember()); + if (wantResult) { + ret.add(new ActionPush(new RegisterNumber(tmpReg), charset)); + asGenerator.releaseTempRegister(localData, tmpReg); + } + return ret; + } } else if ((val instanceof DirectValueActionItem) && ((DirectValueActionItem) val).value instanceof RegisterNumber) { RegisterNumber rn = (RegisterNumber) ((DirectValueActionItem) val).value; ret.add(new ActionPush(new RegisterNumber(rn.number), charset)); @@ -108,6 +137,9 @@ public class PreIncrementActionItem extends UnaryOpItem { ret.add(new ActionIncrement()); ret.add(new ActionSetProperty()); } + if (!wantResult) { + ret.add(new ActionPop()); + } return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java index 882d408e6..a03fe57cb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/script/ActionScript2Parser.java @@ -132,7 +132,9 @@ import com.jpexs.decompiler.flash.action.parser.ActionParseException; import com.jpexs.decompiler.flash.action.swf4.ActionIf; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ConstantIndex; +import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -176,10 +178,13 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; /** * ActionScript 1/2 parser. @@ -280,6 +285,7 @@ public class ActionScript2Parser { this.charset = swf.getCharset(); parseSwfClasses(swf); this.targetSource = targetSource; + this.swf = swf; } private long uniqLast = 0; @@ -461,9 +467,139 @@ public class ActionScript2Parser { return retf; } + private GetMemberActionItem getFirstGetMember(GraphTargetItem item) { + while (item instanceof GetMemberActionItem) { + GetMemberActionItem mem = (GetMemberActionItem) item; + if (!(mem.memberName instanceof DirectValueActionItem)) { + return null; + } + DirectValueActionItem dv = ((DirectValueActionItem) mem.memberName); + if (!dv.isString()) { + return null; + } + if (!(mem.object instanceof GetMemberActionItem)) { + return mem; + } + item = mem.object; + } + return null; + } + + private List getMembersPath(GraphTargetItem item) { + List ret = new ArrayList<>(); + while (item instanceof GetMemberActionItem) { + GetMemberActionItem mem = (GetMemberActionItem) item; + if (!(mem.memberName instanceof DirectValueActionItem)) { + return null; + } + DirectValueActionItem dv = ((DirectValueActionItem) mem.memberName); + if (!dv.isString()) { + return null; + } + ret.add(0, dv.getAsString()); + item = mem.object; + } + if (item instanceof DirectValueActionItem) { + DirectValueActionItem dv1 = (DirectValueActionItem) item; + if (dv1.value instanceof RegisterNumber) { + RegisterNumber rn = (RegisterNumber) dv1.value; + if ("this".equals(rn.name)) { + ret.add(0, "this"); + return ret; + } + if ("super".equals(rn.name)) { + ret.add(0, "super"); + return ret; + } + } + } + if (!((item instanceof GetVariableActionItem || item instanceof VariableActionItem))) { + return null; + } + + if (item instanceof GetVariableActionItem) { + GetVariableActionItem gv = (GetVariableActionItem) item; + if (!(gv.name instanceof DirectValueActionItem)) { + return null; + } + DirectValueActionItem dv = ((DirectValueActionItem) gv.name); + if (!dv.isString()) { + return null; + } + String varName = dv.getAsString(); + ret.add(0, varName); + return ret; + } + + if (item instanceof VariableActionItem) { + VariableActionItem v = (VariableActionItem) item; + ret.add(0, v.getVariableName()); + return ret; + } + + return null; + } + + private void fetchGettersSetters(List parts, Set superGetProperties, Set superSetProperties) { + if (parts == null) { + return; + } + String fullExtendsName = String.join(".", parts); + + String clsName = parts.remove(parts.size() - 1); + + String key; + if (Configuration.flattenASPackages.get()) { + key = "\\__Packages\\" + String.join(".", parts) + "\\" + clsName; + } else { + key = "\\__Packages\\" + String.join("\\", parts) + "\\" + clsName; + } + + ASMSource extendsAsm = swf.getASMs(false).get(key); + if (extendsAsm == null) { + return; + } + + List list = extendsAsm.getActionsToTree(); + for (GraphTargetItem it2 : list) { + if (it2 instanceof ClassActionItem) { + ClassActionItem cai = (ClassActionItem) it2; + List cName = getMembersPath(cai.className); + if (cName != null) { + String fullExtendsName2 = String.join(".", cName); + if (fullExtendsName.equals(fullExtendsName2)) { + for (MyEntry entry : cai.traits) { + String keyAsStr = entry.getKey().toString(); + if (keyAsStr.startsWith("__set__")) { + superSetProperties.add(keyAsStr.substring("__set__".length())); + } + if (keyAsStr.startsWith("__get__")) { + superGetProperties.add(keyAsStr.substring("__get__".length())); + } + } + } + } + if (cai.extendsOp != null) { + fetchGettersSetters(getMembersPath(cai.extendsOp), superGetProperties, superSetProperties); + } + } + } + } + private GraphTargetItem traits(boolean isInterface, GraphTargetItem nameStr, GraphTargetItem extendsStr, List implementsStr, List variables, List functions, boolean inTellTarget, Reference hasEval) throws IOException, ActionParseException, InterruptedException { - GraphTargetItem ret = null; + Set superGetProperties = new HashSet<>(); + Set superSetProperties = new HashSet<>(); + Set thisGetProperties = new HashSet<>(); + Set thisSetProperties = new HashSet<>(); + + if (extendsStr != null) { + fetchGettersSetters(getMembersPath(extendsStr), superGetProperties, superSetProperties); + } + + thisGetProperties.addAll(superGetProperties); + thisSetProperties.addAll(superSetProperties); + /*for (int i = 0; i < nameStr.size() - 1; i++) { List notBody = new ArrayList<>(); List globalClassTypeStr = new ArrayList<>(); @@ -487,7 +623,6 @@ public class ActionScript2Parser { List globalClassTypeStr = new ArrayList<>(); globalClassTypeStr.add("_global"); globalClassTypeStr.addAll(nameStr);*/ - ParsedSymbol s; List> traits = new ArrayList<>(); List traitsStatic = new ArrayList<>(); @@ -534,6 +669,16 @@ public class ActionScript2Parser { if (fname.equals(classNameStr)) { //constructor //actually there's no difference, it's instance trait } + + if (!isStatic) { + if (isGetter) { + thisGetProperties.add(fname); + } + if (isSetter) { + thisSetProperties.add(fname); + } + } + if (!isInterface) { if (isStatic) { FunctionActionItem ft = function(!isInterface, "", true, variables, functions, inTellTarget, hasEval); @@ -596,6 +741,113 @@ public class ActionScript2Parser { } } + for (MyEntry it : traits) { + GraphTargetItem val = it.getValue(); + Set subItems = val.getAllSubItemsRecursively(); + subItems.add(val); + for (GraphTargetItem si : subItems) { + if (si instanceof GetMemberActionItem) { + List path = getMembersPath(si); + if (path != null) { + String varName = path.get(0); + String memberName = path.get(1); + switch (varName) { + case "this": + if (thisGetProperties.contains(memberName)) { + GetMemberActionItem gm = getFirstGetMember(si); + gm.isGetter = true; + } + break; + case "super": + if (superGetProperties.contains(memberName)) { + GetMemberActionItem gm = getFirstGetMember(si); + gm.isGetter = true; + } + break; + } + } + } + if (si instanceof SetMemberActionItem) { + SetMemberActionItem sm = (SetMemberActionItem) si; + if (sm.objectName instanceof DirectValueActionItem + && (sm.object instanceof VariableActionItem)) { + + String memberName = ((DirectValueActionItem) sm.objectName).getAsString(); + + VariableActionItem v = (VariableActionItem) sm.object; + if ("this".equals(v.getVariableName())) { + if (thisSetProperties.contains(memberName)) { + sm.isSetter = true; + } + } + if ("super".equals(v.getVariableName())) { + if (superSetProperties.contains(memberName)) { + sm.isSetter = true; + } + } + } + } + if (si instanceof CallMethodActionItem) { + CallMethodActionItem cm = (CallMethodActionItem) si; + if (cm.methodName instanceof DirectValueActionItem + && (cm.scriptObject instanceof VariableActionItem)) { + String memberName = ((DirectValueActionItem) cm.methodName).getAsString(); + + VariableActionItem v = (VariableActionItem) cm.scriptObject; + if ("this".equals(v.getVariableName())) { + if (thisGetProperties.contains(memberName)) { + cm.isGetter = true; + } + } + if ("super".equals(v.getVariableName())) { + if (superGetProperties.contains(memberName)) { + cm.isGetter = true; + } + } + } + } + if (si instanceof NewMethodActionItem) { + NewMethodActionItem nm = (NewMethodActionItem) si; + if (nm.methodName instanceof DirectValueActionItem + && (nm.scriptObject instanceof VariableActionItem)) { + String memberName = ((DirectValueActionItem) nm.methodName).getAsString(); + + VariableActionItem v = (VariableActionItem) nm.scriptObject; + if ("this".equals(v.getVariableName())) { + if (thisGetProperties.contains(memberName)) { + nm.isGetter = true; + } + } + if ("super".equals(v.getVariableName())) { + if (superGetProperties.contains(memberName)) { + nm.isGetter = true; + } + } + } + } + + if (si instanceof DeleteActionItem) { + DeleteActionItem d = (DeleteActionItem) si; + if (d.propertyName instanceof DirectValueActionItem + && (d.object instanceof VariableActionItem)) { + String memberName = ((DirectValueActionItem) d.propertyName).getAsString(); + + VariableActionItem v = (VariableActionItem) d.object; + if ("this".equals(v.getVariableName())) { + if (thisGetProperties.contains(memberName)) { + d.isGetter = true; + } + } + if ("super".equals(v.getVariableName())) { + if (superGetProperties.contains(memberName)) { + d.isGetter = true; + } + } + } + } + } + } + if (isInterface) { return new InterfaceActionItem(nameStr, implementsStr); } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionCallMethod.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionCallMethod.java index a4a5120fe..7959f6a38 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionCallMethod.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionCallMethod.java @@ -23,11 +23,14 @@ import com.jpexs.decompiler.flash.action.ActionScriptObject; import com.jpexs.decompiler.flash.action.LocalDataArea; import com.jpexs.decompiler.flash.action.as2.Trait; import com.jpexs.decompiler.flash.action.model.CallMethodActionItem; +import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.GetMemberActionItem; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.SecondPassData; import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.AnyItem; import com.jpexs.helpers.utf8.Utf8Helper; import java.util.ArrayList; import java.util.HashMap; @@ -93,6 +96,26 @@ public class ActionCallMethod extends Action { for (long l = 0; l < numArgs; l++) { args.add(stack.pop()); } + + if (methodName instanceof DirectValueActionItem) { + DirectValueActionItem dv = (DirectValueActionItem) methodName; + if (dv.isString()) { + String methodNameStr = dv.getAsString(); + if (methodNameStr.startsWith("__get__") && args.isEmpty()) { + String varName = methodNameStr.substring(7); + GetMemberActionItem gm = new GetMemberActionItem(this, lineStartAction, scriptObject, new DirectValueActionItem(varName)); + gm.isGetter = true; + stack.push(gm); + return; + } else if (methodNameStr.startsWith("__set__") && args.size() == 1) { + String varName = methodNameStr.substring(7); + int outSize = output.size(); + ActionSetMember.handleSetMember(true, args.get(0), new DirectValueActionItem(varName), scriptObject, this, usedDeobfuscations, uninitializedClassTraits, secondPassData, insideDoInitAction, lineStartAction, stack, output, regNames, variables, functions, staticOperation, path); + return; + } + } + } + stack.push(new CallMethodActionItem(this, lineStartAction, scriptObject, methodName, args)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java index b1e11d964..5437f94f3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf5/ActionSetMember.java @@ -38,6 +38,7 @@ import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.SecondPassData; import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.AnyItem; import com.jpexs.decompiler.graph.model.CompoundableBinaryOp; import com.jpexs.helpers.utf8.Utf8Helper; import java.util.HashMap; @@ -86,11 +87,37 @@ public class ActionSetMember extends Action { GraphTargetItem value = stack.pop().getThroughDuplicate(); GraphTargetItem memberName = stack.pop(); GraphTargetItem object = stack.pop(); + handleSetMember(false, value, memberName, object, this, usedDeobfuscations, uninitializedClassTraits, secondPassData, insideDoInitAction, lineStartAction, stack, output, regNames, variables, functions, staticOperation, path); + } + + public static void handleSetMember( + boolean setter, + GraphTargetItem value, + GraphTargetItem memberName, + GraphTargetItem object, + Action action, + Set usedDeobfuscations, + Map> uninitializedClassTraits, + SecondPassData secondPassData, + boolean insideDoInitAction, + GraphSourceItem lineStartAction, + TranslateStack stack, + List output, + HashMap regNames, + HashMap variables, + HashMap functions, + int staticOperation, + String path + ) { + if (value instanceof IncrementActionItem) { GraphTargetItem obj = ((IncrementActionItem) value).object; if (!stack.isEmpty() && stack.peek().valueEquals(obj)) { stack.pop(); - stack.push(new PostIncrementActionItem(this, lineStartAction, obj)); + stack.push(new PostIncrementActionItem(action, lineStartAction, obj)); + if (setter) { + stack.push(new AnyItem()); + } return; } } @@ -98,82 +125,99 @@ public class ActionSetMember extends Action { GraphTargetItem obj = ((DecrementActionItem) value).object; if (!stack.isEmpty() && stack.peek().valueEquals(obj)) { stack.pop(); - stack.push(new PostDecrementActionItem(this, lineStartAction, obj)); + stack.push(new PostDecrementActionItem(action, lineStartAction, obj)); + if (setter) { + stack.push(new AnyItem()); + } return; } } - - if (value instanceof IncrementActionItem) { - if (((IncrementActionItem) value).object instanceof GetMemberActionItem) { - if (((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate().equals(object)) { - if (((GetMemberActionItem) ((IncrementActionItem) value).object).memberName.equals(memberName)) { - ((GetMemberActionItem) ((IncrementActionItem) value).object).object = ((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate(); - output.add(new PostIncrementActionItem(this, lineStartAction, ((IncrementActionItem) value).object)); - return; - } - } - } - } - if (value instanceof DecrementActionItem) { - if (((DecrementActionItem) value).object instanceof GetMemberActionItem) { - if (((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate().valueEquals(object)) { - if (((GetMemberActionItem) ((DecrementActionItem) value).object).memberName.equals(memberName)) { - ((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate(); - output.add(new PostDecrementActionItem(this, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); - return; - } - } - } - } - - SetMemberActionItem setMem = new SetMemberActionItem(this, lineStartAction, object, memberName, value); - - GraphTargetItem inside = value.getNotCoercedNoDup(); - if (inside instanceof StoreRegisterActionItem) { - inside = inside.value; - } - if (inside instanceof CompoundableBinaryOpAs12) { - if (!object.hasSideEffect() && !memberName.hasSideEffect()) { - CompoundableBinaryOp binaryOp = (CompoundableBinaryOp) inside; - if (binaryOp.getLeftSide() instanceof GetMemberActionItem) { - GetMemberActionItem getMember = (GetMemberActionItem) binaryOp.getLeftSide(); - if (GraphTargetItem.objectsValueEquals(object, getMember.object.getThroughDuplicate()) && GraphTargetItem.objectsValueEquals(memberName, getMember.memberName)) { - setMem.setCompoundValue(binaryOp.getRightSide()); - setMem.setCompoundOperator(binaryOp.getOperator()); - } - } - } - } - - GraphTargetItem ret = setMem; - if (value instanceof StoreRegisterActionItem) { - StoreRegisterActionItem sr = (StoreRegisterActionItem) value; - if (sr.define) { - value = sr.getValue(); - ((SetMemberActionItem) ret).setValue(value); - if (value instanceof IncrementActionItem) { - if (((IncrementActionItem) value).object instanceof GetMemberActionItem) { - if (((GetMemberActionItem) ((IncrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) { - ret = new PreIncrementActionItem(this, lineStartAction, ((IncrementActionItem) value).object); + try { + if (value instanceof IncrementActionItem) { + if (((IncrementActionItem) value).object instanceof GetMemberActionItem) { + if (((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate().equals(object)) { + if (((GetMemberActionItem) ((IncrementActionItem) value).object).memberName.equals(memberName)) { + ((GetMemberActionItem) ((IncrementActionItem) value).object).object = ((GetMemberActionItem) ((IncrementActionItem) value).object).object.getThroughDuplicate(); + if (setter) { + output.add(new PreIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate())); + } else { + output.add(new PostIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate())); + } + return; } } - } else if (value instanceof DecrementActionItem) { - if (((DecrementActionItem) value).object instanceof GetMemberActionItem) { - if (((GetMemberActionItem) ((DecrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) { - ret = new PreDecrementActionItem(this, lineStartAction, ((DecrementActionItem) value).object); + } + } + if (value instanceof DecrementActionItem) { + if (((DecrementActionItem) value).object instanceof GetMemberActionItem) { + if (((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate().valueEquals(object)) { + if (((GetMemberActionItem) ((DecrementActionItem) value).object).memberName.equals(memberName)) { + ((GetMemberActionItem) ((DecrementActionItem) value).object).object = ((GetMemberActionItem) ((DecrementActionItem) value).object).object.getThroughDuplicate(); + if (setter) { + output.add(new PreDecrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object.getThroughDuplicate())); + } else { + output.add(new PostDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object.getThroughDuplicate())); + } + return; } } - } else { - sr.temporary = true; - ((SetMemberActionItem) ret).setValue(sr); } - TemporaryRegister tr = new TemporaryRegister(sr.register.number, ret); - variables.put("__register" + sr.register.number, tr); - output.add(new TemporaryRegisterMark(tr)); - return; + } + + SetMemberActionItem setMem = new SetMemberActionItem(action, lineStartAction, object, memberName, value); + setMem.isSetter = setter; + + GraphTargetItem inside = value.getNotCoercedNoDup(); + if (inside instanceof StoreRegisterActionItem) { + inside = inside.value; + } + if (inside instanceof CompoundableBinaryOpAs12) { + if (!object.hasSideEffect() && !memberName.hasSideEffect()) { + CompoundableBinaryOp binaryOp = (CompoundableBinaryOp) inside; + if (binaryOp.getLeftSide() instanceof GetMemberActionItem) { + GetMemberActionItem getMember = (GetMemberActionItem) binaryOp.getLeftSide(); + if (GraphTargetItem.objectsValueEquals(object, getMember.object.getThroughDuplicate()) && GraphTargetItem.objectsValueEquals(memberName, getMember.memberName)) { + setMem.setCompoundValue(binaryOp.getRightSide()); + setMem.setCompoundOperator(binaryOp.getOperator()); + } + } + } + } + + GraphTargetItem ret = setMem; + if (value instanceof StoreRegisterActionItem) { + StoreRegisterActionItem sr = (StoreRegisterActionItem) value; + if (sr.define) { + value = sr.getValue(); + ((SetMemberActionItem) ret).setValue(value); + if (value instanceof IncrementActionItem) { + if (((IncrementActionItem) value).object instanceof GetMemberActionItem) { + if (((GetMemberActionItem) ((IncrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) { + ret = new PreIncrementActionItem(action, lineStartAction, ((IncrementActionItem) value).object); + } + } + } else if (value instanceof DecrementActionItem) { + if (((DecrementActionItem) value).object instanceof GetMemberActionItem) { + if (((GetMemberActionItem) ((DecrementActionItem) value).object).valueEquals(((SetMemberActionItem) ret).getObject())) { + ret = new PreDecrementActionItem(action, lineStartAction, ((DecrementActionItem) value).object); + } + } + } else { + sr.temporary = true; + ((SetMemberActionItem) ret).setValue(sr); + } + TemporaryRegister tr = new TemporaryRegister(sr.register.number, ret); + variables.put("__register" + sr.register.number, tr); + output.add(new TemporaryRegisterMark(tr)); + return; + } + } + output.add(ret); + } finally { + if (setter) { + stack.push(output.remove(output.size() - 1)); } } - output.add(ret); } @Override