Adding goto §§ instruction for unresolved jumps (FlashCC etc.)

AS3: Add/remove instruction improvement
This commit is contained in:
Jindra Petřík
2015-07-02 06:31:12 +02:00
parent e49362cf47
commit 7983b0bd01
9 changed files with 444 additions and 254 deletions

View File

@@ -1770,193 +1770,191 @@ public class AVM2Code implements Cloneable {
return list;
}
public void updateOffsets(OffsetUpdater updater, MethodBody body) {
for (AVM2Instruction ins : code) {
if (ins.definition instanceof LookupSwitchIns) {
long target = ins.offset + ins.operands[0];
ins.operands[0] = updater.updateOperandOffset(target, ins.operands[0]);
for (int k = 2; k < ins.operands.length; k++) {
target = ins.offset + ins.operands[k];
ins.operands[k] = updater.updateOperandOffset(target, ins.operands[k]);
}
} else {
/*for (int j = 0; j < ins.definition.operands.length; j++) {
if (ins.definition.operands[j] == AVM2Code.DAT_OFFSET) {
long target = ins.offset + ins.getBytes().length + ins.operands[j];
ins.operands[j] = updater.updateOperandOffset(target, ins.operands[j]);
}
}*/
//Faster, but not so universal
if ((ins.definition instanceof JumpIns) || (ins.definition instanceof IfTypeIns)) {
long target = ins.offset + ins.getBytes().length + ins.operands[0];
ins.operands[0] = updater.updateOperandOffset(target, ins.operands[0]);
}
}
}
for (ABCException ex : body.exceptions) {
ex.start = updater.updateOperandOffset(ex.start, ex.start);
ex.end = updater.updateOperandOffset(ex.end, ex.end);
ex.target = updater.updateOperandOffset(ex.target, ex.target);
}
for (AVM2Instruction ins : code) {
ins.offset = updater.updateInstructionOffset(ins.offset);
}
}
private void checkValidOffsets(MethodBody body) {
updateOffsets(new OffsetUpdater() {
@Override
public long updateInstructionOffset(long offset) {
adr2pos(offset);
return offset;
}
@Override
public int updateOperandOffset(long targetAddress, int offset) {
adr2pos(targetAddress);
return offset;
}
}, body);
}
public void removeInstruction(int pos, MethodBody body) {
if ((pos < 0) || (pos >= code.size())) {
throw new IndexOutOfBoundsException();
}
int byteCount = code.get(pos).getBytes().length;
long remOffset = code.get(pos).offset;
for (int i = pos + 1; i < code.size(); i++) {
code.get(i).offset -= byteCount;
}
//checkValidOffsets(body);
final long remOffset = code.get(pos).offset;
final int byteCount = code.get(pos).getBytes().length;
updateOffsets(new OffsetUpdater() {
@Override
public long updateInstructionOffset(long address) {
if (address > remOffset) {
return address - byteCount;
}
return address;
}
for (ABCException ex : body.exceptions) {
if (ex.start > remOffset) {
ex.start -= byteCount;
@Override
public int updateOperandOffset(long targetAddress, int offset) {
if (targetAddress > remOffset) {
return offset - byteCount;
}
return offset;
}
if (ex.end > remOffset) {
ex.end -= byteCount;
}
if (ex.target > remOffset) {
ex.target -= byteCount;
}
}
for (int i = 0; i < pos; i++) {
if (code.get(i).definition instanceof LookupSwitchIns) {
long target = code.get(i).offset + code.get(i).operands[0];
if (target > remOffset) {
code.get(i).operands[0] -= byteCount;
}
for (int k = 2; k < code.get(i).operands.length; k++) {
target = code.get(i).offset + code.get(i).operands[k];
if (target > remOffset) {
code.get(i).operands[k] -= byteCount;
}
}
} else {
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
if (target > remOffset) {
code.get(i).operands[j] -= byteCount;
}
}
}
}
}
for (int i = pos + 1; i < code.size(); i++) {
if (code.get(i).definition instanceof LookupSwitchIns) {
long target = code.get(i).offset + code.get(i).operands[0];
if (target < remOffset) {
code.get(i).operands[0] += byteCount;
}
for (int k = 2; k < code.get(i).operands.length; k++) {
target = code.get(i).offset + code.get(i).operands[k];
if (target < remOffset) {
code.get(i).operands[k] += byteCount;
}
}
} else {
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
if (target < remOffset) {
code.get(i).operands[j] += byteCount;
}
}
}
}
}
}, body);
code.remove(pos);
invalidateCache();
//checkValidOffsets(body);
//System.exit(0);
}
/**
* @param pos
* @param instruction
* Inserts instuction at specified point. Handles offsets properly. Note: If
* newinstruction is jump, the offset operand must be handled properly by
* caller. All old jump offsets to pos are targeted before new instruction.
*
* @param pos Position in the list
* @param instruction Instruction False means before new instruction
* @param body Method body (used for try handling)
*/
public void insertInstruction(int pos, AVM2Instruction instruction, MethodBody body) {
insertInstruction(pos, instruction, true, false, body);
insertInstruction(pos, instruction, false, body);
}
public void replaceInstruction(int idx, AVM2Instruction ins, MethodBody body) {
insertInstruction(idx, ins, true, true, body);
removeInstruction(idx + 1, body);
}
public void insertInstruction(int pos, AVM2Instruction instruction, boolean preRefsToThis, boolean postRefsToThis, MethodBody body) {
/**
* Replaces instrunction by another. Properly handles offsets. Note: If
* newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos
* @param instruction
* @param body
*/
public void replaceInstruction(int pos, AVM2Instruction instruction, MethodBody body) {
if (pos < 0) {
pos = 0;
}
if (pos > code.size()) {
pos = code.size();
}
int byteCount = instruction.getBytes().length;
instruction.offset = code.get(pos).offset;
int oldByteCount = code.get(pos).getBytes().length;
int newByteCount = instruction.getBytes().length;
int byteDelta = newByteCount - oldByteCount;
if (byteDelta != 0) {
updateOffsets(new OffsetUpdater() {
@Override
public long updateInstructionOffset(long offset) {
if (offset > instruction.offset) {
return offset + byteDelta;
}
return offset;
}
@Override
public int updateOperandOffset(long targetAddress, int offset) {
if (targetAddress > instruction.offset) {
return offset + byteDelta;
}
return offset;
}
}, body);
}
code.set(pos, instruction);
}
/**
* Inserts instuction at specified point. Handles offsets properly. Note: If
* newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos Position in the list
* @param instruction Instruction
* @param mapOffsetsAfterIns Map all jumps to the pos after new instruction?
* False means before new instruction
* @param body Method body (used for try handling)
*/
public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns, MethodBody body) {
if (pos < 0) {
pos = 0;
}
if (pos > code.size()) {
pos = code.size();
}
final int byteCount = instruction.getBytes().length;
if (pos == code.size()) {
instruction.offset = code.get(pos - 1).offset + code.get(pos - 1).getBytes().length;
} else {
instruction.offset = code.get(pos).offset;
}
updateOffsets(new OffsetUpdater() {
for (ABCException ex : body.exceptions) {
if (ex.start > instruction.offset) {
ex.start += byteCount;
}
if (ex.end > instruction.offset) {
ex.end += byteCount;
}
if (ex.target > instruction.offset) {
ex.target += byteCount;
}
}
{
for (int i = 0; i < pos; i++) {
if (code.get(i).definition instanceof LookupSwitchIns) {
long target = code.get(i).offset + code.get(i).operands[0];
if (target > instruction.offset) {
code.get(i).operands[0] += byteCount;
}
if (target == instruction.offset && !preRefsToThis) {
code.get(i).operands[0] += byteCount;
}
for (int k = 2; k < code.get(i).operands.length; k++) {
target = code.get(i).offset + code.get(i).operands[k];
if (target > instruction.offset) {
code.get(i).operands[k] += byteCount;
}
if (target == instruction.offset && !preRefsToThis) {
code.get(i).operands[k] += byteCount;
}
}
} else {
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
if (target > instruction.offset) {
code.get(i).operands[j] += byteCount;
}
if (target == instruction.offset && !preRefsToThis) {
code.get(i).operands[j] += byteCount;
}
}
}
@Override
public long updateInstructionOffset(long offset) {
if (offset >= instruction.offset) {
return offset + byteCount;
}
return offset;
}
}
{
for (int i = pos; i < code.size(); i++) {
if (code.get(i).definition instanceof LookupSwitchIns) {
long target = code.get(i).offset + code.get(i).operands[0];
if (target < instruction.offset) {
code.get(i).operands[0] -= byteCount;
}
if (target == instruction.offset && postRefsToThis) {
code.get(i).operands[0] -= byteCount;
}
for (int k = 2; k < code.get(i).operands.length; k++) {
target = code.get(i).offset + code.get(i).operands[k];
if (target < instruction.offset) {
code.get(i).operands[k] -= byteCount;
}
if (target == instruction.offset && postRefsToThis) {
code.get(i).operands[k] -= byteCount;
}
}
} else {
for (int j = 0; j < code.get(i).definition.operands.length; j++) {
if (code.get(i).definition.operands[j] == AVM2Code.DAT_OFFSET) {
long target = code.get(i).offset + code.get(i).getBytes().length + code.get(i).operands[j];
if (target < instruction.offset) {
code.get(i).operands[j] -= byteCount;
}
if (target == instruction.offset && postRefsToThis) {
code.get(i).operands[j] -= byteCount;
}
}
}
}
}
}
for (int i = pos; i < code.size(); i++) {
code.get(i).offset += byteCount;
}
@Override
public int updateOperandOffset(long targetAddress, int offset) {
if ((targetAddress > instruction.offset) || (mapOffsetsAfterIns && (targetAddress == instruction.offset))) {
return offset + byteCount;
}
return offset;
}
}, body);
code.add(pos, instruction);
invalidateCache();
checkValidOffsets(body);
}
@SuppressWarnings("unchecked")
@@ -2524,6 +2522,30 @@ public class AVM2Code implements Cloneable {
restoreControlFlowPass(constants, trait, info, body, false);
//restoreControlFlowPass(constants, body, true);
}
/*
public void removeIgnored(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
try {
List<Integer> outputMap = new ArrayList<>();
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
toASMSource(constants, trait, info, body, outputMap, ScriptExportMode.PCODE, writer);
String src = writer.toString();
AVM2Code acode = ASM3Parser.parse(new StringReader(src), constants, trait, body, info);
for (int i = 0; i < acode.code.size(); i++) {
if (outputMap.size() > i) {
int tpos = outputMap.get(i);
if (tpos == -1) {
} else if (code.get(tpos).mappedOffset >= 0) {
acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset;
} else {
acode.code.get(i).mappedOffset = pos2adr(tpos);
}
}
}
this.code = acode.code;
} catch (IOException | AVM2ParseException ex) {
}
invalidateCache();
}*/
public void removeIgnored(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException {
for (int i = 0; i < code.size(); i++) {

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2010-2015 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.flash.abc.avm2;
/**
*
* @author JPEXS
*/
public interface OffsetUpdater {
public long updateInstructionOffset(long offset);
public int updateOperandOffset(long targetAddress, int offset);
}

View File

@@ -164,67 +164,50 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
ExecutionResult result = new ExecutionResult();
executeActions(classIndex, isStatic, body, scriptIndex, abc, code, i, code.code.size() - 1, result);
if (result.idx != -1) {
int newIstructionCount = 1; // jump
if (!result.stack.isEmpty()) {
newIstructionCount += result.stack.size();
}
/*if (result.idx != -1) {
int newIstructionCount = 1; // jump
if (!result.stack.isEmpty()) {
newIstructionCount += result.stack.size();
}
if (newIstructionCount < result.instructionsProcessed) //if (result.isIf)
{
AVM2Instruction target = code.code.get(result.idx);
AVM2Instruction prevAction = code.code.get(i);
int idelta = 0;
if (newIstructionCount < result.instructionsProcessed) //if (result.isIf)
{
AVM2Instruction target = code.code.get(result.idx);
AVM2Instruction prevAction = code.code.get(i);
int idelta = 0;
if (result.stack.isEmpty() && prevAction.definition instanceof JumpIns) {
prevAction.operands[0] = ((int) (target.offset - prevAction.offset - prevAction.getBytes().length));
} else {
if (!result.stack.isEmpty()) {
for (GraphTargetItem graphTargetItem : result.stack) {
if (graphTargetItem instanceof PopItem) {
continue;
}
AVM2Instruction ins = makePush(graphTargetItem.getResult(), cpool);
if (ins != null) {
code.insertInstruction(i + (idelta++), ins, body);
//prevAction = ins;
} else {
throw new TranslateException("Cannot push: " + graphTargetItem);
}
if (result.stack.isEmpty() && prevAction.definition instanceof JumpIns) {
prevAction.operands[0] = ((int) (target.offset - prevAction.offset - prevAction.getBytes().length));
} else {
if (!result.stack.isEmpty()) {
for (GraphTargetItem graphTargetItem : result.stack) {
if (graphTargetItem instanceof PopItem) {
continue;
}
AVM2Instruction ins = makePush(graphTargetItem.getResult(), cpool);
if (ins != null) {
code.insertInstruction(i + (idelta++), ins, body);
//prevAction = ins;
} else {
throw new TranslateException("Cannot push: " + graphTargetItem);
}
}
}
}
}
AVM2Instruction jump = new AVM2Instruction(0, new JumpIns(), new int[]{0});
code.insertInstruction(i + (idelta++), jump, body);
AVM2Instruction jump = new AVM2Instruction(0, new JumpIns(), new int[]{0});
code.insertInstruction(i + (idelta++), jump, body);
jump.operands[0] = ((int) (target.offset - jump.offset - jump.getBytes().length));
jump.operands[0] = ((int) (target.offset - jump.offset - jump.getBytes().length));
}
}
removeUnreachableActions(code, cpool, trait, minfo, body);
removeZeroJumps(code, body);
removeUnreachableActions(code, cpool, trait, minfo, body);
removeZeroJumps(code, body);
i = -1;
/*if (nextAction != null) {
long mapped = nextAction.mappedOffset;
int nextIdx = -1;
for (int p = 0; p < code.code.size(); p++) {
if (code.code.get(p).mappedOffset == mapped) {
nextIdx = p;
break;
}
}
if (nextIdx == -1) {
//?
break;
} else {
i = nextIdx - 1;
}
}*/
}
}
i = -1;
}
}*/
}
return false;
@@ -340,7 +323,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
break;
}
//boolean ifed = false;
boolean ifed = false;
if (def instanceof JumpIns) {
//ActionJump jump = (ActionJump) action;
long address = action.offset + action.getBytes().length + action.operands[0];
@@ -353,18 +336,29 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
//ActionIf aif = (ActionIf) action;
GraphTargetItem top = stack.pop();
Object res = top.getResult();
long address = action.offset + action.getBytes().length + action.operands[0];
int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
AVM2Instruction tarIns = code.code.get(nidx);
if (EcmaScript.toBoolean(res)) {
long address = action.offset + action.getBytes().length + action.operands[0];
idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address));
if (idx == -1) {
throw new TranslateException("If target not found: " + address);
}
//ifed = true;
/*if (nidx == -1) {
throw new TranslateException("If target not found: " + address);
}*/
AVM2Instruction jumpIns = new AVM2Instruction(0, new JumpIns(), new int[]{0});
//jumpIns.operands[0] = action.operands[0] /*- action.getBytes().length*/ + jumpIns.getBytes().length;
code.replaceInstruction(idx, jumpIns, body);
jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytes().length);
code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body);
idx = code.adr2pos(jumpIns.offset + jumpIns.getBytes().length + jumpIns.operands[0]);
} else {
//action.definition = new DeobfuscatePopIns();
code.replaceInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), body);
//action.definition = new DeobfuscatePopIns();
idx++;
}
ifed = true;
//break;
} else {
idx++;
}
@@ -377,7 +371,9 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener {
result.stack.clear();
result.stack.addAll(stack);
}
if (ifed) {
break;
}
}
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
//result.idx = -1;

