Example usage for org.objectweb.asm.tree InsnList getLast

List of usage examples for org.objectweb.asm.tree InsnList getLast

Introduction

In this page you can find the example usage for org.objectweb.asm.tree InsnList getLast.

Prototype

public AbstractInsnNode getLast() 

Source Link

Document

Returns the last instruction in this list.

Usage

From source file:de.tuberlin.uebb.jbop.optimizer.var.LocalVarInliner.java

License:Open Source License

/**
 * Optimize.//from  www . ja  v  a  2  s.c  o  m
 * 
 * @param original
 *          the original
 * @param methodNode
 *          the method node
 * @return the insn list
 */
@Override
public InsnList optimize(final InsnList original, final MethodNode methodNode) {
    optimized = false;
    final Map<Integer, Object> knownValues = new HashMap<>();

    final AbstractInsnNode first = original.getFirst();
    final AbstractInsnNode last = original.getLast();
    handleNodes(first, last, original, knownValues, methodNode);

    return original;
}

From source file:io.moshisho.plugins.MyMojo.java

License:Apache License

private static void betterCompile(String classFile) throws IOException {

    InputStream is = new FileInputStream(classFile);
    ClassReader cr = new ClassReader(is);
    is.close();//  w  w  w.j a v a2 s.  com
    ClassNode cn = new ClassNode();
    cr.accept(cn, 0);

    List methods = cn.methods;
    for (int i = 0; i < methods.size(); ++i) {
        MethodNode method = (MethodNode) methods.get(i);

        if (!isStaticllyBound(method)) {
            continue;
        }

        InsnList instructions = method.instructions;
        AbstractInsnNode last = instructions.getLast();

        while (last != null && last.getType() == AbstractInsnNode.LABEL) {
            last = last.getPrevious();
        }

        if (last == null || !isReturnInstruction(last)
                || last.getPrevious().getType() != AbstractInsnNode.METHOD_INSN) {
            continue;
        }

        MethodInsnNode methodInv = (MethodInsnNode) last.getPrevious();

        if (!isRecursionCall(cn, method, methodInv)) {
            continue;
        }

        System.out.println("TailRec Optimizaing: " + method.name);

        // get arguments and types
        String methodDesc = method.desc;

        String argsDesc = methodDesc.substring(methodDesc.indexOf('(') + 1, methodDesc.indexOf(')'));
        System.out.println(argsDesc);

        // work with Type.getArgumentTypes
        List<AbstractInsnNode> listInstNodes = new LinkedList<AbstractInsnNode>();
        for (int j = argsDesc.length() - 1; j >= 0; j--) {
            char c = argsDesc.charAt(j);
            switch (c) {
            case 'I':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'Z':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'C':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'B':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'S':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'F':
                listInstNodes.add(new VarInsnNode(FSTORE, argsDesc.length() - j));
                break;
            case 'J':
                listInstNodes.add(new VarInsnNode(LSTORE, argsDesc.length() - j));
                break;
            case 'D':
                listInstNodes.add(new VarInsnNode(DSTORE, argsDesc.length() - j));
                break;
            case '[':
                // TODO:
            case 'L':
                // TODO:
            default:
                System.out.println("NOT TREATING: " + c);
            }

        }

        // remove the last aload_0 of the recursion
        AbstractInsnNode pnt = last;
        while (pnt != null && pnt.getOpcode() != 42
                && !(pnt.getOpcode() == 25 && ((VarInsnNode) pnt).var == 0)) {
            pnt = pnt.getPrevious();
        }
        method.instructions.remove(pnt);

        Collections.reverse(listInstNodes);
        for (AbstractInsnNode abstractInsnNode : listInstNodes) {
            method.instructions.insertBefore(last.getPrevious(), abstractInsnNode);
        }
        // place instead of return //goto

        LabelNode startOfMethodLabel = new LabelNode(new Label());
        method.instructions.insertBefore(method.instructions.getFirst(), startOfMethodLabel);
        JumpInsnNode gotoInst = new JumpInsnNode(GOTO, startOfMethodLabel);
        method.instructions.set(last.getPrevious(), gotoInst);
        method.instructions.remove(last);

        ClassWriter cw = new ClassWriter(0);
        cn.accept(cw);
        FileOutputStream fos = new FileOutputStream(classFile);
        fos.write(cw.toByteArray());
        fos.close();
    }
}

