Example usage for org.objectweb.asm Opcodes IRETURN

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

Introduction

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

Prototype

int IRETURN

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

Click Source Link

Usage

From source file:com.android.tools.layoutlib.create.DelegateMethodAdapter2.java

License:Apache License

/**
 * Generates the new code for the method.
 * <p/>/*  w  ww.  j  a  va  2 s . c om*/
 * For native methods, this must be invoked directly by {@link DelegateClassAdapter}
 * (since they have no code to visit).
 * <p/>
 * Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to
 * return this instance of {@link DelegateMethodAdapter2} and let the normal visitor pattern
 * invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then
 * this method will be invoked from {@link MethodVisitor#visitEnd()}.
 */
public void generateDelegateCode() {
    /*
     * The goal is to generate a call to a static delegate method.
     * If this method is non-static, the first parameter will be 'this'.
     * All the parameters must be passed and then the eventual return type returned.
     *
     * Example, let's say we have a method such as
     *   public void myMethod(int a, Object b, ArrayList<String> c) { ... }
     *
     * We'll want to create a body that calls a delegate method like this:
     *   TheClass_Delegate.myMethod(this, a, b, c);
     *
     * If the method is non-static and the class name is an inner class (e.g. has $ in its
     * last segment), we want to push the 'this' of the outer class first:
     *   OuterClass_InnerClass_Delegate.myMethod(
     *     OuterClass.this,
     *     OuterClass$InnerClass.this,
     *     a, b, c);
     *
     * Only one level of inner class is supported right now, for simplicity and because
     * we don't need more.
     *
     * The generated class name is the current class name with "_Delegate" appended to it.
     * One thing to realize is that we don't care about generics -- since generic types
     * are erased at build time, they have no influence on the method name being called.
     */

    // Add our annotation
    AnnotationVisitor aw = mDelWriter.visitAnnotation(
            Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(), true); // visible at runtime
    if (aw != null) {
        aw.visitEnd();
    }

    mDelWriter.visitCode();

    if (mDelegateLineNumber != null) {
        Object[] p = mDelegateLineNumber;
        mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]);
    }

    ArrayList<Type> paramTypes = new ArrayList<Type>();
    String delegateClassName = mClassName + DELEGATE_SUFFIX;
    boolean pushedArg0 = false;
    int maxStack = 0;

    // Check if the last segment of the class name has inner an class.
    // Right now we only support one level of inner classes.
    Type outerType = null;
    int slash = mClassName.lastIndexOf('/');
    int dol = mClassName.lastIndexOf('$');
    if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) {
        String outerClass = mClassName.substring(0, dol);
        outerType = Type.getObjectType(outerClass);

        // Change a delegate class name to "com/foo/Outer_Inner_Delegate"
        delegateClassName = delegateClassName.replace('$', '_');
    }

    // For an instance method (e.g. non-static), push the 'this' preceded
    // by the 'this' of any outer class, if any.
    if (!mIsStatic) {

        if (outerType != null) {
            // The first-level inner class has a package-protected member called 'this$0'
            // that points to the outer class.

            // Push this.getField("this$0") on the call stack.
            mDelWriter.visitVarInsn(Opcodes.ALOAD, 0); // var 0 = this
            mDelWriter.visitFieldInsn(Opcodes.GETFIELD, mClassName, // class where the field is defined
                    "this$0", // field name
                    outerType.getDescriptor()); // type of the field
            maxStack++;
            paramTypes.add(outerType);

        }

        // Push "this" for the instance method, which is always ALOAD 0
        mDelWriter.visitVarInsn(Opcodes.ALOAD, 0);
        maxStack++;
        pushedArg0 = true;
        paramTypes.add(Type.getObjectType(mClassName));
    }

    // Push all other arguments. Start at arg 1 if we already pushed 'this' above.
    Type[] argTypes = Type.getArgumentTypes(mDesc);
    int maxLocals = pushedArg0 ? 1 : 0;
    for (Type t : argTypes) {
        int size = t.getSize();
        mDelWriter.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals);
        maxLocals += size;
        maxStack += size;
        paramTypes.add(t);
    }

    // Construct the descriptor of the delegate based on the parameters
    // we pushed on the call stack. The return type remains unchanged.
    String desc = Type.getMethodDescriptor(Type.getReturnType(mDesc),
            paramTypes.toArray(new Type[paramTypes.size()]));

    // Invoke the static delegate
    mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, mMethodName, desc);

    Type returnType = Type.getReturnType(mDesc);
    mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN));

    mDelWriter.visitMaxs(maxStack, maxLocals);
    mDelWriter.visitEnd();

    // For debugging now. Maybe we should collect these and store them in
    // a text file for helping create the delegates. We could also compare
    // the text file to a golden and break the build on unsupported changes
    // or regressions. Even better we could fancy-print something that looks
    // like the expected Java method declaration.
    mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc);
}

