Skip to content

Commit c6cb0ac

Browse files
committed
Rewrite clear_mixin_classinfo, now more aggressive
1 parent 095b9c3 commit c6cb0ac

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed
Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,73 @@
11
package org.embeddedt.modernfix.util;
22

3+
import org.embeddedt.modernfix.ModernFix;
34
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
5+
import org.objectweb.asm.tree.ClassNode;
6+
import org.spongepowered.asm.mixin.MixinEnvironment;
7+
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
48
import org.spongepowered.asm.mixin.transformer.ClassInfo;
59

610
import java.lang.reflect.Field;
11+
import java.util.Collection;
712
import java.util.Map;
813

914
public class ClassInfoManager {
10-
private static Map<String, ClassInfo> classInfoCache = null;
15+
private static boolean hasRun = false;
1116
public static void clear() {
12-
if(!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager"))
17+
if (!ModernFixMixinPlugin.instance.isOptionEnabled("perf.clear_mixin_classinfo.ClassInfoManager") || hasRun)
18+
return;
19+
hasRun = true;
20+
ModernFix.resourceReloadExecutor().execute(ClassInfoManager::doClear);
21+
}
22+
23+
private static Field accessible(Field f) {
24+
f.setAccessible(true);
25+
return f;
26+
}
27+
28+
private static void doClear() {
29+
Map<String, ClassInfo> classInfoCache;
30+
Field mixinField, stateField, classNodeField, methodsField, fieldsField;
31+
Class<?> stateClz;
32+
try {
33+
Field field = accessible(ClassInfo.class.getDeclaredField("cache"));
34+
classInfoCache = (Map<String, ClassInfo>) field.get(null);
35+
mixinField = accessible(ClassInfo.class.getDeclaredField("mixin"));
36+
methodsField = accessible(ClassInfo.class.getDeclaredField("methods"));
37+
fieldsField = accessible(ClassInfo.class.getDeclaredField("fields"));
38+
stateClz = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo$State");
39+
stateField = accessible(Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo").getDeclaredField("state"));
40+
classNodeField = accessible(stateClz.getDeclaredField("classNode"));
41+
} catch (ReflectiveOperationException | RuntimeException e) {
42+
e.printStackTrace();
1343
return;
14-
if(classInfoCache == null) {
15-
try {
16-
Field field = ClassInfo.class.getDeclaredField("cache");
17-
field.setAccessible(true);
18-
classInfoCache = (Map<String, ClassInfo>)field.get(null);
19-
} catch(ReflectiveOperationException | RuntimeException e) {
20-
e.printStackTrace();
21-
return;
22-
}
2344
}
45+
MixinEnvironment.getDefaultEnvironment().audit();
2446
try {
25-
classInfoCache.entrySet().removeIf(entry -> !entry.getKey().equals("java/lang/Object") && (entry.getValue() == null || !entry.getValue().isMixin()));
26-
} catch(RuntimeException e) {
47+
ClassNode emptyNode = new ClassNode();
48+
classInfoCache.entrySet().removeIf(entry -> {
49+
if(entry.getKey().equals("java/lang/Object"))
50+
return false;
51+
ClassInfo mixinClz = entry.getValue();
52+
try {
53+
if(mixinClz.isMixin()) {
54+
// clear classNode in MixinInfo.State
55+
IMixinInfo theInfo = (IMixinInfo) mixinField.get(mixinClz);
56+
Object state = stateField.get(theInfo);
57+
if (state != null)
58+
classNodeField.set(state, emptyNode);
59+
}
60+
// clear fields, methods
61+
((Collection<?>)methodsField.get(mixinClz)).clear();
62+
((Collection<?>)fieldsField.get(mixinClz)).clear();
63+
} catch (ReflectiveOperationException | RuntimeException e) {
64+
e.printStackTrace();
65+
}
66+
return true;
67+
});
68+
} catch (RuntimeException e) {
2769
e.printStackTrace();
2870
}
71+
ModernFix.LOGGER.warn("Cleared mixin data structures");
2972
}
3073
}

0 commit comments

Comments
 (0)