From source file:io.moshisho.plugins.OptimizeClasses.java

License:Apache License

private void optimize(File clz) throws Exception {
    InputStream is = new FileInputStream(clz);
    ClassReader cr = new ClassReader(is);
    is.close();/*from   w  w w.j av a  2  s  . co m*/
    ClassNode cn = new ClassNode();
    cr.accept(cn, 0);

    List methods = cn.methods;
    for (int i = 0; i < methods.size(); ++i) {
        MethodNode method = (MethodNode) methods.get(i);

        if (!isStaticllyBound(method)) {
            continue;
        }

        InsnList instructions = method.instructions;
        AbstractInsnNode last = instructions.getLast();

        while (last != null && last.getType() == AbstractInsnNode.LABEL) {
            last = last.getPrevious();
        }

        if (last == null || !isReturnInstruction(last)
                || last.getPrevious().getType() != AbstractInsnNode.METHOD_INSN) {
            continue;
        }

        MethodInsnNode methodInv = (MethodInsnNode) last.getPrevious();

        if (!isRecursionCall(cn, method, methodInv)) {
            continue;
        }

        getLog().info("TailRec Optimizaing: " + method.name);

        // get arguments and types
        String methodDesc = method.desc;

        String argsDesc = methodDesc.substring(methodDesc.indexOf('(') + 1, methodDesc.indexOf(')'));
        //System.out.println(argsDesc);

        // work with Type.getArgumentTypes
        List<AbstractInsnNode> listInstNodes = new LinkedList<AbstractInsnNode>();
        for (int j = argsDesc.length() - 1; j >= 0; j--) {
            char c = argsDesc.charAt(j);
            switch (c) {
            case 'I':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'Z':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'C':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'B':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'S':
                listInstNodes.add(new VarInsnNode(ISTORE, argsDesc.length() - j));
                break;
            case 'F':
                listInstNodes.add(new VarInsnNode(FSTORE, argsDesc.length() - j));
                break;
            case 'J':
                listInstNodes.add(new VarInsnNode(LSTORE, argsDesc.length() - j));
                break;
            case 'D':
                listInstNodes.add(new VarInsnNode(DSTORE, argsDesc.length() - j));
                break;
            case '[':
                // TODO:
            case 'L':
                // TODO:
            default:
                System.out.println("NOT TREATING: " + c);
            }

        }

        // remove the last aload_0 of the recursion
        AbstractInsnNode pnt = last;
        while (pnt != null && pnt.getOpcode() != 42
                && !(pnt.getOpcode() == 25 && ((VarInsnNode) pnt).var == 0)) {
            pnt = pnt.getPrevious();
        }
        method.instructions.remove(pnt);

        Collections.reverse(listInstNodes);
        for (AbstractInsnNode abstractInsnNode : listInstNodes) {
            method.instructions.insertBefore(last.getPrevious(), abstractInsnNode);
        }
        // place instead of return //goto

        LabelNode startOfMethodLabel = new LabelNode(new Label());
        method.instructions.insertBefore(method.instructions.getFirst(), startOfMethodLabel);
        JumpInsnNode gotoInst = new JumpInsnNode(GOTO, startOfMethodLabel);
        method.instructions.set(last.getPrevious(), gotoInst);
        method.instructions.remove(last);

        ClassWriter cw = new ClassWriter(0);
        cn.accept(cw);
        FileOutputStream fos = new FileOutputStream(clz);
        fos.write(cw.toByteArray());
        fos.close();
    }
}

From source file:net.doubledoordev.inventorylock.asm.Transformer.java