From source file:com.android.tools.layoutlib.create.StubMethodAdapter.java

License:Apache License

private void generateInvoke() {
    /* Generates the code:
     *  OverrideMethod.invoke("signature", mIsNative ? true : false, null or this);
     *///w w w. j av  a2s  . c  o m
    mParentVisitor.visitLdcInsn(mInvokeSignature);
    // push true or false
    mParentVisitor.visitInsn(mIsNative ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
    // push null or this
    if (mIsStatic) {
        mParentVisitor.visitInsn(Opcodes.ACONST_NULL);
    } else {
        mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0);
    }

    int sort = mReturnType != null ? mReturnType.getSort() : Type.VOID;
    switch (sort) {
    case Type.VOID:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeV",
                "(Ljava/lang/String;ZLjava/lang/Object;)V");
        mParentVisitor.visitInsn(Opcodes.RETURN);
        break;
    case Type.BOOLEAN:
    case Type.CHAR:
    case Type.BYTE:
    case Type.SHORT:
    case Type.INT:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeI",
                "(Ljava/lang/String;ZLjava/lang/Object;)I");
        switch (sort) {
        case Type.BOOLEAN:
            Label l1 = new Label();
            mParentVisitor.visitJumpInsn(Opcodes.IFEQ, l1);
            mParentVisitor.visitInsn(Opcodes.ICONST_1);
            mParentVisitor.visitInsn(Opcodes.IRETURN);
            mParentVisitor.visitLabel(l1);
            mParentVisitor.visitInsn(Opcodes.ICONST_0);
            break;
        case Type.CHAR:
            mParentVisitor.visitInsn(Opcodes.I2C);
            break;
        case Type.BYTE:
            mParentVisitor.visitInsn(Opcodes.I2B);
            break;
        case Type.SHORT:
            mParentVisitor.visitInsn(Opcodes.I2S);
            break;
        }
        mParentVisitor.visitInsn(Opcodes.IRETURN);
        break;
    case Type.LONG:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeL",
                "(Ljava/lang/String;ZLjava/lang/Object;)J");
        mParentVisitor.visitInsn(Opcodes.LRETURN);
        break;
    case Type.FLOAT:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeF",
                "(Ljava/lang/String;ZLjava/lang/Object;)F");
        mParentVisitor.visitInsn(Opcodes.FRETURN);
        break;
    case Type.DOUBLE:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeD",
                "(Ljava/lang/String;ZLjava/lang/Object;)D");
        mParentVisitor.visitInsn(Opcodes.DRETURN);
        break;
    case Type.ARRAY:
    case Type.OBJECT:
        mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                "com/android/tools/layoutlib/create/OverrideMethod", "invokeA",
                "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;");
        mParentVisitor.visitTypeInsn(Opcodes.CHECKCAST, mReturnType.getInternalName());
        mParentVisitor.visitInsn(Opcodes.ARETURN);
        break;
    }

}

From source file:com.android.tools.layoutlib.create.StubMethodAdapter.java

License:Apache License

/**
 * For non-constructor, rewrite existing "return" instructions to write the message.
 *//*www . j a v  a  2  s . c  o m*/
