Skip to content

Commit b373ec7

Browse files
committed
Uniquify LVT names for vars in inner classes that are in methods. Prevents LVT overlapping.
1 parent 27a1699 commit b373ec7

File tree

5 files changed

+237
-103
lines changed

5 files changed

+237
-103
lines changed

ApplyMarker.java

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package de.oceanlabs.mcp.mcinjector.adaptors;
2+
3+
import java.util.logging.Logger;
4+
5+
import org.objectweb.asm.ClassVisitor;
6+
import org.objectweb.asm.FieldVisitor;
7+
import org.objectweb.asm.MethodVisitor;
8+
import org.objectweb.asm.Opcodes;
9+
import org.objectweb.asm.Type;
10+
11+
import de.oceanlabs.mcp.mcinjector.MCInjectorImpl;
12+
import static org.objectweb.asm.Opcodes.*;
13+
14+
public class ApplyMarker extends ClassVisitor
15+
{
16+
private static final Logger log = Logger.getLogger("MCInjector");
17+
private MCInjectorImpl mci;
18+
private String className;
19+
private int FLAGS = ACC_PRIVATE | ACC_STATIC | ACC_FINAL;
20+
private boolean isAnon = false;
21+
private boolean hasContent = false;
22+
private int access;
23+
24+
public ApplyMarker(ClassVisitor cv, MCInjectorImpl mci)
25+
{
26+
super(Opcodes.ASM5, cv);
27+
this.mci = mci;
28+
}
29+
30+
@Override
31+
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
32+
{
33+
this.className = name;;
34+
this.access = access;
35+
if ((access & ACC_INTERFACE) == ACC_INTERFACE)
36+
{
37+
FLAGS = -1; // ACC_STATIC | ACC_FINAL;
38+
}
39+
super.visit(version, access, name, signature, superName, interfaces);
40+
}
41+
42+
@Override
43+
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value)
44+
{
45+
hasContent = true;
46+
return super.visitField(access, name, desc, signature, value);
47+
}
48+
49+
@Override
50+
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
51+
{
52+
hasContent = true;
53+
return super.visitMethod(access, name, desc, signature, exceptions);
54+
}
55+
56+
@Override
57+
public void visitInnerClass(String name, String outerName, String innerName, int access)
58+
{
59+
if (this.className.equals(name) && innerName == null)
60+
{
61+
isAnon = true;
62+
if ((access & ACC_STATIC) != ACC_STATIC || (access & ACC_SYNTHETIC) != ACC_SYNTHETIC)
63+
hasContent = true;
64+
}
65+
super.visitInnerClass(name, outerName, innerName, access);
66+
}
67+
68+
@Override
69+
public void visitEnd()
70+
{
71+
if (!hasContent && isAnon)
72+
{
73+
log.info(" Skipping Marker to " + className + " due to being anon synthetic");
74+
FLAGS = -1;
75+
}
76+
if (FLAGS != -1)
77+
{
78+
String marker = mci.getMarker(className);
79+
if (marker != null)
80+
{
81+
log.info(" MarkerID: " + marker + " " + className);
82+
this.visitField(FLAGS, "__OBFID", Type.getDescriptor(String.class), null, marker);
83+
}
84+
}
85+
super.visitEnd();
86+
}
87+
}

src/main/java/de/oceanlabs/mcp/mcinjector/MCInjectorImpl.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,4 +668,28 @@ public static MethodNode getMethodNode(MethodVisitor mv)
668668

669669
}
670670
}
671+
672+
private static Field field_cv;
673+
public static ClassNode getClassNode(ClassVisitor cv)
674+
{
675+
try
676+
{
677+
if (field_cv == null)
678+
{
679+
field_cv = ClassVisitor.class.getDeclaredField("cv");
680+
field_cv.setAccessible(true);
681+
}
682+
ClassVisitor tmp = cv;
683+
while (!(tmp instanceof ClassNode) && tmp != null)
684+
tmp = (ClassVisitor)field_cv.get(tmp);
685+
return (ClassNode)tmp;
686+
}
687+
catch (Exception e)
688+
{
689+
if (e instanceof RuntimeException)
690+
throw (RuntimeException)e;
691+
throw new RuntimeException(e);
692+
693+
}
694+
}
671695
}
Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,21 @@
11
package de.oceanlabs.mcp.mcinjector.adaptors;
22

3-
import java.util.logging.Logger;
4-
53
import org.objectweb.asm.ClassVisitor;
6-
import org.objectweb.asm.MethodVisitor;
7-
import org.objectweb.asm.Opcodes;
84
import org.objectweb.asm.tree.LocalVariableNode;
95
import org.objectweb.asm.tree.MethodNode;
106