License:Open Source License

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
    ClassNode classNode = new ClassNode();
    ClassReader classReader = new ClassReader(basicClass);
    classReader.accept(classNode, READER_FLAGS);

    boolean isPlayer = transformedName.equals(ENTITY_PLAYER_OWNER_NAME);
    if (isPlayer)
        LOGGER.info("Found EntityPlayer");

    for (MethodNode method : classNode.methods) {
        InsnList list = method.instructions;
        if (isPlayer && INSTANCE.mapMethodDesc(method.desc).equals(ENTITY_PLAYER_DESC)
                && INSTANCE.mapMethodName(name, method.name, method.desc).equals(ENTITY_PLAYER_TARGET)) {
            final LabelNode newLabel = new LabelNode();
            LOGGER.info("Found canOpen");
            AbstractInsnNode node = list.getFirst();
            while (node.getOpcode() != IRETURN && node != list.getLast()) {
                if (node.getOpcode() == IFEQ)
                    ((JumpInsnNode) node).label = newLabel;
                node = node.getNext();/*from   www.  ja  v a 2s  .  co  m*/
            }
            if (node.getOpcode() != IRETURN)
                throw new RuntimeException("ASM failed. (return not found)");
            final AbstractInsnNode target = node;
            while (node.getType() != LABEL && node != list.getLast())
                node = node.getNext();
            if (node.getType() != LABEL)
                throw new RuntimeException("ASM failed. (label not found)");
            final LabelNode label = ((LabelNode) node);

            //Adding "else if (code instanceof BetterLockCode) return ((BetterLockCode) code).contains(this.getUniqueID());"
            InsnList inject = new InsnList();

            inject.add(newLabel);
            inject.add(new VarInsnNode(ALOAD, 1));
            inject.add(new TypeInsnNode(INSTANCEOF, BETTER_LOCK_TYPE));
            inject.add(new JumpInsnNode(IFEQ, label));
            inject.add(new VarInsnNode(ALOAD, 1));
            inject.add(new TypeInsnNode(CHECKCAST, BETTER_LOCK_TYPE));
            inject.add(new VarInsnNode(ALOAD, 0));
            //inject.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, ENTITY_PLAYER_OWNER, ENTITY_PLAYER_GET_UUID, ENTITY_PLATER_GET_UUID_DESC, false));
            inject.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, BETTER_LOCK_TYPE, BETTER_LOCK_CONTAINS,
                    BETTER_LOCK_CONTAINS_DESC, false));
            inject.add(new InsnNode(IRETURN));

            list.insert(target, inject);
            LOGGER.info("Injected elseif into EntityPlayer's canOpen");
        }
        for (AbstractInsnNode node = list.getFirst(); node != list.getLast(); node = node.getNext()) {
            if (node.getOpcode() != INVOKESTATIC)
                continue;
            MethodInsnNode methodInsnNode = ((MethodInsnNode) node);
            //                if (transformedName.equals("net.minecraft.tileentity.TileEntityLockable"))
            //                    LOGGER.info("In {} ({}) Method {}.{}{} Translated {}.{}{}", name, transformedName,
            //                            methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc,
            //                            INSTANCE.map(methodInsnNode.owner), INSTANCE.mapMethodName(methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc), INSTANCE.mapMethodDesc(methodInsnNode.desc).equals(LOCK_CODE_DESC));
            if (INSTANCE.map(methodInsnNode.owner).equals(LOCK_CODE_OWNER)
                    && INSTANCE.mapMethodDesc(methodInsnNode.desc).equals(LOCK_CODE_DESC)
                    && INSTANCE.mapMethodName(methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc)
                            .equals(LOCK_CODE_TARGET)) {
                methodInsnNode.owner = LOCK_CODE_OWNER_REPLACE;
                methodInsnNode.name = LOCK_CODE_NAME;
                LOGGER.info("Replaced call in class {} ({}), method {}{}", name, transformedName, method.name,
                        method.desc);
            }
        }
    }

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

From source file:org.apache.commons.javaflow.providers.asm3.ContinuableMethodNode.java

License:Apache License