public void visitInsn(int opcode) {
    if (mIsInitMethod) {
        switch (opcode) {
        case Opcodes.RETURN:
        case Opcodes.ARETURN:
        case Opcodes.DRETURN:
        case Opcodes.FRETURN:
        case Opcodes.IRETURN:
        case Opcodes.LRETURN:
            // Pop the last word from the stack since invoke will generate its own return.
            generatePop();
            generateInvoke();
            mMessageGenerated = true;
        default:
            mParentVisitor.visitInsn(opcode);
        }
    }
}

From source file:com.android.tools.lint.checks.AllowAllHostnameVerifierDetector.java

License:Apache License

@SuppressWarnings("rawtypes")
@Override//from  w  ww. ja  v  a  2s  .  co m
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!classNode.interfaces.contains("javax/net/ssl/HostnameVerifier")) {
        return;
    }
    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;
        if ("verify".equals(method.name)) {
            InsnList nodes = method.instructions;
            boolean emptyMethod = true; // Stays true if method has no instructions
                                        // other than ICONST_1 or IRETURN.
            boolean containsIconst1 = false;

            for (int i = 0, n = nodes.size(); i < n; i++) {
                // Future work: Improve this check to be less sensitive to irrelevant
                // instructions/statements/invocations (e.g. System.out.println).
                AbstractInsnNode instruction = nodes.get(i);
                int type = instruction.getType();
                if (type != AbstractInsnNode.LABEL && type != AbstractInsnNode.LINE
                        && !(type == AbstractInsnNode.INSN && (instruction.getOpcode() == Opcodes.ICONST_1
                                || instruction.getOpcode() == Opcodes.IRETURN))) {
                    emptyMethod = false;
                    break;
                } else if (type == AbstractInsnNode.INSN && instruction.getOpcode() == Opcodes.ICONST_1) {
                    containsIconst1 = true;
                }
            }
            if (containsIconst1 && emptyMethod) {
                Location location = context.getLocation(method, classNode);
                context.report(ISSUE, location,
                        method.name + " always returns true, which "
                                + "could cause insecure network traffic due to trusting TLS/SSL "
                                + "server certificates for wrong hostnames");
            }
        }
    }
}

From source file:com.android.tools.lint.checks.FieldGetterDetector.java

License:Apache License

private static Map<String, String> checkMethods(ClassNode classNode, Set<String> names) {
    Map<String, String> validGetters = Maps.newHashMap();
    @SuppressWarnings("rawtypes")
    List methods = classNode.methods;
    String fieldName = null;/*from  ww  w.j  av a2 s. c o  m*/
    checkMethod: for (Object methodObject : methods) {
        MethodNode method = (MethodNode) methodObject;
        if (names.contains(method.name) && method.desc.startsWith("()")) { //$NON-NLS-1$ // (): No arguments
            InsnList instructions = method.instructions;
            int mState = 1;
            for (AbstractInsnNode curr = instructions.getFirst(); curr != null; curr = curr.getNext()) {
                switch (curr.getOpcode()) {
                case -1:
                    // Skip label and line number nodes
                    continue;
                case Opcodes.ALOAD:
                    if (mState == 1) {
                        fieldName = null;
                        mState = 2;
                    } else {
                        continue checkMethod;
                    }
                    break;
                case Opcodes.GETFIELD:
                    if (mState == 2) {
                        FieldInsnNode field = (FieldInsnNode) curr;
                        fieldName = field.name;
                        mState = 3;
                    } else {
                        continue checkMethod;
                    }
                    break;
                case Opcodes.ARETURN:
                case Opcodes.FRETURN:
                case Opcodes.IRETURN:
                case Opcodes.DRETURN:
                case Opcodes.LRETURN:
                case Opcodes.RETURN:
                    if (mState == 3) {
                        validGetters.put(method.name, fieldName);
                    }
                    continue checkMethod;
                default:
                    continue checkMethod;
                }
            }
        }
    }

    return validGetters;
}

