Example usage for org.objectweb.asm.tree ClassNode accept

List of usage examples for org.objectweb.asm.tree ClassNode accept

Introduction

In this page you can find the example usage for org.objectweb.asm.tree ClassNode accept.

Prototype

public void accept(final ClassVisitor classVisitor) 

Source Link

Document

Makes the given class visitor visit this class.

Usage

From source file:org.qkit.core.asm.adapters.ChangeSuperclassAdapter.java

License:Open Source License

@Override
public void visitEnd() {
    ClassNode cn = (ClassNode) cv;

    for (MethodNode mn : cn.methods) {
        InsnList il = mn.instructions;//from  www. j a v  a 2s . c o  m
        Iterator<AbstractInsnNode> it = il.iterator();

        while (it.hasNext()) {
            AbstractInsnNode ain = it.next();

            if (ain instanceof MethodInsnNode) {
                MethodInsnNode m = (MethodInsnNode) ain;
                if ((m.getOpcode() == INVOKESPECIAL)) {
                    MethodInsnNode min = (MethodInsnNode) ain;
                    if (min.owner.equals(cn.superName)) {
                        min.owner = superClass;
                    }
                    break;
                }
            }
        }
    }

    cn.superName = superClass;

    System.out.println("    [~S] " + cn.name + " extends " + cn.superName);

    cn.accept(next);

}

From source file:org.spongepowered.asm.mixin.transformer.MixinTransformer.java

License:MIT License

/**
 * Apply mixins for specified target class to the class described by the
 * supplied byte array./*from  w w  w.jav  a2  s . c  o  m*/
 * 
 * @param transformedName 
 * @param basicClass
 * @param mixins
 * @return class bytecode after application of mixins
 */
private byte[] applyMixins(String transformedName, byte[] basicClass, SortedSet<MixinInfo> mixins) {
    // Tree for target class
    ClassNode targetClass = this.readClass(basicClass, true);

    for (MixinInfo mixin : mixins) {
        this.logger.log(mixin.getLoggingLevel(), "Mixing {} into {}", mixin.getName(), transformedName);
        this.applyMixin(transformedName, targetClass, mixin.createContextForTarget(targetClass));
    }

    // Extension point
    this.postTransform(transformedName, targetClass, mixins);

    // Run CheckClassAdapter on the mixin bytecode if debug option is enabled 
    if (MixinTransformer.DEBUG_VERIFY) {
        targetClass.accept(new CheckClassAdapter(new ClassWriter(ClassWriter.COMPUTE_FRAMES)));
    }

    // Collapse tree to bytes
    byte[] bytes = this.writeClass(targetClass);

    // Export transformed class for debugging purposes
    if (MixinTransformer.DEBUG_EXPORT) {
        try {
            FileUtils.writeByteArrayToFile(
                    new File(".mixin.out/" + transformedName.replace('.', '/') + ".class"), bytes);
        } catch (IOException ex) {
            // don't care
        }
    }

    return bytes;
}

From source file:org.spongepowered.asm.transformers.TreeTransformer.java

License:MIT License

/**
 * @param classNode ClassNode to write out
 * @return generated bytecode/*w  ww .ja v a  2s.  c om*/
 */
