From 6e358d3eabdf94b91a345ae193004ff506e0b997 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 28 Jul 2018 22:07:39 +0300 Subject: [PATCH] core: use own immutable list --- .../java/jadx/core/dex/nodes/BlockNode.java | 9 +- .../java/jadx/core/dex/nodes/MethodNode.java | 25 +- .../java/jadx/core/utils/ImmutableList.java | 220 ++++++++++++++++++ .../src/main/java/jadx/core/utils/Utils.java | 13 ++ 4 files changed, 243 insertions(+), 24 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/core/utils/ImmutableList.java diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java index 235d77c0e..003d5f22c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/BlockNode.java @@ -15,6 +15,8 @@ import jadx.core.utils.BlockUtils; import jadx.core.utils.EmptyBitSet; import jadx.core.utils.InsnUtils; +import static jadx.core.utils.Utils.lockList; + public class BlockNode extends AttrNode implements IBlock { private int id; @@ -70,13 +72,6 @@ public class BlockNode extends AttrNode implements IBlock { dominatesOn = lockList(dominatesOn); } - List lockList(List list) { - if (list.isEmpty()) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(list); - } - /** * Return all successor which are not exception handler or followed by loop back edge */ diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index cb48bec2e..e89d77566 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -43,6 +43,8 @@ import jadx.core.utils.Utils; import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.JadxRuntimeException; +import static jadx.core.utils.Utils.lockList; + public class MethodNode extends LineAttrNode implements ILoadable, IDexNode { private static final Logger LOG = LoggerFactory.getLogger(MethodNode.class); @@ -154,10 +156,10 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode { blocks = null; enterBlock = null; exitBlocks = null; - exceptionHandlers.clear(); + exceptionHandlers = Collections.emptyList(); sVars.clear(); region = null; - loops.clear(); + loops = Collections.emptyList(); } private boolean parseSignature() { @@ -407,21 +409,10 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode { } public void finishBasicBlocks() { - trimList(blocks); - trimList(exitBlocks); - - blocks = Collections.unmodifiableList(blocks); - exitBlocks = Collections.unmodifiableList(exitBlocks); - - for (BlockNode block : blocks) { - block.lock(); - } - } - - private void trimList(List blocks) { - if (blocks instanceof ArrayList) { - ((ArrayList)blocks).trimToSize(); - } + blocks = lockList(blocks); + exitBlocks = lockList(exitBlocks); + loops = lockList(loops); + blocks.forEach(BlockNode::lock); } public List getBasicBlocks() { diff --git a/jadx-core/src/main/java/jadx/core/utils/ImmutableList.java b/jadx-core/src/main/java/jadx/core/utils/ImmutableList.java new file mode 100644 index 000000000..04965d019 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/utils/ImmutableList.java @@ -0,0 +1,220 @@ +package jadx.core.utils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; +import java.util.RandomAccess; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import org.jetbrains.annotations.NotNull; + +/** + * Simple immutable list implementation + * Warning: some methods not implemented! + */ +public final class ImmutableList implements List, RandomAccess { + private final E[] arr; + + @SuppressWarnings("unchecked") + public ImmutableList(Object[] arr) { + this.arr = (E[]) Objects.requireNonNull(arr); + } + + @Override + public int size() { + return arr.length; + } + + @Override + public boolean isEmpty() { + return arr.length == 0; + } + + @Override + public E get(int index) { + return arr[index]; + } + + @Override + public int indexOf(Object o) { + int len = arr.length; + for (int i = 0; i < len; i++) { + E e = arr[i]; + if (Objects.equals(e, o)) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + for (int i = arr.length - 1; i > 0; i--) { + E e = arr[i]; + if (Objects.equals(e, o)) { + return i; + } + } + return -1; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + @Override + public boolean containsAll(@NotNull Collection c) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Iterator iterator() { + return new Iterator() { + private int index = 0; + private int len = arr.length; + + @Override + public boolean hasNext() { + return index < len; + } + + @Override + public E next() { + return arr[index++]; + } + }; + } + + @Override + public void forEach(Consumer action) { + for (E e : arr) { + action.accept(e); + } + } + + @NotNull + @Override + public Object[] toArray() { + return arr; + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public T[] toArray(@NotNull T[] a) { + return (T[]) arr; + } + + @Override + public boolean add(E e) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(@NotNull Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(int index, @NotNull Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(@NotNull Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(@NotNull Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(UnaryOperator operator) { + throw new UnsupportedOperationException(); + } + + @Override + public void sort(Comparator c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeIf(Predicate filter) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public E set(int index, E element) { + throw new UnsupportedOperationException(); + } + + @Override + public void add(int index, E element) { + throw new UnsupportedOperationException(); + } + + @Override + public E remove(int index) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public ListIterator listIterator() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public ListIterator listIterator(int index) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public List subList(int fromIndex, int toIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ImmutableList that = (ImmutableList) o; + return Arrays.equals(arr, that.arr); + } + + @Override + public int hashCode() { + return Arrays.hashCode(arr); + } + + @Override + public String toString() { + return "ImmutableList{" + Arrays.toString(arr) + '}'; + } +} diff --git a/jadx-core/src/main/java/jadx/core/utils/Utils.java b/jadx-core/src/main/java/jadx/core/utils/Utils.java index 87dd77e72..f8e02fac8 100644 --- a/jadx-core/src/main/java/jadx/core/utils/Utils.java +++ b/jadx-core/src/main/java/jadx/core/utils/Utils.java @@ -3,7 +3,9 @@ package jadx.core.utils; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.function.Function; import jadx.api.JadxDecompiler; @@ -107,4 +109,15 @@ public class Utils { th.setStackTrace(Arrays.copyOfRange(stackTrace, 0, cutIndex)); } } + + @SuppressWarnings("unchecked") + public static List lockList(List list) { + if (list.isEmpty()) { + return Collections.emptyList(); + } + if (list.size() == 1) { + return Collections.singletonList(list.get(0)); + } + return new ImmutableList<>(list.toArray()); + } }