-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathVariableNumberFixer.java
229 lines (206 loc) · 8.23 KB
/
VariableNumberFixer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package net.minecraftforge.lex.fffixer;
import static org.objectweb.asm.Opcodes.*;
import java.util.Iterator;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
/**
* Fixes decompiler differences between JVM versions caused by HashSet's sorting order changing between JVM implementations.
* Simple solution is to hijack the Iterator to make it use a properly sorted one.
* Thanks to fry for finding this issue with class names, which then led me to look for var names.
*
*
* Code injected in aa:
* implements net.minecraftfroge.lex.fffixer.Util.Indexed
* public final int getIndex()
* {
* if (!isDeclaration) return -1;
* return this.c;
* }
*
* Code injected in bB:
* var = net.minecraftfroge.lex.fffixer.Util.sortIndexed(var)
*
* Code Injected in d:
* var = net.minecraftfroge.lex.fffixer.Util.sortComparable(var);
*
* Code Injected in de (IntPair):
* implements Comparable<de>
* public int compareTo(de o)
* {
* if (this.a != o.a) return this.a - o.a;
* return this.b - o.b
* }
* public int compareTo(Object o)
* {
* return compareTo((de)o);
* }
*
*/
public class VariableNumberFixer implements IClassProcessor
{
private FFFixerImpl inst;
public VariableNumberFixer(FFFixerImpl inst)
{
this.inst = inst;
}
@Override
public void process(ClassNode node)
{
if (node.name.equals("aa")) fix_aa(node);
//if (node.name.equals("aC")) fix_aC(node);
if (node.name.equals("bB")) fix_bB(node);
if (node.name.equals("d" )) fix_d (node);
if (node.name.equals("de")) fixIntPair(node);
}
private void fix_aa(ClassNode node)
{
FFFixerImpl.log.info("Adding index getter to aa");
node.interfaces.add(Type.getInternalName(Util.Indexed.class));
MethodNode mn = new MethodNode(ACC_PUBLIC | ACC_FINAL, "getIndex", "()I", null, null);
mn.visitCode();
Label isDeclaration = new Label();
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "aa", "e", "Z");
mn.visitJumpInsn(IFNE, isDeclaration);
mn.visitInsn(ICONST_M1);
mn.visitInsn(IRETURN);
mn.visitLabel(isDeclaration);
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "aa", "c", "I");
mn.visitInsn(IRETURN);
mn.visitEnd();
node.methods.add(mn);
inst.setWorkDone();
}
/* Old Code, Kept in case we wanna inject it again
private void fix_aC(ClassNode node)
{
FFFixerImpl.log.info("Adding index getter to aC");
node.interfaces.add(Type.getInternalName(Util.Indexed.class));
String idx = Type.getInternalName(Util.Indexed.class);
MethodNode mn = new MethodNode(ACC_PUBLIC | ACC_FINAL, "getIndex", "()I", null, null);
mn.visitCode();
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "aC", "d", "LaJ;");
mn.visitTypeInsn(INSTANCEOF, idx);
Label l0 = new Label();
mn.visitJumpInsn(IFNE, l0);
mn.visitInsn(ICONST_M1);
mn.visitInsn(IRETURN);
mn.visitLabel(l0);
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "aC", "d", "LaJ;");
mn.visitTypeInsn(CHECKCAST, idx);
mn.visitMethodInsn(INVOKEINTERFACE, idx, "getIndex", "()I", true);
mn.visitInsn(ICONST_M1);
mn.visitInsn(IMUL);
mn.visitInsn(IRETURN);
mn.visitEnd();
node.methods.add(mn);
inst.setWorkDone();
}
*/
private void fix_bB(ClassNode node)
{
MethodNode mtd = FFFixerImpl.getMethod(node, "a", "(Ljava/util/List;I)Ljava/lang/String;");
Iterator<AbstractInsnNode> itr = mtd.instructions.iterator();
while(itr.hasNext())
{
AbstractInsnNode insn = itr.next();
if (insn instanceof MethodInsnNode)
{
MethodInsnNode v = (MethodInsnNode)insn;
// first iterator call
if(v.getOpcode() == INVOKEINTERFACE && (v.owner + "/" + v.name + v.desc).equals("java/util/List/iterator()Ljava/util/Iterator;"))
{
FFFixerImpl.log.info("Injecting Var Order Fix in bB");
mtd.instructions.insert(insn, new MethodInsnNode(
INVOKESTATIC,
Type.getInternalName(Util.class),
"sortIndexed",
"(Ljava/util/Iterator;)Ljava/util/Iterator;",
false));
inst.setWorkDone();
return;
}
}
}
}
private void fix_d(ClassNode node)
{
MethodNode mtd = FFFixerImpl.getMethod(node, "b", "(Lcu;Lq;)V");
Iterator<AbstractInsnNode> itr = mtd.instructions.iterator();
while(itr.hasNext())
{
AbstractInsnNode insn = itr.next();
if (insn instanceof MethodInsnNode)
{
MethodInsnNode v = (MethodInsnNode)insn;
if (v.getOpcode() == INVOKEVIRTUAL && (v.owner + "/" + v.name + v.desc).equals("java/util/HashSet/iterator()Ljava/util/Iterator;"))
{
insn = itr.next(); //Pop off the next which is ASTORE 15
FFFixerImpl.log.info("Injecting Var Order Fix");
VarInsnNode var = (VarInsnNode)insn;
InsnList toAdd = new InsnList();
toAdd.add(new VarInsnNode (ALOAD, var.var)); // var15 = fixInnerOrder(var15)
toAdd.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Util.class), "sortComparable", "(Ljava/util/Iterator;)Ljava/util/Iterator;", false));
toAdd.add(new VarInsnNode (ASTORE, var.var));
mtd.instructions.insert(insn, toAdd); // Inject static call
inst.setWorkDone();
return;
}
}
}
}
/**
* Make IntPair (de) extend Comparable, was doing this via string manipulation before because I was tired,
* but converted to ASM method injection for speed by fry, thanks.
*
* @param node The IntPair (de) class node
*/
private void fixIntPair(ClassNode node)
{
FFFixerImpl.log.info("Making IntPair Comparable");
node.signature = "Ljava/lang/Object;Ljava/lang/Comparable<Lde;>;";
node.interfaces.add("java/lang/Comparable");
MethodNode mn = new MethodNode(ACC_PUBLIC, "compareTo", "(Lde;)I", null, null);
mn.visitCode();
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "de", "a", "I");
mn.visitVarInsn(ALOAD, 1);
mn.visitFieldInsn(GETFIELD, "de", "a", "I");
Label a_equals = new Label();
mn.visitJumpInsn(IF_ICMPEQ, a_equals); // if this.a == o.a goto a_euqals
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "de", "a", "I");
mn.visitVarInsn(ALOAD, 1);
mn.visitFieldInsn(GETFIELD, "de", "a", "I");
mn.visitInsn(ISUB);
mn.visitInsn(IRETURN); // return this.a - o.a
mn.visitLabel(a_equals); // a_equals
mn.visitVarInsn(ALOAD, 0);
mn.visitFieldInsn(GETFIELD, "de", "b", "I");
mn.visitVarInsn(ALOAD, 1);
mn.visitFieldInsn(GETFIELD, "de", "b", "I");
mn.visitInsn(ISUB);
mn.visitInsn(IRETURN); // return this.b - o.b
mn.visitEnd();
node.methods.add(mn);
mn = new MethodNode(ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, "compareTo", "(Ljava/lang/Object;)I", null, null);
mn.visitCode();
mn.visitVarInsn(ALOAD, 0);
mn.visitVarInsn(ALOAD, 1);
mn.visitTypeInsn(CHECKCAST, "de");
mn.visitMethodInsn(INVOKEVIRTUAL, "de", "compareTo", "(Lde;)I", false); // Synthetic bounce of (Object) -> (IntPair)
mn.visitInsn(IRETURN);
mn.visitEnd();
node.methods.add(mn);
inst.setWorkDone();
}
}