117
import de.oceanlabs.mcp.mcinjector.MCInjectorImpl;
128

13-
public class LVTFernflower extends ClassVisitor
9+
public class LVTFernflower extends LVTRenamer
1410
{
15-
private static final Logger log = Logger.getLogger("MCInjector");
16-
//private MCInjectorImpl mci;
17-
String className;
18-
1911
public LVTFernflower(ClassVisitor cn, MCInjectorImpl mci)
2012
{
21-
super(Opcodes.ASM5, cn);
22-
//this.mci = mci;
23-
}
24-
25-
@Override
26-
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
27-
{
28-
this.className = name;
29-
super.visit(version, access, name, signature, superName, interfaces);
13+
super(cn, mci);
3014
}
3115

3216
@Override
33-
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
17+
protected String getNewName(MethodNode mtd, LocalVariableNode lvn)
3418
{
35-
return new MethodVisitor(api, cv.visitMethod(access, name, desc, signature, exceptions))
36-
{
37-
@Override
38-
public void visitEnd()
39-
{
40-
super.visitEnd();
41-
MethodNode mn = MCInjectorImpl.getMethodNode(mv);
42-
if (mn.localVariables != null && mn.localVariables.size() > 0)
43-
{
44-
for (LocalVariableNode lvn : mn.localVariables)
45-
{
46-
if (0x2603 != lvn.name.charAt(0)) // Snowmen, added in 1.8.2? rename them to FF names
47-
continue;
48-
log.info(" Renaming LVT: " + lvn.index + " " + lvn.name + " " + lvn.desc + " -> " + "var" + lvn.index);
49-
lvn.name = "var" + lvn.index;
50-
}
51-
}
52-
}
53-
};
19+
return "var" + lvn.index;
5420
}
5521
}
Lines changed: 21 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,44 @@
11
package de.oceanlabs.mcp.mcinjector.adaptors;
22

3-
import java.util.Collections;
4-
import java.util.Comparator;
53
import java.util.HashMap;
64
import java.util.Map;
7-
import java.util.logging.Logger;
85

96
import org.objectweb.asm.ClassVisitor;
10-
import org.objectweb.asm.MethodVisitor;
11-
import org.objectweb.asm.Opcodes;
127
import org.objectweb.asm.tree.LocalVariableNode;
138
import org.objectweb.asm.tree.MethodNode;
149

1510
import de.oceanlabs.mcp.mcinjector.MCInjectorImpl;
1611

