mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-15 09:34:53 +00:00
Upgraded ASM lib
This commit is contained in:
1 parent
0a14b64e12
commit
52f82017e7
14 files changed
+1142
-747
No files matched your search
@@ -0,0 +1,285 @@
|
||||
package codechicken.lib.asm;
|
||||
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import static codechicken.lib.asm.ASMHelper.*;
|
||||
|
||||
public class ModularASMTransformer
|
||||
{
|
||||
public static class ClassNodeTransformerList
|
||||
{
|
||||
List<ClassNodeTransformer> transformers = new LinkedList<ClassNodeTransformer>();
|
||||
HashSet<ObfMapping> methodsToSort = new HashSet<ObfMapping>();
|
||||
|
||||
public void add(ClassNodeTransformer t) {
|
||||
transformers.add(t);
|
||||
t.addMethodsToSort(methodsToSort);
|
||||
}
|
||||
|
||||
public byte[] transform(byte[] bytes) {
|
||||
ClassNode cnode = new ClassNode();
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
ClassVisitor cv = cnode;
|
||||
if(!methodsToSort.isEmpty())
|
||||
cv = new LocalVariablesSorterVisitor(methodsToSort, cv);
|
||||
reader.accept(cv, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
try {
|
||||
int writeFlags = 0;
|
||||
for(ClassNodeTransformer t : transformers) {
|
||||
t.transform(cnode);
|
||||
writeFlags|=t.writeFlags;
|
||||
}
|
||||
|
||||
bytes = createBytes(cnode, writeFlags);
|
||||
if(config.getTag("dump_asm").getBooleanValue(true))
|
||||
dump(bytes, new File("asm/ccl_modular/"+cnode.name.replace('/', '#')+".txt"), false, false);
|
||||
return bytes;
|
||||
} catch (RuntimeException e) {
|
||||
dump(bytes, new File("asm/ccl_modular/"+cnode.name.replace('/', '#')+".txt"), false, false);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class ClassNodeTransformer
|
||||
{
|
||||
public int writeFlags;
|
||||
public ClassNodeTransformer(int writeFlags) {
|
||||
this.writeFlags = writeFlags;
|
||||
}
|
||||
|
||||
public ClassNodeTransformer() {
|
||||
this(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
}
|
||||
|
||||
public abstract String className();
|
||||
public abstract void transform(ClassNode cnode);
|
||||
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {}
|
||||
}
|
||||
|
||||
public static abstract class MethodTransformer extends ClassNodeTransformer
|
||||
{
|
||||
public final ObfMapping method;
|
||||
|
||||
public MethodTransformer(ObfMapping method) {
|
||||
this.method = method.toClassloading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return method.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
MethodNode mv = findMethod(method, cnode);
|
||||
if (mv == null)
|
||||
throw new RuntimeException("Method not found: " + method);
|
||||
|
||||
try {
|
||||
transform(mv);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error transforming method: "+method, e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void transform(MethodNode mv);
|
||||
}
|
||||
|
||||
public static class MethodWriter extends ClassNodeTransformer
|
||||
{
|
||||
public final int access;
|
||||
public final ObfMapping method;
|
||||
public final String[] exceptions;
|
||||
public InsnList list;
|
||||
|
||||
public MethodWriter(int access, ObfMapping method) {
|
||||
this(access, method, null, (InsnList)null);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, InsnList list) {
|
||||
this(access, method, null, list);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, ASMBlock block) {
|
||||
this(access, method, null, block);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions) {
|
||||
this(access, method, exceptions, (InsnList)null);
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions, InsnList list) {
|
||||
this.access = access;
|
||||
this.method = method.toClassloading();
|
||||
this.exceptions = exceptions;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public MethodWriter(int access, ObfMapping method, String[] exceptions, ASMBlock block) {
|
||||
this(access, method, exceptions, block.rawListCopy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return method.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
MethodNode mv = findMethod(method, cnode);
|
||||
if(mv == null)
|
||||
mv = (MethodNode) method.visitMethod(cnode, access, exceptions);
|
||||
else {
|
||||
mv.access = access;
|
||||
mv.instructions.clear();
|
||||
if (mv.localVariables != null)
|
||||
mv.localVariables.clear();
|
||||
if (mv.tryCatchBlocks != null)
|
||||
mv.tryCatchBlocks.clear();
|
||||
}
|
||||
|
||||
write(mv);
|
||||
}
|
||||
|
||||
public void write(MethodNode mv) {
|
||||
logger.debug("Writing method "+method);
|
||||
list.accept(mv);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodInjector extends MethodTransformer
|
||||
{
|
||||
public ASMBlock needle;
|
||||
public ASMBlock injection;
|
||||
public boolean before;
|
||||
|
||||
public MethodInjector(ObfMapping method, ASMBlock needle, ASMBlock injection, boolean before) {
|
||||
super(method);
|
||||
this.needle = needle;
|
||||
this.injection = injection;
|
||||
this.before = before;
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, ASMBlock injection, boolean before) {
|
||||
this(method, null, injection, before);
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList needle, InsnList injection, boolean before) {
|
||||
this(method, new ASMBlock(needle), new ASMBlock(injection), before);
|
||||
}
|
||||
|
||||
public MethodInjector(ObfMapping method, InsnList injection, boolean before) {
|
||||
this(method, null, new ASMBlock(injection), before);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {
|
||||
set.add(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
if(needle == null) {
|
||||
logger.debug("Injecting "+(before ? "before" : "after")+" method "+method);
|
||||
if (before)
|
||||
mv.instructions.insert(injection.rawListCopy());
|
||||
else
|
||||
mv.instructions.add(injection.rawListCopy());
|
||||
}
|
||||
else {
|
||||
for (InsnListSection key : InsnComparator.findN(mv.instructions, needle.list)) {
|
||||
logger.debug("Injecting "+(before ? "before" : "after")+" method "+method+" @ "+key.start+" - "+key.end);
|
||||
ASMBlock injectBlock = injection.copy().mergeLabels(needle.applyLabels(key));
|
||||
|
||||
if (before)
|
||||
key.insertBefore(injectBlock.list.list);
|
||||
else
|
||||
key.insert(injectBlock.list.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodReplacer extends MethodTransformer
|
||||
{
|
||||
public ASMBlock needle;
|
||||
public ASMBlock replacement;
|
||||
|
||||
public MethodReplacer(ObfMapping method, ASMBlock needle, ASMBlock replacement) {
|
||||
super(method);
|
||||
this.needle = needle;
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
public MethodReplacer(ObfMapping method, InsnList needle, InsnList replacement) {
|
||||
this(method, new ASMBlock(needle), new ASMBlock(replacement));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMethodsToSort(Set<ObfMapping> set) {
|
||||
set.add(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(MethodNode mv) {
|
||||
for (InsnListSection key : InsnComparator.findN(mv.instructions, needle.list)) {
|
||||
logger.debug("Replacing method "+method+" @ "+key.start+" - "+key.end);
|
||||
ASMBlock replaceBlock = replacement.copy().pullLabels(needle.applyLabels(key));
|
||||
key.insert(replaceBlock.list.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FieldWriter extends ClassNodeTransformer
|
||||
{
|
||||
public final ObfMapping field;
|
||||
public final int access;
|
||||
public final Object value;
|
||||
|
||||
public FieldWriter(int access, ObfMapping field, Object value) {
|
||||
this.field = field.toClassloading();
|
||||
this.access = access;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public FieldWriter(int access, ObfMapping field) {
|
||||
this(access, field, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String className() {
|
||||
return field.javaClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ClassNode cnode) {
|
||||
field.visitField(cnode, access, value);
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<String, ClassNodeTransformerList> transformers = new HashMap<String, ClassNodeTransformerList>();
|
||||
|
||||
public void add(ClassNodeTransformer t) {
|
||||
ClassNodeTransformerList list = transformers.get(t.className());
|
||||
if(list == null)
|
||||
transformers.put(t.className(), list = new ClassNodeTransformerList());
|
||||
list.add(t);
|
||||
}
|
||||
|
||||
public byte[] transform(String name, byte[] bytes) {
|
||||
if(bytes == null)
|
||||
return null;
|
||||
|
||||
ClassNodeTransformerList list = transformers.get(name);
|
||||
return list == null ? bytes : list.transform(bytes);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user