From d6f14e9ab1ca2163dc481bcdf6ec18ae9ca172a0 Mon Sep 17 00:00:00 2001 From: Chicken Bones Date: Mon, 29 Jul 2013 22:53:29 +1000 Subject: [PATCH] Optimised ClassHeirachyManager --- codechicken/lib/asm/ClassHeirachyManager.java | 189 +++++++++++------- 1 file changed, 118 insertions(+), 71 deletions(-) diff --git a/codechicken/lib/asm/ClassHeirachyManager.java b/codechicken/lib/asm/ClassHeirachyManager.java index e5bf3d6..d04cb52 100644 --- a/codechicken/lib/asm/ClassHeirachyManager.java +++ b/codechicken/lib/asm/ClassHeirachyManager.java @@ -15,8 +15,36 @@ import net.minecraft.launchwrapper.LaunchClassLoader; */ public class ClassHeirachyManager implements IClassTransformer { - public static HashSet knownClasses = new HashSet(); - public static HashMap> superclasses = new HashMap>(); + public static class SuperCache + { + String superclass; + public HashSet parents = new HashSet(); + private boolean flattened; + + public void add(String parent) + { + parents.add(parent); + } + + public void flatten() + { + if(flattened) + return; + + for(String s : new ArrayList(parents)) + { + SuperCache c = declareClass(s); + if(c != null) + { + c.flatten(); + parents.addAll(c.parents); + } + } + flattened = true; + } + } + + public static HashMap superclasses = new HashMap(); private static LaunchClassLoader cl = (LaunchClassLoader)ClassHeirachyManager.class.getClassLoader(); static @@ -27,7 +55,14 @@ public class ClassHeirachyManager implements IClassTransformer public static String toKey(String name) { if(ObfMapping.obfuscated) - name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/','.'); + name = FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.'); + return name; + } + + public static String unKey(String name) + { + if(ObfMapping.obfuscated) + name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.'); return name; } @@ -38,107 +73,119 @@ public class ClassHeirachyManager implements IClassTransformer * @param bytes The bytes for the class. Only needed if not already defined. * @return */ - public static boolean classExtends(String name, String superclass, byte[] bytes) + public static boolean classExtends(String name, String superclass) { name = toKey(name); + superclass = toKey(superclass); - if(!knownClasses.contains(name)) - new ClassHeirachyManager().transform(name, name, bytes); - - return classExtends(name, superclass); - } - - public static boolean classExtends(String clazz, String superclass) - { - if(clazz.equals(superclass)) + if(name.equals(superclass)) return true; - if(clazz.equals("java.lang.Object")) + SuperCache cache = declareClass(name); + if(cache == null)//just can't handle this return false; - declareClass(clazz); - - if(!superclasses.containsKey(clazz))//just can't handle this - return false; - - for(String s : superclasses.get(clazz)) - if(classExtends(s, superclass)) - return true; - - return false; + cache.flatten(); + return cache.parents.contains(superclass); } - private static void declareClass(String name) + private static SuperCache declareClass(String name) { name = toKey(name); + SuperCache cache = superclasses.get(name); + + if(cache != null) + return cache; try { - if(!knownClasses.contains(name)) - { - try - { - byte[] bytes = cl.getClassBytes(name); - if(bytes != null) - new ClassHeirachyManager().transform(name, name, bytes); - } - catch(Exception e) - { - } - - if(!knownClasses.contains(name)) - { - Class aclass = Class.forName(name); - - knownClasses.add(name); - if(aclass.isInterface()) - addSuperclass(name, "java.lang.Object"); - else - addSuperclass(name, aclass.getSuperclass().getName()); - for(Class iclass : aclass.getInterfaces()) - addSuperclass(name, iclass.getName()); - } - } + byte[] bytes = cl.getClassBytes(unKey(name)); + if(bytes != null) + cache = declareASM(bytes); + } + catch(Exception e) + { + } + + if(cache != null) + return cache; + + + try + { + cache = declareReflection(name); } catch(ClassNotFoundException e) { } + + return cache; + } + + private static SuperCache declareReflection(String name) throws ClassNotFoundException + { + Class aclass = Class.forName(name); + + SuperCache cache = getOrCreateCache(name); + if(aclass.isInterface()) + cache.superclass = "java.lang.Object"; + else if(name.equals("java.lang.Object")) + return cache; + else + cache.superclass = toKey(aclass.getSuperclass().getName()); + + cache.add(cache.superclass); + for(Class iclass : aclass.getInterfaces()) + cache.add(toKey(iclass.getName())); + + return cache; + } + + private static SuperCache declareASM(byte[] bytes) + { + ClassNode node = ASMHelper.createClassNode(bytes); + String name = toKey(node.name); + + SuperCache cache = getOrCreateCache(name); + cache.superclass = toKey(node.superName.replace('/', '.')); + cache.add(cache.superclass); + for(String iclass : node.interfaces) + cache.add(toKey(iclass.replace('/', '.'))); + + return cache; } @Override public byte[] transform(String name, String tname, byte[] bytes) { - if (bytes == null) return null; - if(!knownClasses.contains(name)) - { - ClassNode node = ASMHelper.createClassNode(bytes); - - knownClasses.add(name); - addSuperclass(name, node.superName.replace('/', '.')); - for(String iclass : node.interfaces) - addSuperclass(name, iclass.replace('/', '.')); - } + if (bytes == null) + return null; + + if(!superclasses.containsKey(tname)) + declareASM(bytes); return bytes; } - - private static void addSuperclass(String name, String superclass) + + public static SuperCache getOrCreateCache(String name) { - ArrayList supers = superclasses.get(name); - if(supers == null) - superclasses.put(name, supers = new ArrayList()); - supers.add(superclass); - supers.add(new ObfMapping(superclass.replace('.', '/')).toRuntime().javaClass()); + SuperCache cache = superclasses.get(name); + if(cache == null) + superclasses.put(name, cache = new SuperCache()); + return cache; } public static String getSuperClass(String name, boolean runtime) { name = toKey(name); - declareClass(name); - - if(!knownClasses.contains(name)) + SuperCache cache = declareClass(name); + if(cache == null) return "java.lang.Object"; - return superclasses.get(name).get(runtime ? 1 : 0); + cache.flatten(); + String s = cache.superclass; + if(!runtime) + s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s); + return s; } }