summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/InterpreterPair.java')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/InterpreterPair.java138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java b/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
new file mode 100644
index 0000000..af74c85
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
@@ -0,0 +1,138 @@
1package cuchaz.enigma.analysis;
2
3import org.objectweb.asm.Opcodes;
4import org.objectweb.asm.Type;
5import org.objectweb.asm.tree.AbstractInsnNode;
6import org.objectweb.asm.tree.analysis.AnalyzerException;
7import org.objectweb.asm.tree.analysis.Interpreter;
8import org.objectweb.asm.tree.analysis.Value;
9
10import java.util.List;
11import java.util.Objects;
12import java.util.stream.Collectors;
13
14public class InterpreterPair<V extends Value, W extends Value> extends Interpreter<InterpreterPair.PairValue<V, W>> {
15 private final Interpreter<V> left;
16 private final Interpreter<W> right;
17
18 public InterpreterPair(Interpreter<V> left, Interpreter<W> right) {
19 super(Opcodes.ASM7);
20 this.left = left;
21 this.right = right;
22 }
23
24 @Override
25 public PairValue<V, W> newValue(Type type) {
26 return pair(
27 left.newValue(type),
28 right.newValue(type)
29 );
30 }
31
32 @Override
33 public PairValue<V, W> newOperation(AbstractInsnNode insn) throws AnalyzerException {
34 return pair(
35 left.newOperation(insn),
36 right.newOperation(insn)
37 );
38 }
39
40 @Override
41 public PairValue<V, W> copyOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException {
42 return pair(
43 left.copyOperation(insn, value.left),
44 right.copyOperation(insn, value.right)
45 );
46 }
47
48 @Override
49 public PairValue<V, W> unaryOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException {
50 return pair(
51 left.unaryOperation(insn, value.left),
52 right.unaryOperation(insn, value.right)
53 );
54 }
55
56 @Override
57 public PairValue<V, W> binaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2) throws AnalyzerException {
58 return pair(
59 left.binaryOperation(insn, value1.left, value2.left),
60 right.binaryOperation(insn, value1.right, value2.right)
61 );
62 }
63
64 @Override
65 public PairValue<V, W> ternaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2, PairValue<V, W> value3) throws AnalyzerException {
66 return pair(
67 left.ternaryOperation(insn, value1.left, value2.left, value3.left),
68 right.ternaryOperation(insn, value1.right, value2.right, value3.right)
69 );
70 }
71
72 @Override
73 public PairValue<V, W> naryOperation(AbstractInsnNode insn, List<? extends PairValue<V, W>> values) throws AnalyzerException {
74 return pair(
75 left.naryOperation(insn, values.stream().map(v -> v.left).collect(Collectors.toList())),
76 right.naryOperation(insn, values.stream().map(v -> v.right).collect(Collectors.toList()))
77 );
78 }
79
80 @Override
81 public void returnOperation(AbstractInsnNode insn, PairValue<V, W> value, PairValue<V, W> expected) throws AnalyzerException {
82 left.returnOperation(insn, value.left, expected.left);
83 right.returnOperation(insn, value.right, expected.right);
84 }
85
86 @Override
87 public PairValue<V, W> merge(PairValue<V, W> value1, PairValue<V, W> value2) {
88 return pair(
89 left.merge(value1.left, value2.left),
90 right.merge(value1.right, value2.right)
91 );
92 }
93
94 private PairValue<V, W> pair(V left, W right) {
95 if (left == null && right == null) {
96 return null;
97 }
98
99 if (left != null && right != null && left.getSize() != right.getSize()) {
100 throw new IllegalStateException("sizes don't match");
101 }
102
103 return new PairValue<>(left, right);
104 }
105
106 public static final class PairValue<V extends Value, W extends Value> implements Value {
107 public final V left;
108 public final W right;
109
110 public PairValue(V left, W right) {
111 if (left == null && right == null) {
112 throw new IllegalArgumentException("should use null rather than pair of nulls");
113 }
114
115 if (left != null && right != null && left.getSize() != right.getSize()) {
116 throw new IllegalArgumentException("sizes don't match");
117 }
118
119 this.left = left;
120 this.right = right;
121 }
122
123 @Override
124 public boolean equals(Object o) {
125 return o instanceof InterpreterPair.PairValue && Objects.equals(left, ((PairValue) o).left) && Objects.equals(right, ((PairValue) o).right);
126 }
127
128 @Override
129 public int hashCode() {
130 return left.hashCode() * 31 + right.hashCode();
131 }
132
133 @Override
134 public int getSize() {
135 return (left == null ? right : left).getSize();
136 }
137 }
138}