View File

@@ -167,7 +167,7 @@ public class AVM2Graph extends Graph {
}
@Override
protected List<GraphTargetItem> check(GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
List<GraphTargetItem> ret = null;
AVM2LocalData aLocalData = (AVM2LocalData) localData;
@@ -277,7 +277,7 @@ public class AVM2Graph extends Graph {
finallyJumps.clear();
ignoredSwitches.put(e, swPos);
st.push(new PopItem(null));
finallyCommands = printGraph(localData, st, allParts, parent, fpart, null, loops, staticOperation, path);
finallyCommands = printGraph(partCodes, partCodePos, localData, st, allParts, parent, fpart, null, loops, staticOperation, path);
//ignoredSwitches.remove(igs_size-1);
finallyJumps.putAll(oldFinallyJumps);
if (!finallyJumps.containsKey(e)) {
@@ -336,7 +336,7 @@ public class AVM2Graph extends Graph {
stopPart2.add(retPart);
}
List<GraphTargetItem> ncatchedCommands = printGraph(localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path);
List<GraphTargetItem> ncatchedCommands = printGraph(partCodes, partCodePos, localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path);
if (catchedExceptions.get(e).isFinally() && (catchedExceptions.size() > 1 || hasFinally)) {
catchedExceptions.remove(e);
e--;
@@ -376,7 +376,7 @@ public class AVM2Graph extends Graph {
}
TranslateStack st = (TranslateStack) stack.clone();
st.clear();
List<GraphTargetItem> tryCommands = printGraph(localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path);
List<GraphTargetItem> tryCommands = printGraph(partCodes, partCodePos, localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path);
if (retPart != null && avm2code.code.get(retPart.start).isExit() && !(!tryCommands.isEmpty() && (tryCommands.get(tryCommands.size() - 1) instanceof ExitItem))) {
avm2code.code.get(retPart.start).translate(localData, st, tryCommands, staticOperation, path);
}
@@ -413,7 +413,7 @@ public class AVM2Graph extends Graph {
TranslateStack st = (TranslateStack) stack.clone();
st.clear();
ret.addAll(printGraph(localData, st, allParts, null, part, stopPart, loops, staticOperation, path));
ret.addAll(printGraph(partCodes, partCodePos, localData, st, allParts, null, part, stopPart, loops, staticOperation, path));
} else {
ret.add(lop);
}
@@ -603,7 +603,7 @@ public class AVM2Graph extends Graph {
defaultPart = switchLoc.nextParts.get(switchLoc.nextParts.size() - 1);
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(next);
defaultCommands = printGraph(localData, stack, allParts, switchLoc, defaultPart, stopPart2, loops, staticOperation, path);
defaultCommands = printGraph(partCodes, partCodePos, localData, stack, allParts, switchLoc, defaultPart, stopPart2, loops, staticOperation, path);
if (!defaultCommands.isEmpty()) {
if (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem) {
if (((BreakItem) defaultCommands.get(defaultCommands.size() - 1)).loopId == currentLoop.id) {
@@ -630,7 +630,7 @@ public class AVM2Graph extends Graph {
stopPart2.add(defaultPart);
}
cc.addAll(0, printGraph(localData, stack, allParts, switchLoc, caseBodies.get(i), stopPart2, loops, staticOperation, path));
cc.addAll(0, printGraph(partCodes, partCodePos, localData, stack, allParts, switchLoc, caseBodies.get(i), stopPart2, loops, staticOperation, path));
caseCommands.add(cc);
}
@@ -642,7 +642,7 @@ public class AVM2Graph extends Graph {
ret.add(ti);
} else {*/
currentLoop.phase = 2;
ret.addAll(printGraph(localData, stack, allParts, null, next, stopPart, loops, staticOperation, path));
ret.addAll(printGraph(partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path));
//}
}
}

View File

@@ -204,7 +204,7 @@ public final class MethodBody implements Cloneable {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
} else {
//if (!path.contains("RemoveAllPopup")) {
//if (!path.contains("_addGarbageLineMulti")) {
if (!Configuration.decompile.get()) {
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
return;
@@ -248,7 +248,7 @@ public final class MethodBody implements Cloneable {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(constants, trait, method_info.get(this.method_info), this, exportMode, writer);
} else {
//if (!path.contains("RemoveAllPopup")) {
//if (!path.contains("_addGarbageLineMulti")) {
if (!Configuration.decompile.get()) {
//writer.startMethod(this.method_info);
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();

View File

@@ -53,6 +53,7 @@ import com.jpexs.decompiler.graph.model.WhileItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
@@ -247,7 +248,7 @@ public class ActionGraph extends Graph {
}
@Override
protected List<GraphTargetItem> check(GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
if (!output.isEmpty()) {
if (output.get(output.size() - 1) instanceof StoreRegisterActionItem) {
StoreRegisterActionItem str = (StoreRegisterActionItem) output.get(output.size() - 1);
@@ -310,7 +311,7 @@ public class ActionGraph extends Graph {
List<GraphTargetItem> defaultCommands = new ArrayList<>();
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(defaultPart2);
defaultCommands = printGraph(localData, stack, allParts, null, defaultPart, stopPart2, loops, staticOperation, path);
defaultCommands = printGraph(partCodes, partCodePos, localData, stack, allParts, null, defaultPart, stopPart2, loops, staticOperation, path);
List<GraphPart> loopContinues = new ArrayList<>();
for (Loop l : loops) {
@@ -384,7 +385,7 @@ public class ActionGraph extends Graph {
if ((defaultPart != null) && (defaultCommands.isEmpty())) {
List<GraphPart> stopPart2x = new ArrayList<>(stopPart);
stopPart2x.add(next);
defaultCommands = printGraph(localData, stack, allParts, null, defaultPart, stopPart2x, loops, staticOperation, path);
defaultCommands = printGraph(partCodes, partCodePos, localData, stack, allParts, null, defaultPart, stopPart2x, loops, staticOperation, path);
}
if (!defaultCommands.isEmpty()) {
@@ -433,7 +434,7 @@ public class ActionGraph extends Graph {
if (breakPart != null) {
stopPart2x.add(breakPart);
}
cc.addAll(0, printGraph(localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path));
cc.addAll(0, printGraph(partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path));
if (cc.size() >= 2) {
if (cc.get(cc.size() - 1) instanceof BreakItem) {
if ((cc.get(cc.size() - 2) instanceof ContinueItem) || (cc.get(cc.size() - 2) instanceof BreakItem)) {
@@ -452,7 +453,7 @@ public class ActionGraph extends Graph {
if (ti != null) {
ret.add(ti);
} else {
ret.addAll(printGraph(localData, stack, allParts, null, next, stopPart, loops, staticOperation, path));
ret.addAll(printGraph(partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path));
}
}
}

View File

@@ -31,8 +31,10 @@ 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.ForItem;
import com.jpexs.decompiler.graph.model.GotoItem;
import com.jpexs.decompiler.graph.model.IfItem;
import com.jpexs.decompiler.graph.model.IntegerValueItem;
import com.jpexs.decompiler.graph.model.LabelItem;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.decompiler.graph.model.LogicalOpItem;
import com.jpexs.decompiler.graph.model.LoopItem;
@@ -434,7 +436,7 @@ public class Graph {
/*1
System.err.println("<loops>");
for (Loop el : loops) {
System..println(el);
System.err.println(el);
}
System.err.println("</loops>");*/
getPrecontinues(path, localData, null, heads.get(0), allParts, loops, null);
@@ -444,7 +446,7 @@ public class Graph {
}
System.err.println("</loopspre>");//*/
List<GraphTargetItem> ret = printGraph(localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
List<GraphTargetItem> ret = printGraph(new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
processIfs(ret);
finalProcessStack(stack, ret);
finalProcessAll(ret, 0, new FinalProcessLocalData());
@@ -731,7 +733,7 @@ public class Graph {
return false;
}
protected List<GraphTargetItem> check(GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, List<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
return null;
}
@@ -807,9 +809,9 @@ public class Graph {
list.remove(list.size() - 1);
}
protected List<GraphTargetItem> printGraph(BaseLocalData localData, TranslateStack stack, List<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> printGraph(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, BaseLocalData localData, TranslateStack stack, List<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, int staticOperation, String path) throws InterruptedException {
List<GraphPart> visited = new ArrayList<>();
return printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0);
return printGraph(partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0);
}
protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List<Loop> loops) {
@@ -1305,7 +1307,7 @@ public class Graph {
}
}
protected List<GraphTargetItem> printGraph(List<GraphPart> visited, BaseLocalData localData, TranslateStack stack, List<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
protected List<GraphTargetItem> printGraph(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, List<GraphPart> visited, BaseLocalData localData, TranslateStack stack, List<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
}
@@ -1315,11 +1317,7 @@ public class Graph {
if (recursionLevel > allParts.size() + 1) {
throw new TranslateException("printGraph max recursion level reached.");
}
if (visited.contains(part)) {
//return new ArrayList<GraphTargetItem>();
} else {
visited.add(part);
}
if (ret == null) {
ret = new ArrayList<>();
}
@@ -1429,6 +1427,23 @@ public class Graph {
ret.add(new ScriptEndItem());
return ret;
}
if (visited.contains(part)) {
String labelName = "addr" + part.start;
List<GraphTargetItem> firstCode = partCodes.get(part);
int firstCodePos = partCodePos.get(part);
if (firstCode.size() > firstCodePos && (firstCode.get(firstCodePos) instanceof LabelItem)) {
labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName;
} else {
firstCode.add(firstCodePos, new LabelItem(null, labelName));
}
ret.add(new GotoItem(null, labelName));
return ret;
} else {
visited.add(part);
partCodes.put(part, ret);
partCodePos.put(part, ret.size());
}
List<GraphTargetItem> currentRet = ret;
UniversalLoopItem loopItem = null;
TranslateStack sPreLoop = stack;
@@ -1466,7 +1481,7 @@ public class Graph {
}
if (parseNext) {
List<GraphTargetItem> retCheck = check(code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path);
List<GraphTargetItem> retCheck = check(partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path);
if (retCheck != null) {
if (!retCheck.isEmpty()) {
currentRet.addAll(retCheck);
@@ -1524,7 +1539,7 @@ public class Graph {
//int stackLenBefore = stack.size();
TranslateStack s2 = (TranslateStack) stack.clone();
s2.clear();
List<GraphTargetItem> nextCommands = printGraph(visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
List<GraphTargetItem> nextCommands = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
makeAllCommands(nextCommands, s2);
if (first) {
defaultCommands = nextCommands;
@@ -1539,7 +1554,7 @@ public class Graph {
currentRet.add(sw);
swLoop.phase = 2;
if (next != null) {
currentRet.addAll(printGraph(visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
currentRet.addAll(printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
}
} //else
GraphPart nextOnePart = null;
@@ -1576,12 +1591,12 @@ public class Graph {
List<GraphTargetItem> onTrue = new ArrayList<>();
if (!isEmpty && hasOntrue) {
onTrue = printGraph(visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
onTrue = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
}
List<GraphTargetItem> onFalse = new ArrayList<>();
if (!isEmpty && hasOnFalse) {
onFalse = printGraph(visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
onFalse = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
}
//List<GraphTargetItem> out2 = new ArrayList<>();
//makeAllCommands(out2, stack);
@@ -1625,7 +1640,7 @@ public class Graph {
}
//currentRet.addAll(out2);
if (next != null) {
printGraph(visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
//currentRet.addAll();
}
}
@@ -1634,7 +1649,7 @@ public class Graph {
nextOnePart = part.nextParts.get(0);
}
if (nextOnePart != null) {
printGraph(visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1);
}
}
@@ -1659,7 +1674,7 @@ public class Graph {
stopContPart.add(currentLoop.loopContinue);
GraphPart precoBackup = currentLoop.loopPreContinue;
currentLoop.loopPreContinue = null;
loopItem.commands.addAll(printGraph(visited, localData, new TranslateStack(path), allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1));
loopItem.commands.addAll(printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1));
}
}
@@ -1716,7 +1731,7 @@ public class Graph {
currentLoop.loopPreContinue = null;
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(currentLoop.loopContinue);
finalComm = printGraph(visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
finalComm = printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
currentLoop.loopPreContinue = backup;
checkContinueAtTheEnd(finalComm, currentLoop);
}
@@ -1793,7 +1808,7 @@ public class Graph {
currentLoop.loopPreContinue = null;
List<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(currentLoop.loopContinue);
List<GraphTargetItem> finalComm = printGraph(visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
List<GraphTargetItem> finalComm = printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
currentLoop.loopPreContinue = backup;
checkContinueAtTheEnd(finalComm, currentLoop);
@@ -1843,7 +1858,7 @@ public class Graph {
}
if (currentLoop.loopBreak != null) {
ret.addAll(printGraph(visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
ret.addAll(printGraph(partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1));
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2010-2015 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.ecma.Null;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
/**
*
* @author JPEXS
*/
public class GotoItem extends GraphTargetItem {
public String labelName;
public GotoItem(GraphSourceItem src, String labelName) {
super(src, PRECEDENCE_PRIMARY);
this.labelName = labelName;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.append("§§goto(" + labelName + ")");
return writer;
}
@Override
public boolean hasReturnValue() {
return false;
}
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
}
@Override
public Object getResult() {
return null;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2010-2015 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.ecma.Null;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
/**
*
* @author JPEXS
*/
public class LabelItem extends GraphTargetItem {
public String labelName;
public LabelItem(GraphSourceItem src, String labelName) {
super(src, PRECEDENCE_PRIMARY);
this.labelName = labelName;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
writer.append(labelName + ":");
return writer;
}
@Override
public boolean needsNewLine() {
return false;
}
@Override
public boolean needsSemicolon() {
return false;
}
@Override
public boolean hasReturnValue() {
return false;
}
@Override
public GraphTargetItem returnType() {
return TypeItem.UNBOUNDED;
}
@Override
public Object getResult() {
return null;
}
}