From source file:com.android.tools.lint.checks.WakelockDetector.java

License:Apache License

/** Search from the given node towards the target; return false if we reach
 * an exit point such as a return or a call on the way there that is not within
 * a try/catch clause.//  w w w.j a v  a  2 s  . com
 *
 * @param node the current node
 * @return true if the target was reached
 *    XXX RETURN VALUES ARE WRONG AS OF RIGHT NOW
 */
protected int dfs(ControlFlowGraph.Node node) {
    AbstractInsnNode instruction = node.instruction;
    if (instruction.getType() == AbstractInsnNode.JUMP_INSN) {
        int opcode = instruction.getOpcode();
        if (opcode == Opcodes.RETURN || opcode == Opcodes.ARETURN || opcode == Opcodes.LRETURN
                || opcode == Opcodes.IRETURN || opcode == Opcodes.DRETURN || opcode == Opcodes.FRETURN
                || opcode == Opcodes.ATHROW) {
            if (DEBUG) {
                System.out.println("Found exit via explicit return: " //$NON-NLS-1$
                        + node.toString(false));
            }
            return SEEN_RETURN;
        }
    }

    if (!DEBUG) {
        // There are no cycles, so no *NEED* for this, though it does avoid
        // researching shared labels. However, it makes debugging harder (no re-entry)
        // so this is only done when debugging is off
        if (node.visit != 0) {
            return 0;
        }
        node.visit = 1;
    }

    // Look for the target. This is any method call node which is a release on the
    // lock (later also check it's the same instance, though that's harder).
    // This is because finally blocks tend to be inlined so from a single try/catch/finally
    // with a release() in the finally, the bytecode can contain multiple repeated
    // (inlined) release() calls.
    if (instruction.getType() == AbstractInsnNode.METHOD_INSN) {
        MethodInsnNode method = (MethodInsnNode) instruction;
        if (method.name.equals(RELEASE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
            return SEEN_TARGET;
        } else if (method.name.equals(ACQUIRE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
            // OK
        } else if (method.name.equals(IS_HELD_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
            // OK
        } else {
            // Some non acquire/release method call: if this is not associated with a
            // try-catch block, it would mean the exception would exit the method,
            // which would be an error
            if (node.exceptions == null || node.exceptions.isEmpty()) {
                // Look up the corresponding frame, if any
                AbstractInsnNode curr = method.getPrevious();
                boolean foundFrame = false;
                while (curr != null) {
                    if (curr.getType() == AbstractInsnNode.FRAME) {
                        foundFrame = true;
                        break;
                    }
                    curr = curr.getPrevious();
                }

                if (!foundFrame) {
                    if (DEBUG) {
                        System.out.println("Found exit via unguarded method call: " //$NON-NLS-1$
                                + node.toString(false));
                    }
                    return SEEN_RETURN;
                }
            }
        }
    }

    // if (node.instruction is a call, and the call is not caught by
    // a try/catch block (provided the release is not inside the try/catch block)
    // then return false
    int status = 0;

    boolean implicitReturn = true;
    List<Node> successors = node.successors;
    List<Node> exceptions = node.exceptions;
    if (exceptions != null) {
        if (!exceptions.isEmpty()) {
            implicitReturn = false;
        }
        for (Node successor : exceptions) {
            status = dfs(successor) | status;
            if ((status & SEEN_RETURN) != 0) {
                if (DEBUG) {
                    System.out.println("Found exit via exception: " //$NON-NLS-1$
                            + node.toString(false));
                }
                return status;
            }
        }

        if (status != 0) {
            status |= SEEN_EXCEPTION;
        }
    }

    if (successors != null) {
        if (!successors.isEmpty()) {
            implicitReturn = false;
            if (successors.size() > 1) {
                status |= SEEN_BRANCH;
            }
        }
        for (Node successor : successors) {
            status = dfs(successor) | status;
            if ((status & SEEN_RETURN) != 0) {
                if (DEBUG) {
                    System.out.println("Found exit via branches: " //$NON-NLS-1$
                            + node.toString(false));
                }
                return status;
            }
        }
    }

    if (implicitReturn) {
        status |= SEEN_RETURN;
        if (DEBUG) {
            System.out.println("Found exit: via implicit return: " //$NON-NLS-1$
                    + node.toString(false));
        }
    }

    return status;
}

From source file:com.asakusafw.dag.compiler.codegen.DataComparatorGenerator.java

License:Apache License

private static void defineCompare(ClassWriter writer, DataModelReference reference,
        List<Group.Ordering> orderings) {
    MethodVisitor v = writer.visitMethod(Opcodes.ACC_PUBLIC, "compare", DESC_COMPARE, null,
            new String[] { typeOf(IOException.class).getInternalName(), });
    LocalVarRef a = new LocalVarRef(Opcodes.ALOAD, 1);
    LocalVarRef b = new LocalVarRef(Opcodes.ALOAD, 2);
    for (Group.Ordering ordering : orderings) {
        PropertyReference property = Invariants
                .requireNonNull(reference.findProperty(ordering.getPropertyName()));

        // int diff = ValueOptionSerDe.compareT({a, b}, {b, a});
        switch (ordering.getDirection()) {
        case ASCENDANT:
            a.load(v);/*from  w  ww.j a v  a 2  s .c  o m*/
            b.load(v);
            break;
        case DESCENDANT:
            b.load(v);
            a.load(v);
            break;
        default:
            throw new AssertionError(ordering);
        }
        v.visitMethodInsn(Opcodes.INVOKESTATIC, typeOf(ValueOptionSerDe.class).getInternalName(),
                Invariants.requireNonNull(METHOD_NAMES.get(property.getType())), DESC_COMPARE, false);
        LocalVarRef cmp = putLocalVar(v, Type.INT, 3);
        Label eq = new Label();

        // if (diff != 0) {
        cmp.load(v);
        v.visitJumpInsn(Opcodes.IFEQ, eq);

        // return diff;
        cmp.load(v);
        v.visitInsn(Opcodes.IRETURN);

        // } @ eq
        v.visitLabel(eq);
    }
    getConst(v, 0);
    v.visitInsn(Opcodes.IRETURN);
    v.visitMaxs(0, 0);
    v.visitEnd();
}

From source file:com.asakusafw.dag.compiler.codegen.ObjectComparatorGenerator.java

License:Apache License

private static void defineCompare(ClassWriter writer, DataModelReference reference,
        List<Group.Ordering> orderings) {
    MethodVisitor v = writer.visitMethod(Opcodes.ACC_PUBLIC, "compare",
            Type.getMethodDescriptor(typeOf(int.class), typeOf(Object.class), typeOf(Object.class)), null,
            null);//  w  ww .  j a  v  a2 s .co m
    LocalVarRef a = cast(v, 1, reference.getDeclaration());
    LocalVarRef b = cast(v, 2, reference.getDeclaration());
    for (Group.Ordering ordering : orderings) {
        LocalVarRef left;
        LocalVarRef right;
        switch (ordering.getDirection()) {
        case ASCENDANT:
            left = a;
            right = b;
            break;
        case DESCENDANT:
            left = b;
            right = a;
            break;
        default:
            throw new AssertionError(ordering);
        }

        // int diff = left.getXOption().compareTo(right.getXOption());
        PropertyReference property = Invariants
                .requireNonNull(reference.findProperty(ordering.getPropertyName()));
        left.load(v);
        getOption(v, property);
        right.load(v);
        getOption(v, property);
        v.visitMethodInsn(Opcodes.INVOKEINTERFACE, TYPE_COMPARABLE.getInternalName(), "compareTo",
                Type.getMethodDescriptor(typeOf(int.class), typeOf(Object.class)), true);
        LocalVarRef cmp = putLocalVar(v, Type.INT, 3);
        Label eq = new Label();

        // if (diff != 0) {
        cmp.load(v);
        v.visitJumpInsn(Opcodes.IFEQ, eq);

        // return diff;
        cmp.load(v);
        v.visitInsn(Opcodes.IRETURN);

        // } @ eq
        v.visitLabel(eq);
    }
    getConst(v, 0);
    v.visitInsn(Opcodes.IRETURN);
    v.visitMaxs(0, 0);
    v.visitEnd();
}

From source file:com.builtbroken.profiler.asm.WorldTransformer.java

/** {@link World#setBlock(int, int, int, Block, int, int)} */
private void injectSetBlock(ClassNode cn) {
    MethodNode setBlockMethod = getMethod(cn, "setBlock", "(IIIL" + getName(CLASS_KEY_BLOCK) + ";II)Z");

    if (setBlockMethod != null) {
        //Create method call
        final InsnList nodeAdd = new InsnList();

        nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 1));
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 3));
        nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, BLOCK_HOOK_CLASS, "onBlockChange",
                "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));

        //Inject method call at top of method
        setBlockMethod.instructions.insertBefore(setBlockMethod.instructions.get(0), nodeAdd);

        //Locate all return points from the method
        List<AbstractInsnNode> returnNodes = new ArrayList();
        for (int i = 0; i < setBlockMethod.instructions.size(); i++) {
            AbstractInsnNode ain = setBlockMethod.instructions.get(i);
            if (ain.getOpcode() == Opcodes.IRETURN) {
                returnNodes.add(ain);//from w  ww.  j  av  a 2  s  . co m
            }
        }

        //Inject calls in front of return points
        for (AbstractInsnNode node : returnNodes) {
            //Create method call
            final InsnList nodeAdd2 = new InsnList();
            nodeAdd2.add(new VarInsnNode(Opcodes.ALOAD, 0));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 1));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 2));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 3));
            nodeAdd2.add(new MethodInsnNode(Opcodes.INVOKESTATIC, BLOCK_HOOK_CLASS, "onPostBlockChange",
                    "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));
            //Inject method call before return node
            setBlockMethod.instructions.insertBefore(node, nodeAdd2);
        }
    }
}