17-
public class LVTLvt extends ClassVisitor
12+
public class LVTLvt extends LVTRenamer
1813
{
19-
private static final Logger log = Logger.getLogger("MCInjector");
20-
//private MCInjectorImpl mci;
21-
String className;
14+
private MethodNode lastMethod = null;
15+
private Map<Integer, Integer> vers = null;
2216

2317
public LVTLvt(ClassVisitor cn, MCInjectorImpl mci)
2418
{
25-
super(Opcodes.ASM5, cn);
26-
//this.mci = mci;
19+
super(cn, mci);
2720
}
2821

2922
@Override
30-
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
23+
protected String getNewName(MethodNode mtd, LocalVariableNode lvn)
3124
{
32-
this.className = name;
33-
super.visit(version, access, name, signature, superName, interfaces);
34-
}
35-
36-
@Override
37-
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
38-
{
39-
return new MethodVisitor(api, cv.visitMethod(access, name, desc, signature, exceptions))
25+
if (lastMethod != mtd)
4026
{
41-
@Override
42-
public void visitEnd()
43-
{
44-
super.visitEnd();
45-
final MethodNode mn = MCInjectorImpl.getMethodNode(mv);
46-
if (mn.localVariables != null && mn.localVariables.size() > 0)
47-
{
48-
Collections.sort(mn.localVariables, new Comparator<LocalVariableNode>()
49-
{
50-
@Override
51-
public int compare(LocalVariableNode o1, LocalVariableNode o2)
52-
{
53-
if (o1.index < o2.index) return -1;
54-
if (o1.index > o2.index) return 1;
55-
int o1Start = mn.instructions.indexOf(o1.start);
56-
int o2Start = mn.instructions.indexOf(o2.start);
57-
if (o1Start < o2Start) return -1;
58-
if (o2Start > o2Start) return 1;
59-
return 0;
60-
}
27+
vers = new HashMap<Integer, Integer>();
28+
lastMethod = mtd;
29+
}
6130

62-
});
63-
64-
Map<Integer, Integer> vers = new HashMap<Integer, Integer>();
65-
for (LocalVariableNode lvn : mn.localVariables)
66-
{
67-
if (0x2603 != lvn.name.charAt(0)) // Snowmen, added in 1.8.2? rename them
68-
continue;
69-
int ver = 0;
70-
if (vers.containsKey(lvn.index))
71-
{
72-
ver = vers.get(lvn.index);
73-
vers.put(lvn.index, ver + 1);
74-
}
75-
else
76-
{
77-
ver = 1;
78-
vers.put(lvn.index, 2);
79-
}
80-
String name = "lvt_" + lvn.index + "_" + ver + "_";
81-
log.info(" Renaming LVT: " + lvn.index + " " + lvn.name + " " + lvn.desc + " -> " + name);
82-
lvn.name = name;
83-
}
84-
}
85-
}
86-
};
31+
int ver = 0;
32+
if (vers.containsKey(lvn.index))
33+
{
34+
ver = vers.get(lvn.index);
35+
vers.put(lvn.index, ver + 1);
36+
}
37+
else
38+
{
39+
ver = 1;
40+
vers.put(lvn.index, 2);
41+
}
42+
return "lvt_" + lvn.index + "_" + ver + "_";
8743
}
8844
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package de.oceanlabs.mcp.mcinjector.adaptors;
2+
3+
import java.util.Collections;
4+
import java.util.Comparator;
5+
import java.util.logging.Logger;
6+
7+
import org.objectweb.asm.ClassVisitor;
8+
import org.objectweb.asm.Opcodes;
9+
import org.objectweb.asm.tree.ClassNode;
10+
import org.objectweb.asm.tree.LocalVariableNode;
11+
import org.objectweb.asm.tree.MethodNode;
12+
13+
import de.oceanlabs.mcp.mcinjector.MCInjectorImpl;
14+
15+
public abstract class LVTRenamer extends ClassVisitor
16+
{
17+
private static final Logger log = Logger.getLogger("MCInjector");
18+
private MCInjectorImpl mci;
19+
String className;
20+
private boolean isInMethod = false;
21+
22+
public LVTRenamer(ClassVisitor cn, MCInjectorImpl mci)
23+
{
24+
super(Opcodes.ASM5, cn);
25+
this.mci = mci;
26+
}
27+
28+
@Override
29+
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
30+
{
31+
this.className = name;
32+
super.visit(version, access, name, signature, superName, interfaces);
33+
}
34+
35+
@Override
36+
public void visitOuterClass(String owner, String name, String desc) {
37+
super.visitOuterClass(owner, name, desc);
38+
if (desc != null) {
39+
isInMethod = true;
40+
}
41+
}
42+
43+
@Override
44+
public void visitEnd() {
45+
super.visitEnd();
46+
47+
String suffix = null;
48+
if (isInMethod)
49+
{
50+
String tmp = mci.getMarker(className);
51+
if (tmp != null) {
52+
tmp = tmp.replace("CL_", "");
53+
while (tmp.charAt(0) == '0')
54+
tmp = tmp.substring(1);
55+
suffix = tmp;
56+
}
57+
}
58+
59+
ClassNode cls = MCInjectorImpl.getClassNode(cv);
60+
for (final MethodNode mn : cls.methods)
61+
{
62+
if (mn.localVariables != null && mn.localVariables.size() > 0)
63+
{
64+
Collections.sort(mn.localVariables, new Comparator<LocalVariableNode>()
65+
{
66+
@Override
67+
public int compare(LocalVariableNode o1, LocalVariableNode o2)
68+
{
69+
if (o1.index < o2.index) return -1;
70+
if (o1.index > o2.index) return 1;
71+
int o1Start = mn.instructions.indexOf(o1.start);
72+
int o2Start = mn.instructions.indexOf(o2.start);
73+
if (o1Start < o2Start) return -1;
74+
if (o2Start > o2Start) return 1;
75+
return 0;
76+
}
77+
78+
});
79+
80+
for (LocalVariableNode lvn : mn.localVariables)
81+
{
82+
if (0x2603 != lvn.name.charAt(0)) // Snowmen, added in 1.8.2? rename them to FF names
83+
continue;
84+
String name = getNewName(mn, lvn);
85+
if (suffix != null)
86+
{
87+
if (!name.endsWith("_"))
88+
{
89+
name += "_";
90+
}
91+
name += suffix + "_";
92+
}
93+
log.info(" Renaming LVT: " + lvn.index + " " + lvn.name + " " + lvn.desc + " -> " + name);
94+
lvn.name = name;
95+
}
96+
}
97+
}
98+
}
99+
100+
protected abstract String getNewName(MethodNode mtd, LocalVariableNode lvn);
101+
}

0 commit comments

Comments
 (0)