void moveNew() throws AnalyzerException {
    final SourceInterpreter i = new SourceInterpreter();
    final Analyzer a = new Analyzer(i);
    a.analyze(className, this);

    final HashMap<AbstractInsnNode, MethodInsnNode> movable = new HashMap<AbstractInsnNode, MethodInsnNode>();

    final Frame[] frames = a.getFrames();
    for (int j = 0; j < methods.size(); j++) {
        final MethodInsnNode mnode = (MethodInsnNode) methods.get(j);
        // require to move NEW instruction
        int n = instructions.indexOf(mnode);
        Frame f = frames[n];//from ww  w .j  a  v a  2  s. c om
        Type[] args = Type.getArgumentTypes(mnode.desc);

        SourceValue v = (SourceValue) f.getStack(f.getStackSize() - args.length - 1);
        @SuppressWarnings("unchecked")
        Set<AbstractInsnNode> insns = v.insns;
        for (final AbstractInsnNode ins : insns) {
            if (ins.getOpcode() == NEW) {
                movable.put(ins, mnode);
            } else {
                // other known patterns
                int n1 = instructions.indexOf(ins);
                if (ins.getOpcode() == DUP) { // <init> with params
                    AbstractInsnNode ins1 = instructions.get(n1 - 1);
                    if (ins1.getOpcode() == NEW) {
                        movable.put(ins1, mnode);
                    }
                } else if (ins.getOpcode() == SWAP) { // in exception handler
                    AbstractInsnNode ins1 = instructions.get(n1 - 1);
                    AbstractInsnNode ins2 = instructions.get(n1 - 2);
                    if (ins1.getOpcode() == DUP_X1 && ins2.getOpcode() == NEW) {
                        movable.put(ins2, mnode);
                    }
                }
            }
        }
    }

    int updateMaxStack = 0;
    for (final Map.Entry<AbstractInsnNode, MethodInsnNode> e : movable.entrySet()) {
        AbstractInsnNode node1 = e.getKey();
        int n1 = instructions.indexOf(node1);
        AbstractInsnNode node2 = instructions.get(n1 + 1);
        AbstractInsnNode node3 = instructions.get(n1 + 2);
        int producer = node2.getOpcode();

        instructions.remove(node1); // NEW
        boolean requireDup = false;
        if (producer == DUP) {
            instructions.remove(node2); // DUP
            requireDup = true;
        } else if (producer == DUP_X1) {
            instructions.remove(node2); // DUP_X1
            instructions.remove(node3); // SWAP
            requireDup = true;
        }

        MethodInsnNode mnode = (MethodInsnNode) e.getValue();
        AbstractInsnNode nm = mnode;

        int varOffset = stackRecorderVar + 1;
        Type[] args = Type.getArgumentTypes(mnode.desc);

        // optimizations for some common cases
        if (args.length == 0) {
            final InsnList doNew = new InsnList();
            doNew.add(node1); // NEW
            if (requireDup)
                doNew.add(new InsnNode(DUP));
            instructions.insertBefore(nm, doNew);
            nm = doNew.getLast();
            continue;
        }

        if (args.length == 1 && args[0].getSize() == 1) {
            final InsnList doNew = new InsnList();
            doNew.add(node1); // NEW
            if (requireDup) {
                doNew.add(new InsnNode(DUP));
                doNew.add(new InsnNode(DUP2_X1));
                doNew.add(new InsnNode(POP2));
                updateMaxStack = updateMaxStack < 2 ? 2 : updateMaxStack; // a two extra slots for temp values
            } else
                doNew.add(new InsnNode(SWAP));
            instructions.insertBefore(nm, doNew);
            nm = doNew.getLast();
            continue;
        }

        // TODO this one untested!
        if ((args.length == 1 && args[0].getSize() == 2)
                || (args.length == 2 && args[0].getSize() == 1 && args[1].getSize() == 1)) {
            final InsnList doNew = new InsnList();
            doNew.add(node1); // NEW
            if (requireDup) {
                doNew.add(new InsnNode(DUP));
                doNew.add(new InsnNode(DUP2_X2));
                doNew.add(new InsnNode(POP2));
                updateMaxStack = updateMaxStack < 2 ? 2 : updateMaxStack; // a two extra slots for temp values
            } else {
                doNew.add(new InsnNode(DUP_X2));
                doNew.add(new InsnNode(POP));
                updateMaxStack = updateMaxStack < 1 ? 1 : updateMaxStack; // an extra slot for temp value
            }
            instructions.insertBefore(nm, doNew);
            nm = doNew.getLast();
            continue;
        }

        final InsnList doNew = new InsnList();
        // generic code using temporary locals
        // save stack
        for (int j = args.length - 1; j >= 0; j--) {
            Type type = args[j];

            doNew.add(new VarInsnNode(type.getOpcode(ISTORE), varOffset));
            varOffset += type.getSize();
        }
        if (varOffset > maxLocals) {
            maxLocals = varOffset;
        }

        doNew.add(node1); // NEW

        if (requireDup)
            doNew.add(new InsnNode(DUP));

        // restore stack
        for (int j = 0; j < args.length; j++) {
            Type type = args[j];
            varOffset -= type.getSize();

            doNew.add(new VarInsnNode(type.getOpcode(ILOAD), varOffset));

            // clean up store to avoid memory leak?
            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
                updateMaxStack = updateMaxStack < 1 ? 1 : updateMaxStack; // an extra slot for ACONST_NULL

                doNew.add(new InsnNode(ACONST_NULL));

                doNew.add(new VarInsnNode(type.getOpcode(ISTORE), varOffset));
            }
        }
        instructions.insertBefore(nm, doNew);
        nm = doNew.getLast();
    }

    maxStack += updateMaxStack;
}

