mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-02 08:54:53 +00:00
linked lavm2instuction list for faster deobfuscation (not ready yet)
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 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.fastavm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class AVM2InstructionItem {
|
||||
|
||||
public AVM2Instruction ins;
|
||||
|
||||
public AVM2InstructionItem prev;
|
||||
|
||||
public AVM2InstructionItem next;
|
||||
|
||||
private AVM2InstructionItem jumpTarget;
|
||||
|
||||
public Set<AVM2InstructionItem> jumpsHere;
|
||||
|
||||
public Set<AVM2InstructionItem> lastInsOf;
|
||||
|
||||
private List<AVM2InstructionItem> containerLastInstructions;
|
||||
|
||||
// 1 means reachable, 2 means reachable and processed
|
||||
int reachable;
|
||||
|
||||
public boolean excluded;
|
||||
|
||||
public AVM2InstructionItem(AVM2Instruction ins) {
|
||||
this.ins = ins;
|
||||
}
|
||||
|
||||
public boolean isJumpTarget() {
|
||||
return jumpsHere != null && !jumpsHere.isEmpty();
|
||||
}
|
||||
|
||||
public int jumpsHereSize() {
|
||||
return jumpsHere == null ? 0 : jumpsHere.size();
|
||||
}
|
||||
|
||||
public boolean isContainerLastInstruction() {
|
||||
return lastInsOf != null && !lastInsOf.isEmpty();
|
||||
}
|
||||
|
||||
public void removeJumpTarget() {
|
||||
if (jumpTarget == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (jumpTarget.jumpsHere != null) {
|
||||
jumpTarget.jumpsHere.remove(this);
|
||||
}
|
||||
|
||||
jumpTarget = null;
|
||||
}
|
||||
|
||||
public AVM2InstructionItem getJumpTarget() {
|
||||
return jumpTarget;
|
||||
}
|
||||
|
||||
public AVM2Instruction getJumpTargetInstruction() {
|
||||
return jumpTarget == null ? null : jumpTarget.ins;
|
||||
}
|
||||
|
||||
public void setJumpTarget(AVM2InstructionItem item) {
|
||||
removeJumpTarget();
|
||||
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.jumpsHere == null) {
|
||||
item.jumpsHere = new HashSet<>();
|
||||
}
|
||||
|
||||
item.jumpsHere.add(this);
|
||||
jumpTarget = item;
|
||||
}
|
||||
|
||||
public List<AVM2InstructionItem> getContainerLastInstructions() {
|
||||
return containerLastInstructions;
|
||||
}
|
||||
|
||||
public void removeContainerLastInstructions() {
|
||||
if (containerLastInstructions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (AVM2InstructionItem lastIns : containerLastInstructions) {
|
||||
if (lastIns.lastInsOf != null) {
|
||||
lastIns.lastInsOf.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
containerLastInstructions = null;
|
||||
}
|
||||
|
||||
public void replaceContainerLastInstruction(AVM2InstructionItem oldItem, AVM2InstructionItem newItem) {
|
||||
if (containerLastInstructions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < containerLastInstructions.size(); i++) {
|
||||
if (containerLastInstructions.get(i) == oldItem) {
|
||||
containerLastInstructions.set(i, newItem);
|
||||
if (oldItem.lastInsOf != null) {
|
||||
oldItem.lastInsOf.remove(this);
|
||||
}
|
||||
|
||||
newItem.ensureLastInstructionOf().add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setContainerLastInstructions(List<AVM2InstructionItem> lastInstructions) {
|
||||
removeContainerLastInstructions();
|
||||
|
||||
for (AVM2InstructionItem lastIns : lastInstructions) {
|
||||
lastIns.ensureLastInstructionOf().add(this);
|
||||
}
|
||||
|
||||
containerLastInstructions = lastInstructions;
|
||||
}
|
||||
|
||||
private Set<AVM2InstructionItem> ensureLastInstructionOf() {
|
||||
if (lastInsOf == null) {
|
||||
lastInsOf = new HashSet<>();
|
||||
}
|
||||
|
||||
return lastInsOf;
|
||||
}
|
||||
|
||||
public boolean isExcluded() {
|
||||
return excluded;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 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.fastavm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns;
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.LookupSwitchIns;
|
||||
import com.jpexs.decompiler.flash.abc.types.ABCException;
|
||||
import com.jpexs.decompiler.flash.abc.types.MethodBody;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class FastAVM2List implements Collection<AVM2InstructionItem> {
|
||||
|
||||
private int size;
|
||||
|
||||
private AVM2InstructionItem firstItem;
|
||||
|
||||
private final Map<AVM2Instruction, AVM2InstructionItem> actionItemMap;
|
||||
|
||||
private final Set<AVM2InstructionItem> actionItemSet;
|
||||
|
||||
public FastAVM2List(MethodBody body) {
|
||||
// exceptions todo
|
||||
AVM2Code avm2code = body.getCode();
|
||||
List<AVM2Instruction> code = avm2code.code;
|
||||
actionItemMap = new HashMap<>(code.size());
|
||||
actionItemSet = new HashSet<>(code.size());
|
||||
for (AVM2Instruction action : code) {
|
||||
insertItemAfter(null, action);
|
||||
}
|
||||
|
||||
size = code.size();
|
||||
// getContainerLastActions(avm2code, actionItemMap);
|
||||
getJumps(avm2code, actionItemMap);
|
||||
}
|
||||
|
||||
public final AVM2InstructionItem insertItemBefore(AVM2InstructionItem item, AVM2Instruction action) {
|
||||
AVM2InstructionItem newItem = new AVM2InstructionItem(action);
|
||||
return insertItemBefore(item, newItem);
|
||||
}
|
||||
|
||||
public final AVM2InstructionItem insertItemAfter(AVM2InstructionItem item, AVM2Instruction action) {
|
||||
AVM2InstructionItem newItem = new AVM2InstructionItem(action);
|
||||
return insertItemAfter(item, newItem);
|
||||
}
|
||||
|
||||
public final AVM2InstructionItem insertItemBefore(AVM2InstructionItem item, AVM2InstructionItem newItem) {
|
||||
insertItemAfter(item.prev, newItem);
|
||||
if (item == firstItem) {
|
||||
firstItem = newItem;
|
||||
}
|
||||
|
||||
return newItem;
|
||||
}
|
||||
|
||||
public final AVM2InstructionItem insertItemAfter(AVM2InstructionItem item, AVM2InstructionItem newItem) {
|
||||
if (item == null && firstItem == null) {
|
||||
firstItem = newItem;
|
||||
newItem.next = newItem;
|
||||
newItem.prev = newItem;
|
||||
} else {
|
||||
if (item == null) {
|
||||
// insert to the end
|
||||
item = firstItem.prev;
|
||||
}
|
||||
|
||||
AVM2InstructionItem oldNext = item.next;
|
||||
newItem.prev = item;
|
||||
newItem.next = oldNext;
|
||||
item.next = newItem;
|
||||
oldNext.prev = newItem;
|
||||
}
|
||||
|
||||
size++;
|
||||
actionItemMap.put(newItem.ins, newItem);
|
||||
actionItemSet.add(newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
public AVM2InstructionItem removeItem(AVM2InstructionItem item) {
|
||||
AVM2InstructionItem next = null;
|
||||
if (item == firstItem) {
|
||||
if (item.next == item) {
|
||||
// there is only 1 item
|
||||
firstItem = null;
|
||||
} else {
|
||||
next = item.next;
|
||||
firstItem = next;
|
||||
next.prev = item.prev;
|
||||
item.prev.next = next;
|
||||
}
|
||||
} else {
|
||||
next = item.next;
|
||||
item.prev.next = next;
|
||||
next.prev = item.prev;
|
||||
}
|
||||
|
||||
size--;
|
||||
actionItemMap.remove(item.ins);
|
||||
actionItemSet.remove(item);
|
||||
|
||||
item.removeJumpTarget();
|
||||
item.removeContainerLastInstructions();
|
||||
|
||||
if (item.jumpsHere != null) {
|
||||
for (AVM2InstructionItem item1 : new ArrayList<>(item.jumpsHere)) {
|
||||
item1.setJumpTarget(item.next);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.lastInsOf != null) {
|
||||
for (AVM2InstructionItem item1 : new ArrayList<>(item.lastInsOf)) {
|
||||
item1.replaceContainerLastInstruction(item, item.prev);
|
||||
}
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
public void removeItem(int index, int count) {
|
||||
FastAVM2ListIterator iterator = new FastAVM2ListIterator(this, index);
|
||||
for (int i = 0; i < count; i++) {
|
||||
iterator.next();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public AVM2InstructionItem get(int index) {
|
||||
FastAVM2ListIterator iterator = new FastAVM2ListIterator(this, index);
|
||||
return iterator.next();
|
||||
}
|
||||
|
||||
public void replaceJumpTargets(AVM2InstructionItem target, AVM2InstructionItem newTarget) {
|
||||
if (target.jumpsHere != null) {
|
||||
for (AVM2InstructionItem item : new ArrayList<>(target.jumpsHere)) {
|
||||
item.setJumpTarget(newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private void getContainerLastActions(AVM2Code actions, Map<AVM2Instruction, AVM2InstructionItem> actionItemMap) {
|
||||
// AVM2InstructionItem item = firstItem;
|
||||
// if (item == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// do {
|
||||
// AVM2Instruction action = item.ins;
|
||||
// if (action instanceof GraphSourceItemContainer) {
|
||||
// item.setContainerLastInstructions(getContainerLastActions(actions, action, actionItemMap));
|
||||
// }
|
||||
//
|
||||
// item = item.next;
|
||||
// } while (item != firstItem);
|
||||
// }
|
||||
// private List<AVM2InstructionItem> getContainerLastActions(AVM2Code actions, AVM2Instruction action, Map<AVM2Instruction, AVM2InstructionItem> actionItemMap) {
|
||||
// GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
// List<Long> sizes = container.getContainerSizes();
|
||||
// long endAddress = action.getAddress() + container.getHeaderSize();
|
||||
// List<AVM2InstructionItem> lasts = new ArrayList<>(sizes.size());
|
||||
// for (long size : sizes) {
|
||||
// endAddress += size;
|
||||
// long lastActionAddress = getNearAddress(actions.code, endAddress - 1, false);
|
||||
// AVM2Instruction lastAction = null;
|
||||
// if (lastActionAddress != -1) {
|
||||
// lastAction = actions.getByAddress(lastActionAddress);
|
||||
// }
|
||||
//
|
||||
// if (lastAction != null) {
|
||||
// lasts.add(actionItemMap.get(lastAction));
|
||||
// } else {
|
||||
// lasts.add(null);
|
||||
// }
|
||||
// }
|
||||
// return lasts;
|
||||
// }
|
||||
private long getNearAddress(List<AVM2Instruction> instructions, long address, boolean next) {
|
||||
int min = 0;
|
||||
int max = instructions.size() - 1;
|
||||
|
||||
while (max >= min) {
|
||||
int mid = (min + max) / 2;
|
||||
long midValue = instructions.get(mid).getAddress();
|
||||
if (midValue == address) {
|
||||
return address;
|
||||
} else if (midValue < address) {
|
||||
min = mid + 1;
|
||||
} else {
|
||||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return next
|
||||
? (min < instructions.size() ? instructions.get(min).getAddress() : -1)
|
||||
: (max >= 0 ? instructions.get(max).getAddress() : -1);
|
||||
}
|
||||
|
||||
private void getJumps(AVM2Code actions, Map<AVM2Instruction, AVM2InstructionItem> actionItemMap) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
AVM2Instruction action = item.ins;
|
||||
long target = -1;
|
||||
if (action.definition instanceof IfTypeIns) {
|
||||
target = action.getTargetAddress();
|
||||
} else if (action.definition instanceof LookupSwitchIns) {
|
||||
// todo
|
||||
}
|
||||
if (target >= 0) {
|
||||
AVM2Instruction targetAction = actions.adr2ins(target);
|
||||
item.setJumpTarget(actionItemMap.get(targetAction));
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
private void updateActionAddressesAndLengths() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long offset = item.ins.getAddress();
|
||||
do {
|
||||
AVM2Instruction action = item.ins;
|
||||
action.setAddress(offset);
|
||||
offset += action.getBytesLength();
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
private void updateJumps() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long endAddress = item.prev.ins.getAddress();
|
||||
do {
|
||||
AVM2Instruction action = item.ins;
|
||||
if (action.definition instanceof IfTypeIns) {
|
||||
AVM2Instruction target = item.getJumpTargetInstruction();
|
||||
long offset;
|
||||
if (target != null) {
|
||||
offset = target.getAddress() - action.getAddress() - action.getBytesLength();
|
||||
} else {
|
||||
offset = endAddress - action.getAddress() - action.getBytesLength();
|
||||
}
|
||||
action.setTargetOffset((int) offset);
|
||||
} else if (action.definition instanceof LookupSwitchIns) {
|
||||
// todo
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
private void updateContainerSizes() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
AVM2Instruction action = item.ins;
|
||||
if (action instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
List<AVM2InstructionItem> lastActions = item.getContainerLastInstructions();
|
||||
long startAddress = action.getAddress() + container.getHeaderSize();
|
||||
for (int j = 0; j < lastActions.size(); j++) {
|
||||
AVM2Instruction lastAction = lastActions.get(j).ins;
|
||||
int length = (int) (lastAction.getAddress() + lastAction.getBytesLength() - startAddress);
|
||||
container.setContainerSize(j, length);
|
||||
startAddress += length;
|
||||
}
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
public AVM2InstructionItem getContainer(AVM2InstructionItem item) {
|
||||
while (!(item.ins instanceof GraphSourceItemContainer) && item != firstItem) {
|
||||
item = item.prev;
|
||||
}
|
||||
|
||||
if (item.ins instanceof GraphSourceItemContainer) {
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeZeroJumps() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
AVM2Instruction ins = item.ins;
|
||||
if (ins.definition instanceof JumpIns) {
|
||||
if (item.getJumpTarget() == item.next && item.getJumpTarget() != firstItem) {
|
||||
item = removeItem(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
public void removeUnreachableActions() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateReachableFlags(null, null);
|
||||
|
||||
do {
|
||||
if (item.reachable == 0) {
|
||||
item = removeItem(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
public void removeIncludedActions() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!item.excluded) {
|
||||
item = removeItem(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
public int getUnreachableActionCount(AVM2InstructionItem jump, AVM2InstructionItem jumpTarget) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateReachableFlags(jump, jumpTarget);
|
||||
jump.reachable = 0;
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
if (item.reachable == 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private void clearReachableFlags() {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
item.reachable = 0;
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
public void setExcludedFlags(boolean value) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
item.excluded = value;
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
|
||||
private void updateReachableFlags(AVM2InstructionItem jump, AVM2InstructionItem jumpTarget) {
|
||||
if (firstItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearReachableFlags();
|
||||
|
||||
firstItem.reachable = 1;
|
||||
AVM2InstructionItem firstItem2 = firstItem;
|
||||
boolean modified = true;
|
||||
while (modified) {
|
||||
modified = false;
|
||||
AVM2InstructionItem item = firstItem2;
|
||||
do {
|
||||
AVM2InstructionItem next = item.next;
|
||||
//AVM2InstructionItem alternativeNext = null;
|
||||
AVM2Instruction action = item.ins;
|
||||
if (item.reachable == 1) {
|
||||
item.reachable = 2;
|
||||
modified = true;
|
||||
|
||||
if (item == firstItem2) {
|
||||
firstItem2 = next;
|
||||
}
|
||||
|
||||
if (item == jump) {
|
||||
if (jumpTarget.reachable == 0) {
|
||||
jumpTarget.reachable = 1;
|
||||
//alternativeNext = jumpTarget;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!action.isExit() && !(action.definition instanceof JumpIns)) {
|
||||
if (next.reachable == 0) {
|
||||
next.reachable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof GraphSourceItemContainer) {
|
||||
for (AVM2InstructionItem lastActionItem : item.getContainerLastInstructions()) {
|
||||
if (lastActionItem != null && lastActionItem.next != null && lastActionItem.next.reachable == 0) {
|
||||
lastActionItem.next.reachable = 1;
|
||||
//alternativeNext = lastActionItem.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AVM2InstructionItem target = item.getJumpTarget();
|
||||
if (target != null) {
|
||||
if (target.reachable == 0) {
|
||||
target.reachable = 1;
|
||||
//alternativeNext = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//item = alternativeNext == null || next.reachable == 1 ? next : alternativeNext;
|
||||
item = next;
|
||||
} while (item != firstItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateActions(MethodBody body) {
|
||||
AVM2Code result = new AVM2Code(size);
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
body.setCode(result);
|
||||
body.exceptions = new ABCException[0];
|
||||
return;
|
||||
}
|
||||
|
||||
List<AVM2Instruction> resultList = result.code;
|
||||
do {
|
||||
resultList.add(item.ins);
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
|
||||
updateActionAddressesAndLengths();
|
||||
updateJumps();
|
||||
updateContainerSizes();
|
||||
}
|
||||
|
||||
public AVM2InstructionItem first() {
|
||||
return firstItem;
|
||||
}
|
||||
|
||||
public AVM2InstructionItem last() {
|
||||
return firstItem == null ? null : firstItem.prev;
|
||||
}
|
||||
|
||||
public void toMethodBody(MethodBody body) {
|
||||
updateActions(body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof AVM2InstructionItem) {
|
||||
return actionItemSet.contains(o);
|
||||
} else if (o instanceof AVM2Instruction) {
|
||||
return actionItemMap.containsKey((AVM2Instruction) o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAVM2ListIterator iterator() {
|
||||
return new FastAVM2ListIterator(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] result = new Object[size];
|
||||
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
result[i] = item.ins;
|
||||
item = item.next;
|
||||
i++;
|
||||
} while (item != firstItem);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
if (a.length != size) {
|
||||
a = (T[]) new AVM2InstructionItem[size];
|
||||
}
|
||||
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return a;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
a[i] = (T) item;
|
||||
item = item.next;
|
||||
i++;
|
||||
} while (item != firstItem);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(AVM2InstructionItem e) {
|
||||
insertItemAfter(null, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
AVM2InstructionItem item = null;
|
||||
if (o instanceof AVM2InstructionItem) {
|
||||
item = (AVM2InstructionItem) o;
|
||||
} else if (o instanceof AVM2Instruction) {
|
||||
item = actionItemMap.get((AVM2Instruction) o);
|
||||
}
|
||||
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeItem(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object c1 : c) {
|
||||
if (!contains(c1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends AVM2InstructionItem> c) {
|
||||
for (AVM2InstructionItem c1 : c) {
|
||||
insertItemAfter(null, c1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
boolean result = false;
|
||||
for (Object c1 : c) {
|
||||
result |= remove(c1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
AVM2InstructionItem item = firstItem;
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean modified = false;
|
||||
do {
|
||||
if (!c.contains(item)) {
|
||||
item = removeItem(item);
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item != firstItem);
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
firstItem = null;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 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.fastavm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public final class FastAVM2ListIterator implements Iterator<AVM2InstructionItem> {
|
||||
|
||||
private AVM2InstructionItem item;
|
||||
|
||||
private final FastAVM2List list;
|
||||
|
||||
private boolean started = false;
|
||||
|
||||
FastAVM2ListIterator(FastAVM2List list) {
|
||||
item = list.first();
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
FastAVM2ListIterator(FastAVM2List list, int index) {
|
||||
item = list.first();
|
||||
this.list = list;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (!hasNext()) {
|
||||
throw new Error("Invalid index");
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return item != null && (!started || item != list.first());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AVM2InstructionItem next() {
|
||||
AVM2InstructionItem result = item;
|
||||
item = item.next;
|
||||
started = true;
|
||||
/*if (!list.contains(result)) {
|
||||
throw new Error();
|
||||
}*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public AVM2InstructionItem prev() {
|
||||
item = item.prev;
|
||||
if (item == list.first()) {
|
||||
started = false;
|
||||
}
|
||||
|
||||
/*if (!list.contains(item)) {
|
||||
throw new Error();
|
||||
}*/
|
||||
return item;
|
||||
}
|
||||
|
||||
public void setCurrent(AVM2InstructionItem item) {
|
||||
this.item = item;
|
||||
if (item == list.first()) {
|
||||
started = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
item = list.removeItem(item.prev);
|
||||
}
|
||||
|
||||
public void add(AVM2Instruction ins) {
|
||||
item = list.insertItemAfter(item.prev, ins).next;
|
||||
}
|
||||
|
||||
public void add(AVM2InstructionItem insItem) {
|
||||
item = list.insertItemAfter(item.prev, insItem).next;
|
||||
}
|
||||
|
||||
public void addBefore(AVM2InstructionItem insItem) {
|
||||
list.insertItemBefore(item.prev, insItem);
|
||||
}
|
||||
|
||||
public AVM2InstructionItem peek(int index) {
|
||||
AVM2InstructionItem item = this.item;
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (item == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user