Example usage for org.objectweb.asm Opcodes INVOKESPECIAL

List of usage examples for org.objectweb.asm Opcodes INVOKESPECIAL

Introduction

In this page you can find the example usage for org.objectweb.asm Opcodes INVOKESPECIAL.

Prototype

int INVOKESPECIAL

To view the source code for org.objectweb.asm Opcodes INVOKESPECIAL.

Click Source Link

Usage

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

License:MIT License

/**
 * Handle "imaginary super" invokations, these are invokations in
 * non-derived mixins for accessing methods known to exist in a supermixin
 * which is not directly inherited by this mixix. The method can only call
 * its <b>own</b> super-implmentation and the methd must also be tagged with
 * {@link SoftOverride} to indicate that the method must exist in a super
 * class./*from w  ww  . j a  va 2s  .  c  o m*/
 * 
 * @param method Method being processed
 * @param fieldInsn the GETFIELD insn which access the pseudo-field which is
 *      used as a handle to the superclass
 */
private void processImaginarySuper(MethodNode method, FieldInsnNode fieldInsn) {
    if (fieldInsn.getOpcode() != Opcodes.GETFIELD) {
        if (MixinTargetContext.INIT.equals(method.name)) {
            throw new InvalidMixinException(this, "Illegal imaginary super declaration: field " + fieldInsn.name
                    + " must not specify an initialiser");
        }

        throw new InvalidMixinException(this, "Illegal imaginary super access: found "
                + ASMHelper.getOpcodeName(fieldInsn.getOpcode()) + " opcode in " + method.name + method.desc);
    }

    if ((method.access & Opcodes.ACC_PRIVATE) != 0 || (method.access & Opcodes.ACC_STATIC) != 0) {
        throw new InvalidMixinException(this, "Illegal imaginary super access: method " + method.name
                + method.desc + " is private or static");
    }

    if (ASMHelper.getInvisibleAnnotation(method, SoftOverride.class) == null) {
        throw new InvalidMixinException(this, "Illegal imaginary super access: method " + method.name
                + method.desc + " is not decorated with @SoftOverride");
    }

    for (Iterator<AbstractInsnNode> methodIter = method.instructions
            .iterator(method.instructions.indexOf(fieldInsn)); methodIter.hasNext();) {
        AbstractInsnNode insn = methodIter.next();
        if (insn instanceof MethodInsnNode) {
            MethodInsnNode methodNode = (MethodInsnNode) insn;
            if (methodNode.owner.equals(this.getClassRef()) && methodNode.name.equals(method.name)
                    && methodNode.desc.equals(method.desc)) {
                methodNode.setOpcode(Opcodes.INVOKESPECIAL);
                this.updateStaticBinding(method, methodNode);
                return;
            }
        }
    }

    throw new InvalidMixinException(this,
            "Illegal imaginary super access: could not find INVOKE for " + method.name + method.desc);
}

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

License:MIT License

/**
 * Identifies line numbers in the supplied ctor which correspond to the
 * start and end of the method body./*w  ww . j  a  va  2 s  .  c  o  m*/
 * 
 * @param ctor
 * @return range indicating the line numbers of the specified constructor
 *      and the position of the superclass ctor invocation
 */
private Range getConstructorRange(MethodNode ctor) {
    int line = 0, start = 0, end = 0, superIndex = -1;
    for (Iterator<AbstractInsnNode> iter = ctor.instructions.iterator(); iter.hasNext();) {
        AbstractInsnNode insn = iter.next();
        if (insn instanceof LineNumberNode) {
            line = ((LineNumberNode) insn).line;
        } else if (insn instanceof MethodInsnNode) {
            if (insn.getOpcode() == Opcodes.INVOKESPECIAL
                    && MixinTransformer.INIT.equals(((MethodInsnNode) insn).name) && superIndex == -1) {
                superIndex = ctor.instructions.indexOf(insn);
                start = line;
            }
        } else if (insn.getOpcode() == Opcodes.RETURN) {
            end = line;
        }
    }

    return new Range(start, end, superIndex);
}

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