From source file:com.builtbroken.profiler.asm.WorldTransformer.java

/** {@link World#setBlockMetadataWithNotify(int, int, int, int, int)} */
private void injectSetBlockWithMeta(ClassNode cn) {
    MethodNode setBlockMetaMethod = getMethod(cn, "setBlockMetadataWithNotify", "(IIIII)Z");

    if (setBlockMetaMethod != null) {
        final InsnList nodeAdd = new InsnList();

        nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0)); //this
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 1)); //x
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 2)); //y
        nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 3)); //z
        nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, BLOCK_HOOK_CLASS, "onBlockMetaChange",
                "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));

        setBlockMetaMethod.instructions.insertBefore(setBlockMetaMethod.instructions.get(0), nodeAdd);

        //Locate all return points from the method
        List<AbstractInsnNode> returnNodes = new ArrayList();
        for (int i = 0; i < setBlockMetaMethod.instructions.size(); i++) {
            AbstractInsnNode ain = setBlockMetaMethod.instructions.get(i);
            if (ain.getOpcode() == Opcodes.IRETURN) {
                returnNodes.add(ain);//from  ww w. jav a 2s.  c  om
            }
        }

        //Inject calls in front of return points
        for (AbstractInsnNode node : returnNodes) {
            //Create method call
            final InsnList nodeAdd2 = new InsnList();
            nodeAdd2.add(new VarInsnNode(Opcodes.ALOAD, 0));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 1));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 2));
            nodeAdd2.add(new VarInsnNode(Opcodes.ILOAD, 3));
            nodeAdd2.add(new MethodInsnNode(Opcodes.INVOKESTATIC, BLOCK_HOOK_CLASS, "onPostBlockMetaChange",
                    "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));
            //Inject method call before return node
            setBlockMetaMethod.instructions.insertBefore(node, nodeAdd2);
        }
    }
}