Fix swaps

This commit is contained in:
Jindra Petřík
2025-09-01 17:01:26 +02:00
parent a804987067
commit 77d96e8e43
23 changed files with 540 additions and 43 deletions
@@ -2390,7 +2390,7 @@ public class Graph {
*/
protected final void translatePart(List<GraphTargetItem> output, BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
List<GraphPart> sub = part.getSubParts();
stack.setConnectedOutput(0, output);
stack.setConnectedOutput(0, output, localData);
int end;
for (GraphPart p : sub) {
if (p.end == -1) {
@@ -3370,7 +3370,7 @@ public class Graph {
if (code.size() <= part.start) {
if (!(!ret.isEmpty() && ret.get(ret.size() - 1) instanceof ExitItem)) {
stack.setConnectedOutput(0, ret);
stack.setConnectedOutput(0, ret, localData);
stack.addToOutput(new ScriptEndItem(dialect));
}
return ret;
@@ -3503,7 +3503,7 @@ public class Graph {
if (currentRet instanceof GraphPartMarkedArrayList) {
((GraphPartMarkedArrayList) currentRet).startPart(part);
}
stack.setConnectedOutput(0, currentRet);
stack.setConnectedOutput(0, currentRet, localData);
if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) {
parseNext = false;
} else {
@@ -3512,7 +3512,7 @@ public class Graph {
do {
exHappened = false;
try {
stack.setConnectedOutput(currentRet.size(), output);
stack.setConnectedOutput(currentRet.size(), output, localData);
code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path);
} catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts
//output.addAll(ex.getOutput());
@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.clauses.ExceptionAVM2Item;
@@ -23,11 +24,16 @@ import com.jpexs.decompiler.graph.model.BranchStackResistant;
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.DuplicateSourceItem;
import com.jpexs.decompiler.graph.model.ExitItem;
import com.jpexs.decompiler.graph.model.HasTempIndex;
import com.jpexs.decompiler.graph.model.PopItem;
import com.jpexs.decompiler.graph.model.PushItem;
import com.jpexs.decompiler.graph.model.ScriptEndItem;
import com.jpexs.decompiler.graph.model.SetTemporaryItem;
import com.jpexs.decompiler.graph.model.SwapItem;
import com.jpexs.decompiler.graph.model.TemporaryItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -60,6 +66,8 @@ public class TranslateStack extends Stack<GraphTargetItem> {
private Map<String, GraphTargetItem> marks = new HashMap<>();
public List<GraphTargetItem> outputQueue = new ArrayList<>();
public BaseLocalData localData = null;
@Override
public synchronized Object clone() {
@@ -75,9 +83,10 @@ public class TranslateStack extends Stack<GraphTargetItem> {
}
public void setConnectedOutput(int prevOutputSize, List<GraphTargetItem> connectedOutput) {
public void setConnectedOutput(int prevOutputSize, List<GraphTargetItem> connectedOutput, BaseLocalData localData) {
this.prevOutputSize = prevOutputSize;
this.connectedOutput = connectedOutput;
this.localData = localData;
}
@Override
@@ -86,7 +95,7 @@ public class TranslateStack extends Stack<GraphTargetItem> {
if (item instanceof FindPropertyAVM2Item) {
finishBlock(connectedOutput);
} else {
outputQueue.add(item);
outputQueue.add(item);
item = new CommaExpressionItem(item.dialect, null, item.lineStartItem, outputQueue);
outputQueue = new ArrayList<>();
}
@@ -226,6 +235,39 @@ public class TranslateStack extends Stack<GraphTargetItem> {
connectedOutput.addAll(oldQueue);
}
if (isEmpty() && connectedOutput != null) {
for (int i = connectedOutput.size() - 1; i >= 0; i--) {
GraphTargetItem item = connectedOutput.get(i);
if (item instanceof Block) {
break;
}
if (item instanceof PushItem) {
PushItem pi = (PushItem) item;
if (pi.value instanceof SetTemporaryItem) {
SetTemporaryItem st = (SetTemporaryItem) pi.value;
connectedOutput.set(i, st);
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, st.tempIndex);
} else if (pi.value instanceof DuplicateSourceItem) {
DuplicateSourceItem ds = (DuplicateSourceItem) pi.value;
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, ds.getSrc(), ds.getLineStartItem(), ds.value, ds.tempIndex,"push"));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), ds.value, ds.tempIndex);
} /*else if (pi.value instanceof DuplicateItem) {
DuplicateItem d = (DuplicateItem) pi.value;
//connectedOutput.remove(i);
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, d.getSrc(), d.getLineStartItem(), d.value, d.tempIndex));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, d.tempIndex);
} */else if (pi.value instanceof TemporaryItem) {
connectedOutput.remove(i);
return pi.value;
} else {
int temp = localData.maxTempIndex.getVal() + 1;
localData.maxTempIndex.setVal(temp);
connectedOutput.set(i, new SetTemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp, "push"));
return new TemporaryItem(pi.dialect, pi.value.getSrc(), pi.value.getLineStartItem(), pi.value, temp);
}
}
}
}
if (path != null) {
if (this.isEmpty()) {
@@ -260,10 +302,25 @@ public class TranslateStack extends Stack<GraphTargetItem> {
}
}
private boolean isAllTemp() {
for (int i = 0; i < size(); i++) {
GraphTargetItem item = get(i);
if (item instanceof TemporaryItem) {
continue;
}
if (item instanceof DuplicateItem) {
continue;
}
return false;
}
return true;
}
public void addToOutput(GraphTargetItem item) {
if (isEmpty()
|| peek() instanceof ExceptionAVM2Item
|| peek() instanceof NewActivationAVM2Item
//|| isAllTemp()
) {
connectedOutput.add(item);
return;
@@ -356,7 +413,7 @@ public class TranslateStack extends Stack<GraphTargetItem> {
if (output.size() < 3) {
return;
}
if (!(output.get(output.size() - 1) instanceof SwapItem)) {
if (!(output.get(output.size() - 1) instanceof PushItem)) {
return;
}
@@ -364,13 +421,34 @@ public class TranslateStack extends Stack<GraphTargetItem> {
return;
}
if (!(output.get(output.size() - 3) instanceof PushItem)) {
if (!(output.get(output.size() - 3) instanceof SetTemporaryItem)) {
return;
}
PushItem pi1 = (PushItem) output.get(output.size() - 1);
if (!(pi1.value instanceof TemporaryItem)) {
return;
}
TemporaryItem ti = (TemporaryItem) pi1.value;
SetTemporaryItem st = (SetTemporaryItem) output.get(output.size() - 3);
if (!"swap".equals(st.getSuffix())) {
return;
}
if (st.getTempIndex() != ti.getTempIndex()) {
return;
}
PushItem pi2 = (PushItem) output.get(output.size() - 2);
output.remove(output.size() - 1);
push(((PushItem)output.remove(output.size() - 1)).value);
push(((PushItem)output.remove(output.size() - 1)).value);
output.remove(output.size() - 1);
output.remove(output.size() - 1);
push(pi2.value);
push(ti.value);
//moveToStack(output);
}
}
@@ -33,8 +33,9 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DuplicateItem extends GraphTargetItem implements SimpleValue {
public class DuplicateItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
*
@@ -43,8 +44,9 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
* @param lineStartIns Line start item
* @param value Value
*/
public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) {
public DuplicateItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
@@ -62,9 +64,12 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
/*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
return value.appendTry(writer, localData);
}*/
writer.append("§§dup(");
value.appendTry(writer, localData);
return writer.append(")");
if (tempIndex == 0) {
writer.append("§§dup(");
value.appendTry(writer, localData);
return writer.append(")");
}
return writer.append("_temp_").append(tempIndex);
}
@Override
@@ -137,4 +142,8 @@ public class DuplicateItem extends GraphTargetItem implements SimpleValue {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}
@@ -34,7 +34,9 @@ import java.util.Set;
*
* @author JPEXS
*/
public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue {
public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
@@ -44,10 +46,11 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
* @param lineStartIns Line start item
* @param value Value
*/
public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value) {
public DuplicateSourceItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
public Object getResult() {
return value.getResult();
@@ -63,9 +66,18 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
/*if (!value.hasSideEffect() || !Configuration.displayDupInstructions.get()) {
return value.appendTry(writer, localData);
}*/
writer.append("§§dupsrc(");
value.appendTry(writer, localData);
return writer.append(")");
if (tempIndex == 0) {
writer.append("§§dupsrc(");
value.appendTry(writer, localData);
return writer.append(")");
}
GraphTargetItem val = value;
while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) {
val = val.value;
}
writer.append("_tempdup_").append(tempIndex).append(" = ");
val.appendTry(writer, localData);
return writer;
}
@Override
@@ -138,4 +150,8 @@ public class DuplicateSourceItem extends GraphTargetItem implements SimpleValue
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph.model;
/**
*
* @author JPEXS
*/
public interface HasTempIndex {
public int getTempIndex();
}
@@ -0,0 +1,156 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetDialect;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.SourceGenerator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Duplicate item.
*
* @author JPEXS
*/
public class SetTemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
private static final boolean SHOW_SUFFIX = false;
public int tempIndex;
private final String suffix;
public String getSuffix() {
return suffix;
}
/**
* Constructor.
*
* @param dialect Dialect
* @param src Source
* @param lineStartIns Line start item
* @param value Value
*/
public SetTemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex, String suffix) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
this.suffix = suffix;
}
@Override
public Object getResult() {
return value.getResult();
}
@Override
public Double getResultAsNumber() {
return value.getResultAsNumber();
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
GraphTargetItem val = value;
while ((val instanceof HasTempIndex) && ((HasTempIndex) val).getTempIndex() == tempIndex) {
val = val.value;
}
writer.append("_temp");
if (SHOW_SUFFIX) {
writer.append(suffix);
}
writer.append("_").append(tempIndex).append(" = ");
val.appendTry(writer, localData);
return writer;
}
@Override
public GraphTargetItem getNotCoerced() {
return value.getNotCoerced();
}
@Override
public GraphTargetItem getNotCoercedNoDup() {
return this;
}
@Override
public GraphTargetItem getThroughRegister() {
return value.getThroughRegister();
}
@Override
public GraphTargetItem getThroughDuplicate() {
return value.getThroughDuplicate();
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
if (dependencies.contains(value)) {
return false;
}
if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) {
dependencies.add(value);
}
return value.isCompileTime(dependencies);
}
@Override
public boolean isVariableComputed() {
return value.isVariableComputed();
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return new ArrayList<>();
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem simplify(String implicitCoerce) {
return this;
}
@Override
public GraphTargetItem returnType() {
return value.returnType();
}
@Override
public boolean isSimpleValue() {
return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue());
}
@Override
public boolean hasSideEffect() {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2010-2025 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.graph.model;
import com.jpexs.decompiler.flash.SourceGeneratorLocalData;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetDialect;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SimpleValue;
import com.jpexs.decompiler.graph.SourceGenerator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Duplicate item.
*
* @author JPEXS
*/
public class TemporaryItem extends GraphTargetItem implements SimpleValue, HasTempIndex {
public int tempIndex;
/**
* Constructor.
*
* @param dialect Dialect
* @param src Source
* @param lineStartIns Line start item
* @param value Value
*/
public TemporaryItem(GraphTargetDialect dialect, GraphSourceItem src, GraphSourceItem lineStartIns, GraphTargetItem value, int tempIndex) {
super(dialect, src, lineStartIns, value.getPrecedence(), value);
this.tempIndex = tempIndex;
}
@Override
public Object getResult() {
return value.getResult();
}
@Override
public Double getResultAsNumber() {
return value.getResultAsNumber();
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
return writer.append("_temp_").append(tempIndex);
}
@Override
public GraphTargetItem getNotCoerced() {
return value.getNotCoerced();
}
@Override
public GraphTargetItem getNotCoercedNoDup() {
return this;
}
@Override
public GraphTargetItem getThroughRegister() {
return value.getThroughRegister();
}
@Override
public GraphTargetItem getThroughDuplicate() {
return value.getThroughDuplicate();
}
@Override
public boolean isCompileTime(Set<GraphTargetItem> dependencies) {
if (dependencies.contains(value)) {
return false;
}
if (!((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue())) {
dependencies.add(value);
}
return value.isCompileTime(dependencies);
}
@Override
public boolean isVariableComputed() {
return value.isVariableComputed();
}
@Override
public List<GraphSourceItem> toSource(SourceGeneratorLocalData localData, SourceGenerator generator) throws CompilationException {
return new ArrayList<>();
}
@Override
public boolean hasReturnValue() {
return true;
}
@Override
public GraphTargetItem simplify(String implicitCoerce) {
return this;
}
@Override
public GraphTargetItem returnType() {
return value.returnType();
}
@Override
public boolean isSimpleValue() {
return ((value instanceof SimpleValue) && ((SimpleValue) value).isSimpleValue());
}
@Override
public boolean hasSideEffect() {
return value.hasSideEffect();
}
@Override
public int getTempIndex() {
return tempIndex;
}
}