mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-09 03:33:20 +00:00
Fixed: Dot parent operator not detected in some cases
This commit is contained in:
@@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file.
|
||||
- #1206 Switch with multiple default clauses
|
||||
- ASC2 §§push of function calls before returning from a method
|
||||
- Support for ASC2 and swftools try..catch..finally block
|
||||
- Dot parent operator not detected in some cases
|
||||
|
||||
### Changed
|
||||
- AS3 test methods separated to classes
|
||||
|
||||
@@ -43,8 +43,10 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceAIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.ConvertIIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ConstructAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FilteredCheckAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.GetLexAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.InAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item;
|
||||
@@ -59,6 +61,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.SetSlotAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.SetTypeAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.ThrowAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.WithEndAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.FilterAVM2Item;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ForEachInAVM2Item;
|
||||
@@ -79,9 +82,11 @@ import com.jpexs.decompiler.graph.ScopeStack;
|
||||
import com.jpexs.decompiler.graph.TranslateStack;
|
||||
import com.jpexs.decompiler.graph.model.AnyItem;
|
||||
import com.jpexs.decompiler.graph.model.BreakItem;
|
||||
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
|
||||
import com.jpexs.decompiler.graph.model.ContinueItem;
|
||||
import com.jpexs.decompiler.graph.model.DuplicateItem;
|
||||
import com.jpexs.decompiler.graph.model.ExitItem;
|
||||
import com.jpexs.decompiler.graph.model.FalseItem;
|
||||
import com.jpexs.decompiler.graph.model.GotoItem;
|
||||
import com.jpexs.decompiler.graph.model.IfItem;
|
||||
import com.jpexs.decompiler.graph.model.LoopItem;
|
||||
@@ -626,7 +631,6 @@ public class AVM2Graph extends Graph {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private List<GraphTargetItem> checkTry(List<GraphTargetItem> currentRet, List<GraphTargetItem> output, List<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, AVM2LocalData localData, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, Set<GraphPart> allParts, TranslateStack stack, int staticOperation, String path) throws InterruptedException {
|
||||
if (localData.parsedExceptions == null) {
|
||||
localData.parsedExceptions = new ArrayList<>();
|
||||
@@ -1210,62 +1214,133 @@ public class AVM2Graph extends Graph {
|
||||
if (hn.obj.getNotCoerced().getThroughRegister().getNotCoerced() instanceof FilteredCheckAVM2Item) {
|
||||
if (w.commands.size() >= 3) {
|
||||
int pos = 0;
|
||||
Set<Integer> localRegsToKill = new HashSet<>();
|
||||
|
||||
while (w.commands.get(pos) instanceof SetLocalAVM2Item) {
|
||||
if (w.commands.get(pos).value instanceof NextValueAVM2Item) {
|
||||
NextValueAVM2Item nextValueItem = (NextValueAVM2Item) w.commands.get(pos).value;
|
||||
if (nextValueItem.index instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) nextValueItem.index).regIndex);
|
||||
}
|
||||
if (nextValueItem.obj instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) nextValueItem.obj).regIndex);
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
GraphTargetItem ft = w.commands.get(pos);
|
||||
if (ft instanceof WithAVM2Item) {
|
||||
pos++;
|
||||
while (w.commands.get(pos) instanceof SetTypeAVM2Item) {
|
||||
List<GraphTargetItem> withCommands = new ArrayList<>();
|
||||
while (!(w.commands.get(pos) instanceof WithEndAVM2Item)) {
|
||||
withCommands.add(w.commands.get(pos));
|
||||
pos++;
|
||||
}
|
||||
ft = w.commands.get(pos);
|
||||
if (ft instanceof IfItem) {
|
||||
IfItem ift = (IfItem) ft;
|
||||
if (ift.onTrue.size() > 0) {
|
||||
ft = ift.onTrue.get(0);
|
||||
if (ft instanceof SetPropertyAVM2Item) {
|
||||
SetPropertyAVM2Item spt = (SetPropertyAVM2Item) ft;
|
||||
if (spt.object instanceof LocalRegAVM2Item) {
|
||||
int regIndex = ((LocalRegAVM2Item) spt.object).regIndex;
|
||||
HashMap<Integer, GraphTargetItem> localRegs = aLocalData.localRegs;
|
||||
localRegs.put(regIndex, new FilterAVM2Item(null, null, hn.obj.getThroughRegister(), ift.expression));
|
||||
|
||||
Set<Integer> localRegsToKill = new HashSet<>();
|
||||
localRegsToKill.add(regIndex);
|
||||
GraphTargetItem expr = null;
|
||||
int getLocalObjectIp = -1;
|
||||
int regIndex = -1;
|
||||
HashMap<Integer, GraphTargetItem> localRegs = aLocalData.localRegs;
|
||||
|
||||
if (hn.obj instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) hn.obj).regIndex);
|
||||
}
|
||||
if (spt.value instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) spt.value).regIndex);
|
||||
}
|
||||
if (spt.propertyName instanceof FullMultinameAVM2Item) {
|
||||
if (((FullMultinameAVM2Item) spt.propertyName).name instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) ((FullMultinameAVM2Item) spt.propertyName).name).regIndex);
|
||||
if (!withCommands.isEmpty()) {
|
||||
if (withCommands.get(withCommands.size() - 1) instanceof IfItem) {
|
||||
IfItem ift = (IfItem) withCommands.get(withCommands.size() - 1);
|
||||
if (ift.onTrue.size() > 0) {
|
||||
ft = ift.onTrue.get(0);
|
||||
if (ft instanceof SetPropertyAVM2Item) {
|
||||
SetPropertyAVM2Item spt = (SetPropertyAVM2Item) ft;
|
||||
if (spt.object instanceof LocalRegAVM2Item) {
|
||||
getLocalObjectIp = avm2code.adr2pos(spt.object.getSrc().getAddress());
|
||||
regIndex = ((LocalRegAVM2Item) spt.object).regIndex;
|
||||
expr = ift.expression.getNotCoerced();
|
||||
if (withCommands.size() > 1) {
|
||||
withCommands.remove(withCommands.size() - 1);
|
||||
withCommands.add(expr);
|
||||
expr = new CommaExpressionItem(null, localData.lineStartInstruction, withCommands);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: maybe check its single usage
|
||||
for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) {
|
||||
if (localRegsToKill.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
if (output.get(i) instanceof SetLocalAVM2Item) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i);
|
||||
if (localRegsToKill.contains(setLocal.regIndex)) {
|
||||
output.remove(i);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//There is no if - this means there was something that
|
||||
// can be evaluated on compiletime and compiler removed the whole if
|
||||
// ASC2 does this
|
||||
withCommands.add(new FalseItem(null, localData.lineStartInstruction));
|
||||
expr = new CommaExpressionItem(null, localData.lineStartInstruction, withCommands);
|
||||
}
|
||||
} else {
|
||||
expr = new FalseItem(null, localData.lineStartInstruction);
|
||||
}
|
||||
FilteredCheckAVM2Item filteredCheck = (FilteredCheckAVM2Item) hn.obj.getThroughRegister().getNotCoerced();
|
||||
FilterAVM2Item filter = new FilterAVM2Item(null, null, filteredCheck.object, expr);
|
||||
|
||||
if (regIndex == -1) {
|
||||
for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) {
|
||||
if (output.get(i) instanceof SetLocalAVM2Item) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i);
|
||||
if (setLocal.value instanceof ConstructAVM2Item) {
|
||||
if ((((ConstructAVM2Item) setLocal.value).object instanceof GetLexAVM2Item)) {
|
||||
GetLexAVM2Item lex = (GetLexAVM2Item) ((ConstructAVM2Item) setLocal.value).object;
|
||||
if ("XMLList".equals(lex.getRawPropertyName())) {
|
||||
regIndex = setLocal.regIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localRegsToKill.add(regIndex);
|
||||
|
||||
if (hn.obj instanceof LocalRegAVM2Item) {
|
||||
localRegsToKill.add(((LocalRegAVM2Item) hn.obj).regIndex);
|
||||
}
|
||||
|
||||
int setLocalIp = -1;
|
||||
for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) {
|
||||
if (output.get(i) instanceof SetLocalAVM2Item) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i);
|
||||
if (setLocal.regIndex == regIndex) {
|
||||
setLocalIp = avm2code.adr2pos(setLocal.getSrc().getAddress());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<Integer> usages = new HashSet<>();
|
||||
if (setLocalIp > -1) {
|
||||
usages = new HashSet<>(aLocalData.getSetLocalUsages(setLocalIp));
|
||||
usages.remove(getLocalObjectIp);
|
||||
|
||||
}
|
||||
|
||||
for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) {
|
||||
if (localRegsToKill.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
if (output.get(i) instanceof SetLocalAVM2Item) {
|
||||
SetLocalAVM2Item setLocal = (SetLocalAVM2Item) output.get(i);
|
||||
if (localRegsToKill.contains(setLocal.regIndex)) {
|
||||
output.remove(i);
|
||||
}
|
||||
if (setLocal.regIndex == regIndex) {
|
||||
setLocal.value = filter;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usages.isEmpty()) {
|
||||
output.add(filter);
|
||||
} else {
|
||||
localRegs.put(regIndex, filter);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
} else if (!w.commands.isEmpty()) {
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2.model;
|
||||
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
@@ -28,7 +29,7 @@ import com.jpexs.decompiler.graph.model.LocalData;
|
||||
*/
|
||||
public class FilteredCheckAVM2Item extends AVM2Item {
|
||||
|
||||
|
||||
public GraphTargetItem object;
|
||||
|
||||
public FilteredCheckAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, GraphTargetItem object) {
|
||||
super(instruction, lineStartIns, NOPRECEDENCE);
|
||||
@@ -42,7 +43,10 @@ public class FilteredCheckAVM2Item extends AVM2Item {
|
||||
|
||||
@Override
|
||||
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
|
||||
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
|
||||
writer.append("§§checkfilter(");
|
||||
object.toString(writer, localData);
|
||||
writer.append(")");
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -232,6 +232,30 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoWhile3() {
|
||||
decompileMethod("classic", "testDoWhile3", "do\r\n"
|
||||
+ "{\r\n"
|
||||
+ "this.nextChar();\r\n"
|
||||
+ "}\r\n"
|
||||
+ "while(this.ch != \"\\n\" && this.ch != \"\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDotParent() {
|
||||
decompileMethod("classic", "testDotParent", "var d:* = undefined;\r\n"
|
||||
+ "var k:* = undefined;\r\n"
|
||||
+ "var g:* = undefined;\r\n"
|
||||
+ "d = new TestClass1();\r\n"
|
||||
+ "k = null;\r\n"
|
||||
+ "k.(d.attrib++, 0);\r\n"
|
||||
+ "trace(\"between\");\r\n"
|
||||
+ "g = k.(d.attrib++, 0);\r\n"
|
||||
+ "trace(\"end\");\r\n",
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpressions() {
|
||||
decompileMethod("classic", "testExpressions", "var arr:Array = null;\r\n"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -22,6 +22,7 @@ package
|
||||
TestDecl2;
|
||||
TestDeclarations;
|
||||
TestDefaultNotLastGrouped;
|
||||
TestDotParent;
|
||||
TestDoWhile;
|
||||
TestDoWhile2;
|
||||
TestDoWhile3;
|
||||
|
||||
22
libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestDotParent.as
vendored
Normal file
22
libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestDotParent.as
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package tests
|
||||
{
|
||||
|
||||
public class TestDotParent
|
||||
{
|
||||
public function run():*
|
||||
{
|
||||
var d:* = new TestClass1();
|
||||
var k:* = null;
|
||||
|
||||
k.(d.attrib++, 0);
|
||||
trace("between");
|
||||
var g:* = k.(d.attrib++, 0);
|
||||
trace("end");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestClass1
|
||||
{
|
||||
public var attrib:int = 5;
|
||||
}
|
||||
Reference in New Issue
Block a user