License:MIT License

/**
 * Inject initialiser code into the target constructor
 * /*w w w .  j  a va 2 s . c  o m*/
 * @param ctor
 * @param initialiser
 */
private void injectInitialiser(MethodNode ctor, InsnList initialiser) {
    for (Iterator<AbstractInsnNode> iter = ctor.instructions.iterator(0); iter.hasNext();) {
        AbstractInsnNode insn = iter.next();
        if (insn.getOpcode() == Opcodes.INVOKESPECIAL
                && MixinTransformer.INIT.equals(((MethodInsnNode) insn).name)) {
            ctor.instructions.insert(insn, initialiser);
        }
    }
}

From source file:org.spongepowered.despector.emitter.bytecode.instruction.BytecodeInstanceMethodInvokeEmitter.java

License:Open Source License

public int getOpcode(InstanceMethodInvoke.Type type) {
    switch (type) {
    case INTERFACE:
        return Opcodes.INVOKEINTERFACE;
    case SPECIAL:
        return Opcodes.INVOKESPECIAL;
    case VIRTUAL:
    default:/*from w w  w.j  a v a  2 s.  c o m*/
        return Opcodes.INVOKEVIRTUAL;
    }
}

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;
    }/* ww  w .  j av a2  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);

        // 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

protected static MethodNode createGetSimpleNameMethod() {
    MethodNode methodNode = new MethodNode(Opcodes.ASM4, Opcodes.ACC_PUBLIC, "getSimpleName",
            "()Ljava/lang/String;", null, null);
    methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
    methodNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Object", "getClass",
            "()Ljava/lang/Class;", false));
    methodNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getSimpleName",
            "()Ljava/lang/String;", false));
    methodNode.instructions.add(new InsnNode(Opcodes.ARETURN));
    methodNode.maxLocals = 1;//from  w  w w .java 2s. co m
    methodNode.maxStack = 1;
    return methodNode;
}

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

License:MIT License

protected static MethodNode createIsCancellableMethod() {
    MethodNode methodNode = new MethodNode(Opcodes.ASM4, Opcodes.ACC_PUBLIC, "isCancellable", "()Z", null,
            null);//  w w w  . jav a2 s.c  o  m
    methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
    methodNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
            "net/minecraftforge/fml/common/eventhandler/Event", "isCancelable", "()Z", false));
    methodNode.instructions.add(new InsnNode(Opcodes.IRETURN));
    methodNode.maxLocals = 1;
    methodNode.maxStack = 1;
    return methodNode;
}

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

License:MIT License

protected static MethodNode createIsCancelledMethod() {
    MethodNode methodNode = new MethodNode(Opcodes.ASM4, Opcodes.ACC_PUBLIC, "isCancelled", "()Z", null, null);
    methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
    methodNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
            "net/minecraftforge/fml/common/eventhandler/Event", "isCanceled", "()Z", false));
    methodNode.instructions.add(new InsnNode(Opcodes.IRETURN));
    methodNode.maxLocals = 1;//  w w w .ja va 2 s. c o  m
    methodNode.maxStack = 1;
    return methodNode;
}

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

License:MIT License

protected static MethodNode createSetCancelledMethod() {
    MethodNode methodNode = new MethodNode(Opcodes.ASM4, Opcodes.ACC_PUBLIC, "setCancelled", "(Z)V", null,
            null);//from w w w .jav  a  2  s  . c o m
    methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
    methodNode.instructions.add(new VarInsnNode(Opcodes.ILOAD, 1));
    methodNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
            "net/minecraftforge/fml/common/eventhandler/Event", "setCanceled", "(Z)V", false));
    methodNode.instructions.add(new InsnNode(Opcodes.RETURN));
    methodNode.maxLocals = 1;
    methodNode.maxStack = 1;
    return methodNode;
}

From source file:org.spongepowered.mod.asm.util.ASMEventListenerFactory.java

License:MIT License

@SuppressWarnings("unchecked")
private static <T> Class<T> createClass(Class<T> interf, Method input, Method output) {

    String className = getClassName(interf, input, output);

    ClassWriter cwBase = new ClassWriter(0);
    CheckClassAdapter cw = new CheckClassAdapter(cwBase);

    MethodVisitor mv;/*from  w  w  w  . j  a va 2 s .c  om*/

    String classNameDesc = className.replace('.', '/');

    String interfaceInternalName = Type.getInternalName(interf);

    String inputName = input.getName();
    String inputMethodDescriptor = Type.getMethodDescriptor(input);

    String outputParameterTypeIntName = Type.getInternalName(output.getParameterTypes()[0]);
    String outputTargetTypeIntName = Type.getInternalName(output.getDeclaringClass());
    String outputMethodDescriptor = Type.getMethodDescriptor(output);
    String outputName = output.getName();

    boolean isOutputInterface = output.getDeclaringClass().isInterface();

    // A new class of the following form is created, with a unique name
    //
    // package org.spongepowered.mod.asm;
    // public class <className> extends java.lang.Object implements <interf>
    //
    //     private final Object target
    //
    //     public <className> (java.lang.Object target) {
    //         super();
    //         this.target = target;
    //         return;
    //     }
    //
    //     public void <inputMethod> (<inputMethodType event) {
    //         ((outputTargetType) this.target).outputMethod((outputParameteType) event);
    //         return
    //     }
    // }

    // package org.spongepowered.mod.asm;
    // public class <className> extends java.lang.Object implements <interf>
    cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, classNameDesc, null, "java/lang/Object",
            new String[] { interfaceInternalName });

    // private final Object target
    cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "target", "Ljava/lang/Object;", null, null);

    // Constructor

    // public UniqueClass (java.lang.Object target) {
    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "(Ljava/lang/Object;)V", null, null);
    mv.visitCode();

    // super();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);

    // this.target = target;
    mv.visitVarInsn(Opcodes.ALOAD, 0); // Loads this
    mv.visitVarInsn(Opcodes.ALOAD, 1); // Loads target (from input)
    mv.visitFieldInsn(Opcodes.PUTFIELD, classNameDesc, "target", "Ljava/lang/Object;");

    // return;
    mv.visitInsn(Opcodes.RETURN);

    // }
    // 2 localvars due to inputs: this, target
    // 2 items on stack after double ALOAD
    mv.visitMaxs(2, 2);
    mv.visitEnd();

    // Callback method

    // public void <inputMethod> (<inputMethodType event) {
    mv = cw.visitMethod(Opcodes.ACC_PUBLIC, inputName, inputMethodDescriptor, null, null);
    mv.visitCode();

    // push((casted) this.target)
    mv.visitVarInsn(Opcodes.ALOAD, 0); // Loads this
    mv.visitFieldInsn(Opcodes.GETFIELD, classNameDesc, "target", "Ljava/lang/Object;");
    mv.visitTypeInsn(Opcodes.CHECKCAST, outputTargetTypeIntName);

    // push((casted) event)
    mv.visitVarInsn(Opcodes.ALOAD, 1); // Loads method parameter 0
    mv.visitTypeInsn(Opcodes.CHECKCAST, outputParameterTypeIntName);

    // ((outputTargetType) this.target).outputMethod((outputParameteType) event);
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, outputTargetTypeIntName, outputName, outputMethodDescriptor,
            isOutputInterface);

    // return
    mv.visitInsn(Opcodes.RETURN);

    // }
    mv.visitMaxs(2, 2);
    mv.visitEnd();

    cw.visitEnd();

    byte[] bytes = cwBase.toByteArray();

    return (Class<T>) loader.defineClass(className, bytes);
}