From source file:org.evosuite.instrumentation.NodeRegularExpression.java

License:Open Source License

/**
 * <p>matches</p>//from w w w  . jav  a  2s.co  m
 *
 * @param instructions a {@link org.objectweb.asm.tree.InsnList} object.
 * @return a boolean.
 */
public boolean matches(InsnList instructions) {
    int match = 0;

    AbstractInsnNode node = instructions.getFirst();
    while (node != instructions.getLast()) {
        if (node.getType() == AbstractInsnNode.FRAME || node.getType() == AbstractInsnNode.LABEL
                || node.getType() == AbstractInsnNode.LINE) {
            node = node.getNext();
            continue;
        } else {
            boolean found = false;
            for (int opcode : pattern[match]) {
                if (node.getOpcode() == opcode) {
                    match++;
                    found = true;
                    break;
                }
            }
            if (!found)
                match = 0;
        }
        if (match == pattern.length)
            return true;

        node = node.getNext();
    }

    return false;
}

From source file:org.evosuite.instrumentation.NodeRegularExpression.java

License:Open Source License

/**
 * <p>getNextMatch</p>//w w  w. j  a  v  a 2s  . c o m
 *
 * @param start a {@link org.objectweb.asm.tree.AbstractInsnNode} object.
 * @param instructions a {@link org.objectweb.asm.tree.InsnList} object.
 * @return a {@link org.objectweb.asm.tree.AbstractInsnNode} object.
 */
public AbstractInsnNode getNextMatch(AbstractInsnNode start, InsnList instructions) {
    int match = 0;

    AbstractInsnNode node = start;
    AbstractInsnNode startNode = start;
    while (node != instructions.getLast()) {
        if (node.getType() == AbstractInsnNode.FRAME || node.getType() == AbstractInsnNode.LABEL
                || node.getType() == AbstractInsnNode.LINE) {
            node = node.getNext();
            continue;
        } else {
            boolean found = false;
            for (int opcode : pattern[match]) {
                if (node.getOpcode() == opcode) {
                    if (match == 0)
                        startNode = node;
                    match++;
                    found = true;
                    break;
                }
            }
            if (!found)
                match = 0;
        }
        if (match == pattern.length) {
            return startNode;
        }

        node = node.getNext();
    }

    return null;

}

From source file:org.parboiled.transform.process.LabellingGenerator.java

License:Apache License

@Override
public void process(@Nonnull final ParserClassNode classNode, @Nonnull final RuleMethod method)
        throws Exception {
    Objects.requireNonNull(classNode, "classNode");
    Objects.requireNonNull(method, "method");
    // super methods have flag moved to the overriding method
    Preconditions.checkState(!method.isSuperMethod());

    final InsnList instructions = method.instructions;

    AbstractInsnNode retInsn = instructions.getLast();
    while (retInsn.getOpcode() != ARETURN)
        retInsn = retInsn.getPrevious();

    final LabelNode label = new LabelNode();
    final CodeBlock block = CodeBlock.newCodeBlock().dup().ifnull(label).ldc(getLabelText(method))
            .invokeinterface(CodegenUtils.p(Rule.class), "label", CodegenUtils.sig(Rule.class, String.class))
            .label(label);/*from   w ww .j  a  v a  2 s.c  o  m*/

    instructions.insertBefore(retInsn, block.getInstructionList());
}

