diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java index 655c0b8f1..991aab147 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionList.java @@ -1,759 +1,762 @@ -/* - * 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.action.fastactionlist; - -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.special.ActionStore; -import com.jpexs.decompiler.flash.action.special.ActionUnknown; -import com.jpexs.decompiler.flash.action.swf4.ActionIf; -import com.jpexs.decompiler.flash.action.swf4.ActionJump; -import com.jpexs.decompiler.flash.action.swf4.ActionPush; -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 FastActionList implements Collection { - - private int size; - - private ActionItem firstItem; - - private final Map actionItemMap; - - private final Set actionItemSet; - - public FastActionList(ActionList actions) { - actionItemMap = new HashMap<>(actions.size()); - actionItemSet = new HashSet<>(actions.size()); - for (Action action : actions) { - insertItemAfter(null, action); - } - - size = actions.size(); - getContainerLastActions(actions, actionItemMap); - getJumps(actions, actionItemMap); - } - - public final ActionItem insertItemBefore(ActionItem item, Action action) { - ActionItem newItem = new ActionItem(action); - return insertItemBefore(item, newItem); - } - - public final ActionItem insertItemAfter(ActionItem item, Action action) { - ActionItem newItem = new ActionItem(action); - return insertItemAfter(item, newItem); - } - - public final ActionItem insertItemBefore(ActionItem item, ActionItem newItem) { - insertItemAfter(item.prev, newItem); - if (item == firstItem) { - firstItem = newItem; - } - - return newItem; - } - - public final ActionItem insertItemAfter(ActionItem item, ActionItem 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; - } - - ActionItem oldNext = item.next; - newItem.prev = item; - newItem.next = oldNext; - item.next = newItem; - oldNext.prev = newItem; - } - - size++; - actionItemMap.put(newItem.action, newItem); - actionItemSet.add(newItem); - return newItem; - } - - public ActionItem removeItem(ActionItem item) { - ActionItem 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.action); - actionItemSet.remove(item); - - item.removeJumpTarget(); - item.removeContainerLastActions(); - - if (item.jumpsHere != null) { - for (ActionItem item1 : new ArrayList<>(item.jumpsHere)) { - item1.setJumpTarget(item.next); - } - } - - if (item.lastActionOf != null) { - for (ActionItem item1 : new ArrayList<>(item.lastActionOf)) { - item1.replaceContainerLastAction(item, item.prev); - } - } - - return next; - } - - public void removeItem(int index, int count) { - FastActionListIterator iterator = new FastActionListIterator(this, index); - for (int i = 0; i < count; i++) { - iterator.next(); - iterator.remove(); - } - } - - public ActionItem get(int index) { - FastActionListIterator iterator = new FastActionListIterator(this, index); - return iterator.next(); - } - - public void replaceJumpTargets(ActionItem target, ActionItem newTarget) { - if (target.jumpsHere != null) { - for (ActionItem item : new ArrayList<>(target.jumpsHere)) { - item.setJumpTarget(newTarget); - } - } - } - - private void getContainerLastActions(ActionList actions, Map actionItemMap) { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof GraphSourceItemContainer) { - item.setContainerLastActions(getContainerLastActions(actions, action, actionItemMap)); - } - - item = item.next; - } while (item != firstItem); - } - - private List getContainerLastActions(ActionList actions, Action action, Map actionItemMap) { - GraphSourceItemContainer container = (GraphSourceItemContainer) action; - List sizes = container.getContainerSizes(); - long endAddress = action.getAddress() + container.getHeaderSize(); - List lasts = new ArrayList<>(sizes.size()); - for (long size : sizes) { - endAddress += size; - long lastActionAddress = getNearAddress(actions, endAddress - 1, false); - Action 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(ActionList actions, long address, boolean next) { - int min = 0; - int max = actions.size() - 1; - - while (max >= min) { - int mid = (min + max) / 2; - long midValue = actions.get(mid).getAddress(); - if (midValue == address) { - return address; - } else if (midValue < address) { - min = mid + 1; - } else { - max = mid - 1; - } - } - - return next - ? (min < actions.size() ? actions.get(min).getAddress() : -1) - : (max >= 0 ? actions.get(max).getAddress() : -1); - } - - private void getJumps(ActionList actions, Map actionItemMap) { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - long target = -1; - if (action instanceof ActionIf) { - target = ((ActionIf) action).getTargetAddress(); - } else if (action instanceof ActionJump) { - target = ((ActionJump) action).getTargetAddress(); - } else if (action instanceof ActionStore) { - ActionStore aStore = (ActionStore) action; - int storeSize = aStore.getStoreSize(); - // skip storeSize + 1 actions (+1 is the current action) - Action targetAction = action; - for (int i = 0; i <= storeSize; i++) { - long address = targetAction.getAddress() + targetAction.getTotalActionLength(); - targetAction = actions.getByAddress(address); - if (targetAction == null) { - break; - } - } - - item.setJumpTarget(actionItemMap.get(targetAction)); - } - if (target >= 0) { - Action targetAction = actions.getByAddress(target); - item.setJumpTarget(actionItemMap.get(targetAction)); - } - - item = item.next; - } while (item != firstItem); - } - - private void updateActionAddressesAndLengths() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - long address = item.action.getAddress(); - do { - Action action = item.action; - action.setAddress(address); - action.updateLength(); - address += action.getTotalActionLength(); - item = item.next; - } while (item != firstItem); - } - - private void updateJumps() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - long endAddress = item.prev.action.getAddress(); - do { - Action action = item.action; - if (action instanceof ActionIf) { - ActionIf aIf = (ActionIf) action; - Action target = item.getJumpTargetAction(); - long offset; - if (target != null) { - offset = target.getAddress() - action.getAddress() - action.getTotalActionLength(); - } else { - offset = endAddress - action.getAddress() - action.getTotalActionLength(); - } - aIf.setJumpOffset((int) offset); - } else if (action instanceof ActionJump) { - ActionJump aJump = (ActionJump) action; - Action target = item.getJumpTargetAction(); - long offset; - if (target != null) { - offset = target.getAddress() - action.getAddress() - action.getTotalActionLength(); - } else { - offset = endAddress - action.getAddress() - action.getTotalActionLength(); - } - aJump.setJumpOffset((int) offset); - } - - item = item.next; - } while (item != firstItem); - } - - private void updateActionStores() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof ActionStore) { - ActionStore aStore = (ActionStore) action; - Action nextActionAfterStore = item.getJumpTargetAction(); - ActionItem item1 = item; - List store = new ArrayList<>(); - while (true) { - item1 = item1.next; - if (item1 == firstItem || item1.action == nextActionAfterStore) { - break; - } - - store.add(item1.action); - } - - aStore.setStore(store); - } - - item = item.next; - } while (item != firstItem); - } - - private void updateContainerSizes() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof GraphSourceItemContainer) { - GraphSourceItemContainer container = (GraphSourceItemContainer) action; - List lastActions = item.getContainerLastActions(); - long startAddress = action.getAddress() + container.getHeaderSize(); - for (int j = 0; j < lastActions.size(); j++) { - Action lastAction = lastActions.get(j).action; - int length = (int) (lastAction.getAddress() + lastAction.getTotalActionLength() - startAddress); - container.setContainerSize(j, length); - startAddress += length; - } - } - - item = item.next; - } while (item != firstItem); - } - - public ActionItem getContainer(ActionItem item) { - while (!(item.action instanceof GraphSourceItemContainer) && item != firstItem) { - item = item.prev; - } - - if (item.action instanceof GraphSourceItemContainer) { - return item; - } - - return null; - } - - public void expandPushes() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof ActionPush) { - ActionPush push = (ActionPush) action; - if (push.values.size() > 1) { - for (int i = 1; i < push.values.size(); i++) { - Object value = push.values.get(i); - ActionPush newPush = new ActionPush(value); - newPush.constantPool = push.constantPool; - insertItemAfter(item, newPush); - item = item.next; - } - - Object obj = push.values.get(0); - push.values.clear(); - push.values.add(obj); - } - } - - item = item.next; - } while (item != firstItem); - } - - public void removeUnknownActions() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof ActionUnknown) { - item = removeItem(item); - continue; - } - - item = item.next; - } while (item != firstItem); - } - - public void removeZeroJumps() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - Action action = item.action; - if (action instanceof ActionJump) { - if (item.getJumpTarget() == item.next && item.getJumpTarget() != firstItem) { - item = removeItem(item); - continue; - } - } - - item = item.next; - } while (item != firstItem); - } - - public void removeUnreachableActions() { - ActionItem 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() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - if (!item.excluded) { - item = removeItem(item); - continue; - } - - item = item.next; - } while (item != firstItem); - } - - public int getUnreachableActionCount(ActionItem jump, ActionItem jumpTarget) { - ActionItem 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() { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - item.reachable = 0; - item = item.next; - } while (item != firstItem); - } - - public void setExcludedFlags(boolean value) { - ActionItem item = firstItem; - if (item == null) { - return; - } - - do { - item.excluded = value; - item = item.next; - } while (item != firstItem); - } - - private void updateReachableFlags(ActionItem jump, ActionItem jumpTarget) { - if (firstItem == null) { - return; - } - - clearReachableFlags(); - - firstItem.reachable = 1; - ActionItem firstItem2 = firstItem; - boolean modified = true; - while (modified) { - modified = false; - ActionItem item = firstItem2; - do { - ActionItem next = item.next; - //ActionItem alternativeNext = null; - Action action = item.action; - 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 instanceof ActionJump)) { - if (next.reachable == 0) { - next.reachable = 1; - } - } - - if (action instanceof GraphSourceItemContainer) { - for (ActionItem lastActionItem : item.getContainerLastActions()) { - if (lastActionItem != null && lastActionItem.next != null && lastActionItem.next.reachable == 0) { - lastActionItem.next.reachable = 1; - //alternativeNext = lastActionItem.next; - } - } - } - - ActionItem 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 ActionList updateActions() { - List resultList = new ArrayList<>(size); - ActionItem item = firstItem; - if (item == null) { - return new ActionList(resultList); - } - - do { - resultList.add(item.action); - item = item.next; - } while (item != firstItem); - - ActionList result = new ActionList(resultList); - updateActionAddressesAndLengths(); - updateJumps(); - updateActionStores(); - updateContainerSizes(); - return result; - } - - public ActionItem first() { - return firstItem; - } - - public ActionItem last() { - return firstItem == null ? null : firstItem.prev; - } - - public ActionList toActionList() { - return updateActions(); - } - - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return size == 0; - } - - @Override - public boolean contains(Object o) { - if (o instanceof ActionItem) { - return actionItemSet.contains(o); - } else if (o instanceof Action) { - return actionItemMap.containsKey((Action) o); - } - - return false; - } - - @Override - public FastActionListIterator iterator() { - return new FastActionListIterator(this); - } - - @Override - public Object[] toArray() { - Object[] result = new Object[size]; - - ActionItem item = firstItem; - if (item == null) { - return result; - } - - int i = 0; - do { - result[i] = item.action; - item = item.next; - i++; - } while (item != firstItem); - return null; - } - - @Override - @SuppressWarnings("unchecked") - public T[] toArray(T[] a) { - if (a.length != size) { - a = (T[]) new ActionItem[size]; - } - - ActionItem 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(ActionItem e) { - insertItemAfter(null, e); - return true; - } - - @Override - public boolean remove(Object o) { - ActionItem item = null; - if (o instanceof ActionItem) { - item = (ActionItem) o; - } else if (o instanceof Action) { - item = actionItemMap.get((Action) 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 c) { - for (ActionItem 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) { - ActionItem 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; - } -} +/* + * 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.action.fastactionlist; + +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.special.ActionStore; +import com.jpexs.decompiler.flash.action.special.ActionUnknown; +import com.jpexs.decompiler.flash.action.swf4.ActionIf; +import com.jpexs.decompiler.flash.action.swf4.ActionJump; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +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 FastActionList implements Collection { + + private int size; + + private ActionItem firstItem; + + private final Map actionItemMap; + + private final Set actionItemSet; + + public FastActionList(ActionList actions) { + actionItemMap = new HashMap<>(actions.size()); + actionItemSet = new HashSet<>(actions.size()); + for (Action action : actions) { + insertItemAfter(null, action); + } + + size = actions.size(); + getContainerLastActions(actions, actionItemMap); + getJumps(actions, actionItemMap); + } + + public final ActionItem insertItemBefore(ActionItem item, Action action) { + ActionItem newItem = new ActionItem(action); + return insertItemBefore(item, newItem); + } + + public final ActionItem insertItemAfter(ActionItem item, Action action) { + ActionItem newItem = new ActionItem(action); + return insertItemAfter(item, newItem); + } + + public final ActionItem insertItemBefore(ActionItem item, ActionItem newItem) { + insertItemAfter(item.prev, newItem); + if (item == firstItem) { + firstItem = newItem; + } + + return newItem; + } + + public final ActionItem insertItemAfter(ActionItem item, ActionItem 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; + } + + ActionItem oldNext = item.next; + newItem.prev = item; + newItem.next = oldNext; + item.next = newItem; + oldNext.prev = newItem; + } + + size++; + actionItemMap.put(newItem.action, newItem); + actionItemSet.add(newItem); + return newItem; + } + + public ActionItem removeItem(ActionItem item) { + ActionItem 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.action); + actionItemSet.remove(item); + + item.removeJumpTarget(); + item.removeContainerLastActions(); + + if (item.jumpsHere != null) { + for (ActionItem item1 : new ArrayList<>(item.jumpsHere)) { + item1.setJumpTarget(item.next); + } + } + + if (item.lastActionOf != null) { + for (ActionItem item1 : new ArrayList<>(item.lastActionOf)) { + item1.replaceContainerLastAction(item, item.prev); + } + } + + return next; + } + + public void removeItem(int index, int count) { + FastActionListIterator iterator = new FastActionListIterator(this, index); + for (int i = 0; i < count; i++) { + iterator.next(); + iterator.remove(); + } + } + + public ActionItem get(int index) { + FastActionListIterator iterator = new FastActionListIterator(this, index); + return iterator.next(); + } + + public void replaceJumpTargets(ActionItem target, ActionItem newTarget) { + if (target.jumpsHere != null) { + for (ActionItem item : new ArrayList<>(target.jumpsHere)) { + item.setJumpTarget(newTarget); + } + } + } + + private void getContainerLastActions(ActionList actions, Map actionItemMap) { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof GraphSourceItemContainer) { + item.setContainerLastActions(getContainerLastActions(actions, action, actionItemMap)); + } + + item = item.next; + } while (item != firstItem); + } + + private List getContainerLastActions(ActionList actions, Action action, Map actionItemMap) { + GraphSourceItemContainer container = (GraphSourceItemContainer) action; + List sizes = container.getContainerSizes(); + long endAddress = action.getAddress() + container.getHeaderSize(); + List lasts = new ArrayList<>(sizes.size()); + for (long size : sizes) { + endAddress += size; + long lastActionAddress = getNearAddress(actions, endAddress - 1, false); + Action 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(ActionList actions, long address, boolean next) { + int min = 0; + int max = actions.size() - 1; + + while (max >= min) { + int mid = (min + max) / 2; + long midValue = actions.get(mid).getAddress(); + if (midValue == address) { + return address; + } else if (midValue < address) { + min = mid + 1; + } else { + max = mid - 1; + } + } + + return next + ? (min < actions.size() ? actions.get(min).getAddress() : -1) + : (max >= 0 ? actions.get(max).getAddress() : -1); + } + + private void getJumps(ActionList actions, Map actionItemMap) { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + long target = -1; + if (action instanceof ActionIf) { + target = ((ActionIf) action).getTargetAddress(); + } else if (action instanceof ActionJump) { + target = ((ActionJump) action).getTargetAddress(); + } else if (action instanceof ActionStore) { + ActionStore aStore = (ActionStore) action; + int storeSize = aStore.getStoreSize(); + // skip storeSize + 1 actions (+1 is the current action) + Action targetAction = action; + for (int i = 0; i <= storeSize; i++) { + long address = targetAction.getAddress() + targetAction.getTotalActionLength(); + targetAction = actions.getByAddress(address); + if (targetAction == null) { + break; + } + } + + item.setJumpTarget(actionItemMap.get(targetAction)); + } + if (target >= 0) { + Action targetAction = actions.getByAddress(target); + item.setJumpTarget(actionItemMap.get(targetAction)); + } + + item = item.next; + } while (item != firstItem); + } + + private void updateActionAddressesAndLengths() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + long address = item.action.getAddress(); + do { + Action action = item.action; + action.setAddress(address); + action.updateLength(); + address += action.getTotalActionLength(); + item = item.next; + } while (item != firstItem); + } + + private void updateJumps() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + long endAddress = item.prev.action.getAddress(); + do { + Action action = item.action; + if (action instanceof ActionIf) { + ActionIf aIf = (ActionIf) action; + Action target = item.getJumpTargetAction(); + long offset; + if (target != null) { + offset = target.getAddress() - action.getAddress() - action.getTotalActionLength(); + } else { + offset = endAddress - action.getAddress() - action.getTotalActionLength(); + } + aIf.setJumpOffset((int) offset); + } else if (action instanceof ActionJump) { + ActionJump aJump = (ActionJump) action; + Action target = item.getJumpTargetAction(); + long offset; + if (target != null) { + offset = target.getAddress() - action.getAddress() - action.getTotalActionLength(); + } else { + offset = endAddress - action.getAddress() - action.getTotalActionLength(); + } + aJump.setJumpOffset((int) offset); + } + + item = item.next; + } while (item != firstItem); + } + + private void updateActionStores() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof ActionStore) { + ActionStore aStore = (ActionStore) action; + Action nextActionAfterStore = item.getJumpTargetAction(); + ActionItem item1 = item; + List store = new ArrayList<>(); + while (true) { + item1 = item1.next; + if (item1 == firstItem || item1.action == nextActionAfterStore) { + break; + } + + store.add(item1.action); + } + + aStore.setStore(store); + } + + item = item.next; + } while (item != firstItem); + } + + private void updateContainerSizes() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof GraphSourceItemContainer) { + GraphSourceItemContainer container = (GraphSourceItemContainer) action; + List lastActions = item.getContainerLastActions(); + long startAddress = action.getAddress() + container.getHeaderSize(); + for (int j = 0; j < lastActions.size(); j++) { + Action lastAction = lastActions.get(j).action; + int length = (int) (lastAction.getAddress() + lastAction.getTotalActionLength() - startAddress); + container.setContainerSize(j, length); + startAddress += length; + } + } + + item = item.next; + } while (item != firstItem); + } + + public ActionItem getContainer(ActionItem item) { + while (!(item.action instanceof GraphSourceItemContainer) && item != firstItem) { + item = item.prev; + } + + if (item.action instanceof GraphSourceItemContainer) { + return item; + } + + return null; + } + + public void expandPushes() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof ActionPush) { + ActionPush push = (ActionPush) action; + if (push.values.size() > 1) { + for (int i = 1; i < push.values.size(); i++) { + Object value = push.values.get(i); + ActionPush newPush = new ActionPush(value); + newPush.constantPool = push.constantPool; + insertItemAfter(item, newPush); + item = item.next; + } + + Object obj = push.values.get(0); + push.values.clear(); + push.values.add(obj); + } + } + + item = item.next; + } while (item != firstItem); + } + + public void removeUnknownActions() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof ActionUnknown) { + item = removeItem(item); + continue; + } + + item = item.next; + } while (item != firstItem); + } + + public void removeZeroJumps() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + Action action = item.action; + if (action instanceof ActionJump) { + if (item.getJumpTarget() == item.next && item.getJumpTarget() != firstItem) { + item = removeItem(item); + continue; + } + } + + item = item.next; + } while (item != firstItem); + } + + public void removeUnreachableActions() { + ActionItem 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() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + while (true) { + if (!item.excluded) { + item = removeItem(item); + continue; + } + + item = item.next; + if (item == firstItem) { + break; + } + } + } + + public int getUnreachableActionCount(ActionItem jump, ActionItem jumpTarget) { + ActionItem 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() { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + item.reachable = 0; + item = item.next; + } while (item != firstItem); + } + + public void setExcludedFlags(boolean value) { + ActionItem item = firstItem; + if (item == null) { + return; + } + + do { + item.excluded = value; + item = item.next; + } while (item != firstItem); + } + + private void updateReachableFlags(ActionItem jump, ActionItem jumpTarget) { + if (firstItem == null) { + return; + } + + clearReachableFlags(); + + firstItem.reachable = 1; + ActionItem firstItem2 = firstItem; + boolean modified = true; + while (modified) { + modified = false; + ActionItem item = firstItem2; + do { + ActionItem next = item.next; + //ActionItem alternativeNext = null; + Action action = item.action; + 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 instanceof ActionJump)) { + if (next.reachable == 0) { + next.reachable = 1; + } + } + + if (action instanceof GraphSourceItemContainer) { + for (ActionItem lastActionItem : item.getContainerLastActions()) { + if (lastActionItem != null && lastActionItem.next != null && lastActionItem.next.reachable == 0) { + lastActionItem.next.reachable = 1; + //alternativeNext = lastActionItem.next; + } + } + } + + ActionItem 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 ActionList updateActions() { + List resultList = new ArrayList<>(size); + ActionItem item = firstItem; + if (item == null) { + return new ActionList(resultList); + } + + do { + resultList.add(item.action); + item = item.next; + } while (item != firstItem); + + ActionList result = new ActionList(resultList); + updateActionAddressesAndLengths(); + updateJumps(); + updateActionStores(); + updateContainerSizes(); + return result; + } + + public ActionItem first() { + return firstItem; + } + + public ActionItem last() { + return firstItem == null ? null : firstItem.prev; + } + + public ActionList toActionList() { + return updateActions(); + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + @Override + public boolean contains(Object o) { + if (o instanceof ActionItem) { + return actionItemSet.contains(o); + } else if (o instanceof Action) { + return actionItemMap.containsKey((Action) o); + } + + return false; + } + + @Override + public FastActionListIterator iterator() { + return new FastActionListIterator(this); + } + + @Override + public Object[] toArray() { + Object[] result = new Object[size]; + + ActionItem item = firstItem; + if (item == null) { + return result; + } + + int i = 0; + do { + result[i] = item.action; + item = item.next; + i++; + } while (item != firstItem); + return null; + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + if (a.length != size) { + a = (T[]) new ActionItem[size]; + } + + ActionItem 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(ActionItem e) { + insertItemAfter(null, e); + return true; + } + + @Override + public boolean remove(Object o) { + ActionItem item = null; + if (o instanceof ActionItem) { + item = (ActionItem) o; + } else if (o instanceof Action) { + item = actionItemMap.get((Action) 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 c) { + for (ActionItem 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) { + ActionItem 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; + } +}