Files
CodeChickenCore/codechicken/lib/asm/ClassHeirachyManager.java
T

188 lines
5.2 KiB
Java
Raw Normal View History

2013-07-16 17:58:02 +10:00
package codechicken.lib.asm;
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
2013-07-16 17:58:02 +10:00
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraft.launchwrapper.LaunchClassLoader;
2014-04-09 13:38:05 +10:00
import org.objectweb.asm.tree.ClassNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
2013-07-16 17:58:02 +10:00
/**
* This is added as a class transformer if CodeChickenCore is installed. Adding it as a class transformer will speed evaluation up slightly by automatically caching superclasses when they are first loaded.
*/
public class ClassHeirachyManager implements IClassTransformer
{
2013-07-29 22:53:29 +10:00
public static class SuperCache
{
String superclass;
public HashSet<String> parents = new HashSet<String>();
private boolean flattened;
public void add(String parent)
{
parents.add(parent);
}
public void flatten()
{
if(flattened)
return;
for(String s : new ArrayList<String>(parents))
{
SuperCache c = declareClass(s);
if(c != null)
{
c.flatten();
parents.addAll(c.parents);
}
}
flattened = true;
}
}
public static HashMap<String, SuperCache> superclasses = new HashMap<String, SuperCache>();
2013-07-16 17:58:02 +10:00
private static LaunchClassLoader cl = (LaunchClassLoader)ClassHeirachyManager.class.getClassLoader();
2013-07-17 18:18:57 +10:00
static
{
cl.addTransformerExclusion("codechicken.lib.asm");
}
public static String toKey(String name)
{
if(ObfMapping.obfuscated)
2013-07-29 22:53:29 +10:00
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;
}
2013-07-16 17:58:02 +10:00
/**
* @param name The class in question
2013-07-16 17:58:02 +10:00
* @param superclass The class being extended
2014-04-09 13:38:05 +10:00
* @return true if clazz extends, either directly or indirectly, superclass.
2013-07-16 17:58:02 +10:00
*/
2013-07-29 22:53:29 +10:00
public static boolean classExtends(String name, String superclass)
2013-07-16 17:58:02 +10:00
{
name = toKey(name);
2013-07-29 22:53:29 +10:00
superclass = toKey(superclass);
2013-07-29 22:53:29 +10:00
if(name.equals(superclass))
2013-07-16 17:58:02 +10:00
return true;
2013-07-29 22:53:29 +10:00
SuperCache cache = declareClass(name);
if(cache == null)//just can't handle this
2013-07-16 17:58:02 +10:00
return false;
2013-07-29 22:53:29 +10:00
cache.flatten();
return cache.parents.contains(superclass);
2013-07-16 17:58:02 +10:00
}
2013-07-29 22:53:29 +10:00
private static SuperCache declareClass(String name)
2013-07-16 17:58:02 +10:00
{
name = toKey(name);
2013-07-29 22:53:29 +10:00
SuperCache cache = superclasses.get(name);
if(cache != null)
return cache;
2013-07-16 17:58:02 +10:00
try
{
2013-07-29 22:53:29 +10:00
byte[] bytes = cl.getClassBytes(unKey(name));
if(bytes != null)
cache = declareASM(bytes);
}
catch(Exception e)
{
}
if(cache != null)
return cache;
try
{
cache = declareReflection(name);
2013-07-16 17:58:02 +10:00
}
catch(ClassNotFoundException e)
{
}
2013-07-29 22:53:29 +10:00
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;
2013-07-16 17:58:02 +10:00
}
@Override
public byte[] transform(String name, String tname, byte[] bytes)
{
2013-07-29 22:53:29 +10:00
if (bytes == null)
return null;
if(!superclasses.containsKey(tname))
declareASM(bytes);
2013-07-16 17:58:02 +10:00
return bytes;
}
2013-07-29 22:53:29 +10:00
public static SuperCache getOrCreateCache(String name)
2013-07-16 17:58:02 +10:00
{
2013-07-29 22:53:29 +10:00
SuperCache cache = superclasses.get(name);
if(cache == null)
superclasses.put(name, cache = new SuperCache());
return cache;
2013-07-16 17:58:02 +10:00
}
public static String getSuperClass(String name, boolean runtime)
2013-07-16 17:58:02 +10:00
{
name = toKey(name);
2013-07-29 22:53:29 +10:00
SuperCache cache = declareClass(name);
if(cache == null)
2013-07-16 17:58:02 +10:00
return "java.lang.Object";
2013-07-29 22:53:29 +10:00
cache.flatten();
String s = cache.superclass;
if(!runtime)
s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s);
return s;
2013-07-16 17:58:02 +10:00
}
}