From source file:org.parboiled.transform.process.VarFramingGenerator.java

License:Apache License

@Override
public void process(@Nonnull final ParserClassNode classNode, @Nonnull final RuleMethod method)
        throws Exception {
    Objects.requireNonNull(classNode, "classNode");
    Objects.requireNonNull(method, "method");
    final InsnList instructions = method.instructions;

    AbstractInsnNode ret = instructions.getLast();
    while (ret.getOpcode() != ARETURN)
        ret = ret.getPrevious();/*  w w  w  .  ja  v  a 2  s . c  o  m*/

    final CodeBlock block = CodeBlock.newCodeBlock();

    block.newobj(CodegenUtils.p(VarFramingMatcher.class)).dup_x1().swap();

    createVarFieldArray(block, method);

    block.invokespecial(CodegenUtils.p(VarFramingMatcher.class), "<init>",
            CodegenUtils.sig(void.class, Rule.class, Var[].class));

    instructions.insertBefore(ret, block.getInstructionList());

    method.setBodyRewritten();
}

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

License:MIT License

/**
 * Get insns corresponding to the instance initialiser (hopefully) from the
 * supplied constructor.//from  w  ww  . jav a 2 s . c  o  m
 * 
 * TODO Potentially rewrite this to be less horrible.
 * 
 * @param mixin
 * @param ctor
 * @return initialiser bytecode extracted from the supplied constructor, or
 *      null if the constructor range could not be parsed
 */
private InsnList getInitialiser(MixinTargetContext mixin, MethodNode ctor) {
    // Find the range of line numbers which corresponds to the constructor body
    Range init = this.getConstructorRange(ctor);
    if (!init.isValid()) {
        return null;
    }

    // Now we know where the constructor is, look for insns which lie OUTSIDE the method body
    int line = 0;
    InsnList initialiser = new InsnList();
    boolean gatherNodes = false;
    int trimAtOpcode = -1;
    LabelNode optionalInsn = null;
    for (Iterator<AbstractInsnNode> iter = ctor.instructions.iterator(init.marker); iter.hasNext();) {
        AbstractInsnNode insn = iter.next();
        if (insn instanceof LineNumberNode) {
            line = ((LineNumberNode) insn).line;
            AbstractInsnNode next = ctor.instructions.get(ctor.instructions.indexOf(insn) + 1);
            if (line == init.end && next.getOpcode() != Opcodes.RETURN) {
                gatherNodes = true;
                trimAtOpcode = Opcodes.RETURN;
            } else {
                gatherNodes = init.excludes(line);
                trimAtOpcode = -1;
            }
        } else if (gatherNodes) {
            if (optionalInsn != null) {
                initialiser.add(optionalInsn);
                optionalInsn = null;
            }

            if (insn instanceof LabelNode) {
                optionalInsn = (LabelNode) insn;
            } else {
                int opcode = insn.getOpcode();
                if (opcode == trimAtOpcode) {
                    trimAtOpcode = -1;
                    continue;
                }
                for (int ivalidOp : MixinTransformer.INITIALISER_OPCODE_BLACKLIST) {
                    if (opcode == ivalidOp) {
                        // At the moment I don't handle any transient locals because I haven't seen any in the wild, but let's avoid writing
                        // code which will likely break things and fix it if a real test case ever appears
                        throw new InvalidMixinException(mixin,
                                "Cannot handle " + ASMHelper.getOpcodeName(opcode) + " opcode (0x"
                                        + Integer.toHexString(opcode).toUpperCase() + ") in class initialiser");
                    }
                }

                initialiser.add(insn);
            }
        }
    }

    // Check that the last insn is a PUTFIELD, if it's not then 
    AbstractInsnNode last = initialiser.getLast();
    if (last != null) {
        if (last.getOpcode() != Opcodes.PUTFIELD) {
            throw new InvalidMixinException(mixin, "Could not parse initialiser, expected 0xB5, found 0x"
                    + Integer.toHexString(last.getOpcode()));
        }
    }

    return initialiser;
}