protected final byte[] writeClass(ClassNode classNode) {
    // Use optimised writer for speed
    if (this.classReader != null && this.classNode == classNode) {
        this.classNode = null;
        ClassWriter writer = new MixinClassWriter(this.classReader,
                ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
        this.classReader = null;
        classNode.accept(writer);
        return writer.toByteArray();
    }

    this.classNode = null;

    ClassWriter writer = new MixinClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.granite.launch.transformers.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }//w ww  .j  av  a  2s. c  o m

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = new ArrayList<>(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.lantern.launch.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }//from w  w  w . j a  v a  2  s . c  o m

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = Lists.newArrayListWithExpectedSize(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.lwts.transformer.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (this.modifiers == null) {
        this.modifiers = this.processor.build();
        this.processor = null;
    }/*ww  w .j a  va 2s . co m*/

    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = Lists.newArrayListWithExpectedSize(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.mod.asm.transformers.BaseEventTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {

    if (bytes == null || name == null) {
        return bytes;
    }/*  w w  w .  j a  v a2  s .com*/

    try {
        ClassReader cr = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();
        cr.accept(classNode, 0);

        String parentName = classNode.superName.replace('/', '.');

        Class<?> parent = this.getClass().getClassLoader().loadClass(parentName);

        // Skip classes that do not implement SpongeAPI Event, or extend other classes
        // This implies that there will be issues with custom event classes that extend a superclass that does not fit these conditions itself
        // However, this is a fairly fundamental JVM limitation
        if ((!Object.class.equals(parent.getSuperclass())) || (!Event.class.isAssignableFrom(parent))) {
            return bytes;
        }

        // Add forwarding methods
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createGetGameMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createGetSimpleNameMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createIsCancellableMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createIsCancelledMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createSetCancelledMethod());

        // Change super-class
        classNode.superName = "net/minecraftforge/fml/common/eventhandler/Event";

        // Replace super() call in constructor so that it points to the new super-class
        MethodNode method = ASMHelper.findMethod(classNode, "<init>", "()V");

        ListIterator<AbstractInsnNode> instructions = method.instructions.iterator();

        while (instructions.hasNext()) {
            AbstractInsnNode insn = instructions.next();
            if (insn.getOpcode() == Opcodes.INVOKESPECIAL) {
                MethodInsnNode methodInsn = new MethodInsnNode(Opcodes.INVOKESPECIAL, classNode.superName,
                        "<init>", "()V", false);
                instructions.remove();
                instructions.add(methodInsn);
                break;
            }
        }

        ClassWriter cw = new ClassWriter(cr, COMPUTE_MAXS | COMPUTE_FRAMES);
        classNode.accept(cw);
        return cw.toByteArray();
    } catch (Throwable t) {
        t.printStackTrace();
        return bytes;
    }
}

From source file:org.spongepowered.mod.asm.transformers.EventTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {

    if (bytes == null || transformedName.startsWith("net.minecraft.")
            || transformedName.equals("net.minecraftforge.fml.common.event.FMLEvent")
            || transformedName.equals("net.minecraftforge.fml.common.eventhandler.Event")
            || transformedName.indexOf('.') == -1) {
        return bytes;
    }//from w w w. ja  v  a 2  s . c o m

    try {
        ClassReader cr = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();
        cr.accept(classNode, 0);

        String parentName = classNode.superName.replace('/', '.');

        Class<?> parent = this.getClass().getClassLoader().loadClass(parentName);

        // Only process FMLEvents and Forge Events sub-classes

        if ((!Event.class.isAssignableFrom(parent)) && (!FMLEvent.class.isAssignableFrom(parent))) {
            return bytes;
        }

        Class<?> interf = events.get(transformedName);
        if (interf != null && interf.isInterface()) {
            String interfaceName = Type.getInternalName(interf);

            classNode.interfaces.add(interfaceName);
        }

        // Method forwarding for all events
        classNode.methods.add(createGetGameMethod());
        classNode.methods.add(createGetSimpleNameMethod());

        if (Event.class.isAssignableFrom(parent)) {
            // Forge Event method forwarding
            if (classNode.interfaces.contains("org/spongepowered/api/event/Cancellable")) {
                if (classNode.visibleAnnotations == null) {
                    classNode.visibleAnnotations = new ArrayList<AnnotationNode>();
                }
                classNode.visibleAnnotations
                        .add(new AnnotationNode("Lnet/minecraftforge/fml/common/eventhandler/Cancelable;"));
                classNode.methods.add(createIsCancelledMethod());
                classNode.methods.add(createSetCancelledMethod());
            }
            classNode.methods.add(createIsCancellableMethod());
        }

        // TODO: This is a temporary thing to make PreInit work. The different things needed to make different events work should be abstracted.
        if (interf != null && PreInitializationEvent.class.isAssignableFrom(interf)) {
            ASMHelper.generateSelfForwardingMethod(classNode, "getConfigurationDirectory",
                    "getModConfigurationDirectory", Type.getType(File.class));
            ASMHelper.generateSelfForwardingMethod(classNode, "getPluginLog", "getModLog",
                    Type.getType(Logger.class));
        }

        ClassWriter cw = new ClassWriter(cr, COMPUTE_MAXS | COMPUTE_FRAMES);

        classNode.accept(cw);
        return cw.toByteArray();
    } catch (Throwable t) {
        t.printStackTrace();
        return bytes;
    }
}

From source file:org.spongepowered.mod.asm.transformers.PriorityTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {

    if (bytes == null || !name.equals("cpw.mods.fml.common.eventhandler.EventPriority")) {
        return bytes;
    }/*from   w  w w .  jav a2 s. c  om*/

    try {
        ClassReader cr = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();
        cr.accept(classNode, 0);

        ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);
        CheckClassAdapter checker = new CheckClassAdapter(cw);
        classNode.accept(checker);
        return cw.toByteArray();
    } catch (Throwable t) {
        t.printStackTrace();
        return bytes;
    }
}

From source file:org.spongepowered.mod.asm.transformers.TreeTransformer.java

License:MIT License

/**
 * @param classNode//from  ww w  .  java  2 s .  c  om
 * @return
 */
protected final byte[] writeClass(ClassNode classNode) {
    // Use optimised writer for speed
    if (this.classReader != null && this.classNode == classNode) {
        this.classNode = null;
        ClassWriter writer = new ClassWriter(this.classReader,
                ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
        this.classReader = null;
        classNode.accept(writer);
        return writer.toByteArray();
    }

    this.classNode = null;

    ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    classNode.accept(writer);
    return writer.toByteArray();
}