From b789f3914a8148ca28b4c2297055a7501e7d8a35 Mon Sep 17 00:00:00 2001 From: Player Date: Fri, 20 Sep 2024 14:10:01 -0400 Subject: [PATCH] Analyze jdk classes through reflection instead of asm --- .../asm/mixin/transformer/ClassInfo.java | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/spongepowered/asm/mixin/transformer/ClassInfo.java b/src/main/java/org/spongepowered/asm/mixin/transformer/ClassInfo.java index 66fa2a27..5381c303 100644 --- a/src/main/java/org/spongepowered/asm/mixin/transformer/ClassInfo.java +++ b/src/main/java/org/spongepowered/asm/mixin/transformer/ClassInfo.java @@ -24,6 +24,8 @@ */ package org.spongepowered.asm.mixin.transformer; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -907,6 +909,59 @@ private ClassInfo(ClassNode classNode) { } } + private ClassInfo(Class cls) { + this.name = getName(cls); + this.superName = cls.getSuperclass() != null ? getName(cls.getSuperclass()) : ClassInfo.JAVA_LANG_OBJECT; + this.initialisers = new HashSet(); + this.methods = new HashSet(); + this.fields = new HashSet(); + this.isInterface = cls.isInterface(); + Class[] interfaces = cls.getInterfaces(); + this.interfaces = new HashSet(interfaces.length); + this.isMixin = false; + this.mixin = null; + this.mixins = Collections.emptySet(); + + for (Class iface : interfaces) { + this.interfaces.add(getName(iface)); + } + + for (Constructor ctor : cls.getDeclaredConstructors()) { + if ((ctor.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { + continue; + } + + this.initialisers.add(new Method(ctor.getName(), org.objectweb.asm.Type.getConstructorDescriptor(ctor), ctor.getModifiers())); + } + + for (java.lang.reflect.Method method : cls.getDeclaredMethods()) { + if ((method.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { + continue; + } + + this.methods.add(new Method(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method), method.getModifiers())); + } + + for (java.lang.reflect.Field field : cls.getDeclaredFields()) { + if ((field.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { + continue; + } + + this.fields.add(new Field(field.getName(), org.objectweb.asm.Type.getDescriptor(field.getType()), field.getModifiers())); + } + + this.isProbablyStatic = true; + this.methodMapper = new MethodMapper(MixinEnvironment.getCurrentEnvironment(), this); + + this.access = cls.getModifiers(); + this.isInner = false; + this.outerName = null; + } + + private static String getName(Class cls) { + return cls.getName().replace('.', '/'); + } + void addInterface(String iface) { this.interfaces.add(iface); this.getSignature().addInterface(iface); @@ -2025,9 +2080,13 @@ public static ClassInfo forName(String className) { ClassInfo info = ClassInfo.cache.get(className); if (info == null) { try { - int flags = MixinEnvironment.getCurrentEnvironment().getOption(Option.CLASSREADER_EXPAND_FRAMES) ? ClassReader.EXPAND_FRAMES : 0; - ClassNode classNode = MixinService.getService().getBytecodeProvider().getClassNode(className, true, flags); - info = new ClassInfo(classNode); + if (className.startsWith("java/")) { // this would ideally check the platform class loader for other jdk classes, but needs extra api to do so + info = new ClassInfo(Class.forName(className.replace('/', '.'), false, ClassInfo.class.getClassLoader())); + } else { + int flags = MixinEnvironment.getCurrentEnvironment().getOption(Option.CLASSREADER_EXPAND_FRAMES) ? ClassReader.EXPAND_FRAMES : 0; + ClassNode classNode = MixinService.getService().getBytecodeProvider().getClassNode(className, true, flags); + info = new ClassInfo(classNode); + } } catch (Exception ex) { ClassInfo.logger.catching(Level.TRACE, ex); ClassInfo.logger.warn("Error loading class: {} ({}: {})", className, ex.getClass().getName(), ex.getMessage());