Example usage for org.objectweb.asm.tree MethodNode visitFieldInsn

List of usage examples for org.objectweb.asm.tree MethodNode visitFieldInsn

Introduction

In this page you can find the example usage for org.objectweb.asm.tree MethodNode visitFieldInsn.

Prototype

@Override
    public void visitFieldInsn(final int opcode, final String owner, final String name, final String descriptor) 

Source Link

Usage

From source file:clientapi.load.transform.impl.ValueAccessorTransformer.java

License:Apache License

/**
 * Creates the field-getter getter method in the specified {@code ClassNode}
 *
 * @param cn The ClassNode/*from w ww  .j a v  a  2  s. co  m*/
 */
private void createFieldGetter(ClassNode cn) {
    MethodNode mn = new MethodNode(ACC_PUBLIC | ACC_FINAL, "getFieldGetter",
            "(Ljava/lang/String;)Ljava/util/function/Supplier;", null, null);

    // Create a check for all labeled fields in the cache
    fieldCache.forEach((id, fn) -> {
        MethodNode handle;
        {
            // Create lambda handle method
            handle = new MethodNode(ACC_PRIVATE | ACC_SYNTHETIC, "lambda$getFieldGetter$" + current++,
                    "()Ljava/lang/Object;", null, null);

            // Get the field value
            handle.visitVarInsn(ALOAD, 0);
            handle.visitFieldInsn(GETFIELD, cn.name, fn.name, fn.desc);

            // If the field is a primitive type, get the object representation
            String object = getObject(fn.desc);
            if (!object.equals(fn.desc))
                handle.visitMethodInsn(INVOKESTATIC, object, "valueOf", "(" + fn.desc + ")L" + object + ";",
                        false);

            // Return the value
            handle.visitInsn(ARETURN);

            // Add the handle method to the class
            cn.methods.add(handle);
        }

        // Create label for IF statement jump
        Label skip = new Label();

        // Compare the target value with the expected value
        mn.visitVarInsn(ALOAD, 1);
        mn.visitLdcInsn(id);
        mn.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);

        // Jump if the input doesn't match the expected value
        mn.visitJumpInsn(IFEQ, skip);

        // Return the getter
        mn.visitVarInsn(ALOAD, 0);
        mn.visitInvokeDynamicInsn("get", "(L" + cn.name + ";)Ljava/util/function/Supplier;",
                // Define the bootstrap method
                METAFACTORY,
                // Fill the remaining 3 args for the method
                Type.getMethodType("()Ljava/lang/Object;"), createMethodHandle(H_INVOKESPECIAL, cn, handle),
                Type.getMethodType("()Ljava/lang/Object;"));
        mn.visitInsn(ARETURN);

        // Indicate where the IF statement should jump to if it fails
        mn.visitLabel(skip);
    });
    mn.visitInsn(ACONST_NULL);
    mn.visitInsn(ARETURN);

    cn.methods.add(mn);
}

From source file:clientapi.load.transform.impl.ValueAccessorTransformer.java

License:Apache License

/**
 * Creates the field-setter getter method in the specified {@code ClassNode}
 *
 * @see ValueAccessor//from ww  w  .j a  va 2s  . c o m
 *
 * @param cn The ClassNode
 */
private void createFieldSetter(ClassNode cn) {
    MethodNode mn = new MethodNode(ACC_PUBLIC | ACC_FINAL, "getFieldSetter",
            "(Ljava/lang/String;)Ljava/util/function/Consumer;", null, null);

    // Create a check for all labeled fields in the cache
    fieldCache.forEach((id, fn) -> {
        MethodNode handle;
        {
            // Create lambda handle method
            handle = new MethodNode(ACC_PRIVATE | ACC_SYNTHETIC, "lambda$getFieldSetter$" + current++,
                    "(Ljava/lang/Object;)V", null, null);

            handle.visitVarInsn(ALOAD, 0);
            handle.visitVarInsn(ALOAD, 1);
            handle.visitTypeInsn(CHECKCAST, getStrippedDesc(getObject(fn.desc)));

            // If the field is a primitive type, get the primitive value
            String object = getObject(fn.desc);
            if (!object.equals(fn.desc))
                handle.visitMethodInsn(INVOKEVIRTUAL, object, getClassName(fn.desc) + "Value", "()" + fn.desc,
                        false);

            // Set the field value
            handle.visitFieldInsn(PUTFIELD, cn.name, fn.name, fn.desc);
            handle.visitInsn(RETURN);

            // Add the handle method to the class
            cn.methods.add(handle);
        }

        // Create label for IF statement jump
        Label skip = new Label();

        // Compare the target value with the expected value
        mn.visitVarInsn(ALOAD, 1);
        mn.visitLdcInsn(id);
        mn.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);

        // Jump if the input doesn't match the expected value
        mn.visitJumpInsn(IFEQ, skip);

        // Return the setter
        mn.visitVarInsn(ALOAD, 0);
        mn.visitInvokeDynamicInsn("accept", "(L" + cn.name + ";)Ljava/util/function/Consumer;",
                // Define the bootstrap method
                METAFACTORY,
                // Fill the remaining 3 args for the method
                Type.getMethodType("(Ljava/lang/Object;)V"), createMethodHandle(H_INVOKESPECIAL, cn, handle),
                Type.getMethodType("(Ljava/lang/Object;)V"));
        mn.visitInsn(ARETURN);

        // Indicate where the IF statement should jump to if it fails
        mn.visitLabel(skip);
    });
    mn.visitInsn(ACONST_NULL);
    mn.visitInsn(ARETURN);

    cn.methods.add(mn);
}

From source file:com.seovic.pof.PortableTypeGenerator.java

License:Apache License

private void implementReadExternal() {
    int index = 0;

    MethodNode mn = new MethodNode(ACC_PRIVATE, "readExternal", "(Lcom/tangosol/io/pof/PofReader;)V", null,
            new String[] { "java/io/IOException" });
    mn.visitCode();/*  w ww. ja  v a2s .  com*/

    for (int version : properties.keySet()) {
        mn.visitVarInsn(ALOAD, 1);
        mn.visitMethodInsn(INVOKEINTERFACE, "com/tangosol/io/pof/PofReader", "getVersionId", "()I");
        mn.visitIntInsn(BIPUSH, version);
        Label l = new Label();
        mn.visitJumpInsn(IF_ICMPLT, l);

        SortedSet<FieldNode> fields = properties.get(version);
        for (FieldNode fn : fields) {
            Type type = Type.getType(fn.desc);

            if (isDebugEnabled()) {
                mn.visitLdcInsn("reading attribute " + index + " (" + fn.name + ") from POF stream");
                mn.visitIntInsn(BIPUSH, 7);
                mn.visitMethodInsn(INVOKESTATIC, "com/tangosol/net/CacheFactory", "log",
                        "(Ljava/lang/String;I)V");
            }
            mn.visitVarInsn(ALOAD, 0);
            mn.visitVarInsn(ALOAD, 1);
            mn.visitIntInsn(BIPUSH, index++);

            ReadMethod readMethod = getReadMethod(fn, type);
            readMethod.createTemplate(mn, fn, type);
            mn.visitMethodInsn(INVOKEINTERFACE, "com/tangosol/io/pof/PofReader", readMethod.getName(),
                    readMethod.getDescriptor());
            if (type.getSort() == Type.OBJECT || "readObjectArray".equals(readMethod.getName())) {
                mn.visitTypeInsn(CHECKCAST, type.getInternalName());
            }
            mn.visitFieldInsn(PUTFIELD, cn.name, fn.name, fn.desc);
        }

        mn.visitLabel(l);
        mn.visitFrame(F_SAME, 0, null, 0, null);
    }

    mn.visitInsn(RETURN);
    mn.visitMaxs(0, 0);
    mn.visitEnd();

    if (!hasMethod(mn)) {
        cn.methods.add(mn);
    }
    LOG.debug("Implemented method: " + mn.name);
}

From source file:com.seovic.pof.PortableTypeGenerator.java

License:Apache License

private void implementWriteExternal() {
    int index = 0;

    MethodNode mn = new MethodNode(ACC_PRIVATE, "writeExternal", "(Lcom/tangosol/io/pof/PofWriter;)V", null,
            new String[] { "java/io/IOException" });
    mn.visitCode();/*  w w  w  .  j  av  a 2 s.  c o m*/

    for (int version : properties.keySet()) {
        SortedSet<FieldNode> fields = properties.get(version);
        for (FieldNode fn : fields) {
            addPofIndex(fn, index);
            Type type = Type.getType(fn.desc);

            if (isDebugEnabled()) {
                mn.visitLdcInsn("writing attribute " + index + " (" + fn.name + ") to POF stream");
                mn.visitIntInsn(BIPUSH, 7);
                mn.visitMethodInsn(INVOKESTATIC, "com/tangosol/net/CacheFactory", "log",
                        "(Ljava/lang/String;I)V");
            }
            mn.visitVarInsn(ALOAD, 1);
            mn.visitIntInsn(BIPUSH, index++);
            mn.visitVarInsn(ALOAD, 0);
            mn.visitFieldInsn(GETFIELD, cn.name, fn.name, fn.desc);

            WriteMethod writeMethod = getWriteMethod(fn, type);
            writeMethod.pushUniformTypes(mn);
            mn.visitMethodInsn(INVOKEINTERFACE, "com/tangosol/io/pof/PofWriter", writeMethod.getName(),
                    writeMethod.getDescriptor());
        }
    }

    mn.visitInsn(RETURN);
    mn.visitMaxs(0, 0);
    mn.visitEnd();

    if (!hasMethod(mn)) {
        cn.methods.add(mn);
    }
    LOG.debug("Implemented method: " + mn.name);
}

From source file:de.sanandrew.core.manpack.transformer.TransformBadPotionsATN.java

License:Creative Commons License

private byte[] transformPotion(byte[] bytes) {
    ClassNode cn = ASMHelper.createClassNode(bytes);

    if (ASMHelper.hasClassMethodName(cn, ASMNames.M_isBadEffect)) {
        return bytes;
    }/*ww  w.j av  a 2s.  c  o  m*/

    MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC, ASMNames.M_isBadEffect, "()Z", null, null);
    method.visitCode();
    Label l0 = new Label();
    method.visitLabel(l0);
    method.visitVarInsn(Opcodes.ALOAD, 0);
    method.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/potion/Potion", ASMNames.F_isBadEffect, "Z");
    method.visitInsn(Opcodes.IRETURN);
    Label l1 = new Label();
    method.visitLabel(l1);
    method.visitLocalVariable("this", "Lnet/minecraft/potion/Potion;", null, l0, l1, 0);
    method.visitMaxs(0, 0);
    method.visitEnd();

    cn.methods.add(method);

    bytes = ASMHelper.createBytes(cn, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

    return bytes;
}

From source file:de.sanandrew.core.manpack.transformer.TransformELBAttackingPlayer.java

License:Creative Commons License

private static byte[] transformAttackingPlayer(byte[] bytes) {
    ClassNode clazz = ASMHelper.createClassNode(bytes);

    /** ADD GETTER FOR ATTACKING PLAYER **/
    {/*from  w  w  w  . ja v  a 2 s.  c  om*/
        MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC, "_SAP_getAttackingPlayer",
                "()Lnet/minecraft/entity/player/EntityPlayer;", null, null);
        method.visitCode();
        Label l0 = new Label();
        method.visitLabel(l0);
        method.visitVarInsn(Opcodes.ALOAD, 0);
        method.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/entity/EntityLivingBase",
                ASMNames.F_attackingPlayer, "Lnet/minecraft/entity/player/EntityPlayer;");
        method.visitInsn(Opcodes.ARETURN);
        Label l1 = new Label();
        method.visitLabel(l1);
        method.visitLocalVariable("this", "Lnet/minecraft/entity/EntityLivingBase;", null, l0, l1, 0);
        method.visitMaxs(0, 0);
        method.visitEnd();
        clazz.methods.add(method);
    }

    /** ADD SETTER FOR ATTACKING PLAYER **/
    {
        MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC, "_SAP_setAttackingPlayer",
                "(Lnet/minecraft/entity/player/EntityPlayer;)V", null, null);
        method.visitCode();
        Label l0 = new Label();
        method.visitLabel(l0);
        method.visitVarInsn(Opcodes.ALOAD, 0);
        method.visitVarInsn(Opcodes.ALOAD, 1);
        method.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/entity/EntityLivingBase",
                ASMNames.F_attackingPlayer, "Lnet/minecraft/entity/player/EntityPlayer;");
        Label l1 = new Label();
        method.visitLabel(l1);
        method.visitInsn(Opcodes.RETURN);
        Label l2 = new Label();
        method.visitLabel(l2);
        method.visitLocalVariable("this", "Lnet/minecraft/entity/EntityLivingBase;", null, l0, l2, 0);
        method.visitLocalVariable("player", "Lnet/minecraft/entity/player/EntityPlayer;", null, l0, l2, 1);
        method.visitMaxs(0, 0);
        method.visitEnd();
        clazz.methods.add(method);
    }

    /** ADD GETTER FOR RECENTLY HIT **/
    {
        MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC, "_SAP_getRecentlyHit", "()I", null, null);
        method.visitCode();
        Label l0 = new Label();
        method.visitLabel(l0);
        method.visitVarInsn(Opcodes.ALOAD, 0);
        method.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/entity/EntityLivingBase", ASMNames.F_recentlyHit,
                "I");
        method.visitInsn(Opcodes.IRETURN);
        Label l1 = new Label();
        method.visitLabel(l1);
        method.visitLocalVariable("this", "Lnet/minecraft/entity/EntityLivingBase;", null, l0, l1, 0);
        method.visitMaxs(0, 0);
        method.visitEnd();
        clazz.methods.add(method);
    }

    /** ADD SETTER FOR RECENTLY HIT **/
    {
        MethodNode method = new MethodNode(Opcodes.ACC_PUBLIC, "_SAP_setRecentlyHit", "(I)V", null, null);
        method.visitCode();
        Label l0 = new Label();
        method.visitLabel(l0);
        method.visitVarInsn(Opcodes.ALOAD, 0);
        method.visitVarInsn(Opcodes.ILOAD, 1);
        method.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/entity/EntityLivingBase", ASMNames.F_recentlyHit,
                "I");
        Label l1 = new Label();
        method.visitLabel(l1);
        method.visitInsn(Opcodes.RETURN);
        Label l2 = new Label();
        method.visitLabel(l2);
        method.visitLocalVariable("this", "Lnet/minecraft/entity/EntityLivingBase;", null, l0, l2, 0);
        method.visitLocalVariable("hit", "I", null, l0, l2, 1);
        method.visitMaxs(0, 0);
        method.visitEnd();
        clazz.methods.add(method);
    }

    bytes = ASMHelper.createBytes(clazz, /*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);

    return bytes;
}

From source file:org.jacoco.core.internal.analysis.filter.KotlinCoroutineFilterTest.java

License:Open Source License

@Test
public void should_filter_suspending_lambdas_generated_by_Kotlin_1_3_30() {
    final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "invokeSuspend",
            "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
    context.classAnnotations.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);

    m.visitLabel(new Label());
    final Range range1 = new Range();
    range1.fromInclusive = m.instructions.getLast();
    m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/coroutines/intrinsics/IntrinsicsKt",
            "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);
    m.visitVarInsn(Opcodes.ASTORE, 4);/*from w w w .  ja  va 2  s. c o m*/

    m.visitVarInsn(Opcodes.ALOAD, 0);
    // line of "runBlocking"
    m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I");
    final Label dflt = new Label();
    final Label state0 = new Label();
    final Label state1 = new Label();
    m.visitTableSwitchInsn(0, 1, dflt, state0, state1);

    m.visitLabel(state0);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V",
                false);
        range1.toInclusive = m.instructions.getLast();
    }

    // line before "suspendingFunction"
    m.visitInsn(Opcodes.NOP);

    // line of "suspendingFunction"
    m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
            "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);

    m.visitInsn(Opcodes.DUP);
    final Range range2 = new Range();
    range2.fromInclusive = m.instructions.getLast();
    m.visitVarInsn(Opcodes.ALOAD, 4);
    final Label continuationLabelAfterLoadedResult = new Label();
    m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
    // line of "runBlocking"
    m.visitVarInsn(Opcodes.ALOAD, 4);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(state1);

    m.visitVarInsn(Opcodes.ALOAD, 0);
    m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I");
    m.visitVarInsn(Opcodes.ISTORE, 3);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V",
                false);
    }
    m.visitVarInsn(Opcodes.ALOAD, 1);
    range2.toInclusive = m.instructions.getLast();
    m.visitLabel(continuationLabelAfterLoadedResult);

    // line after "suspendingFunction"
    m.visitInsn(Opcodes.NOP);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(dflt);
    final Range range0 = new Range();
    range0.fromInclusive = m.instructions.getLast();
    m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
    m.visitInsn(Opcodes.DUP);
    m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
    m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalStateException", "<init>",
            "(Ljava/lang/String;)V", false);
    m.visitInsn(Opcodes.ATHROW);
    range0.toInclusive = m.instructions.getLast();

    filter.filter(m, context, output);

    assertIgnored(range0, range1, range2);
}

From source file:org.jacoco.core.internal.analysis.filter.KotlinCoroutineFilterTest.java

License:Open Source License

/**
 * <pre>/* w  w  w . jav  a 2 s  .  c o  m*/
 *     runBlocking {
 *         val x = 42
 *         nop(x)
 *         suspendingFunction()
 *         nop(x)
 *     }
 * </pre>
 */
@Test
public void should_filter_suspending_lambdas() {
    final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "invokeSuspend",
            "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
    context.classAnnotations.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);

    m.visitLabel(new Label());
    final Range range1 = new Range();
    range1.fromInclusive = m.instructions.getLast();
    m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/coroutines/intrinsics/IntrinsicsKt",
            "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);
    m.visitVarInsn(Opcodes.ASTORE, 4);

    m.visitVarInsn(Opcodes.ALOAD, 0);
    // line of "runBlocking"
    m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I");
    final Label dflt = new Label();
    final Label state0 = new Label();
    final Label state1 = new Label();
    m.visitTableSwitchInsn(0, 1, dflt, state0, state1);

    m.visitLabel(state0);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitInsn(Opcodes.DUP);
        m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
        Label label = new Label();
        m.visitJumpInsn(Opcodes.IFEQ, label);
        m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
        m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", "exception", "Ljava/lang/Throwable");
        m.visitInsn(Opcodes.ATHROW);
        m.visitInsn(Opcodes.POP);
        range1.toInclusive = m.instructions.getLast();
        m.visitLabel(label);
    }

    // line before "suspendingFunction"
    m.visitInsn(Opcodes.NOP);

    // line of "suspendingFunction"
    m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
            "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);

    m.visitInsn(Opcodes.DUP);
    final Range range2 = new Range();
    range2.fromInclusive = m.instructions.getLast();
    m.visitVarInsn(Opcodes.ALOAD, 4);
    final Label continuationLabelAfterLoadedResult = new Label();
    m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
    // line of "runBlocking"
    m.visitVarInsn(Opcodes.ALOAD, 4);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(state1);

    m.visitVarInsn(Opcodes.ALOAD, 0);
    m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I");
    m.visitVarInsn(Opcodes.ISTORE, 3);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitInsn(Opcodes.DUP);
        m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
        final Label label = new Label();
        m.visitJumpInsn(Opcodes.IFEQ, label);
        m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
        m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", "exception", "Ljava/lang/Throwable");
        m.visitInsn(Opcodes.ATHROW);
        m.visitInsn(Opcodes.POP);
        m.visitLabel(label);
    }
    m.visitVarInsn(Opcodes.ALOAD, 1);
    range2.toInclusive = m.instructions.getLast();
    m.visitLabel(continuationLabelAfterLoadedResult);

    // line after "suspendingFunction"
    m.visitInsn(Opcodes.NOP);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(dflt);
    final Range range0 = new Range();
    range0.fromInclusive = m.instructions.getLast();
    m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
    m.visitInsn(Opcodes.DUP);
    m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
    m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalStateException", "<init>",
            "(Ljava/lang/String;)V", false);
    m.visitInsn(Opcodes.ATHROW);
    range0.toInclusive = m.instructions.getLast();

    filter.filter(m, context, output);

    assertIgnored(range0, range1, range2);
}

From source file:org.jacoco.core.internal.analysis.filter.KotlinCoroutineFilterTest.java

License:Open Source License

/**
 * <pre>/*from w  ww  . jav a 2s . c  o m*/
 *     suspend fun example() {
 *         suspendingFunction()
 *         nop()
 *     }
 * </pre>
 */
@Test
public void should_filter_suspending_functions() {
    final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, Opcodes.ACC_STATIC, "example",
            "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", null, null);
    context.classAnnotations.add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);

    final int continuationArgumentIndex = 0;
    final int continuationIndex = 2;

    m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
    final Range range1 = new Range();
    range1.fromInclusive = m.instructions.getLast();
    m.visitTypeInsn(Opcodes.INSTANCEOF, "ExampleKt$example$1");
    final Label createStateInstance = new Label();
    m.visitJumpInsn(Opcodes.IFEQ, createStateInstance);

    m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
    m.visitTypeInsn(Opcodes.CHECKCAST, "ExampleKt$example$1");
    m.visitVarInsn(Opcodes.ASTORE, continuationIndex);

    m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
    m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");

    m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE));
    m.visitInsn(Opcodes.IAND);
    m.visitJumpInsn(Opcodes.IFEQ, createStateInstance);

    m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
    m.visitInsn(Opcodes.DUP);
    m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");

    m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE));
    m.visitInsn(Opcodes.ISUB);
    m.visitFieldInsn(Opcodes.PUTFIELD, "ExampleKt$example$1", "label", "I");

    final Label afterCoroutineStateCreated = new Label();
    m.visitJumpInsn(Opcodes.GOTO, afterCoroutineStateCreated);

    m.visitLabel(createStateInstance);

    m.visitTypeInsn(Opcodes.NEW, "ExampleKt$example$1");
    m.visitInsn(Opcodes.DUP);
    m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
    m.visitMethodInsn(Opcodes.INVOKESPECIAL, "ExampleKt$example$1", "<init>",
            "(Lkotlin/coroutines/Continuation;)V", false);

    m.visitVarInsn(Opcodes.ASTORE, continuationIndex);

    m.visitLabel(afterCoroutineStateCreated);

    m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
    m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "result", "Ljava/lang/Object;");
    m.visitVarInsn(Opcodes.ASTORE, 1);

    m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/coroutines/intrinsics/IntrinsicsKt",
            "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);

    // line of "fun"
    m.visitVarInsn(Opcodes.ASTORE, 3);

    m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
    m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");
    final Label dflt = new Label();
    final Label state0 = new Label();
    final Label state1 = new Label();
    m.visitTableSwitchInsn(0, 1, dflt, state0, state1);

    m.visitLabel(state0);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitInsn(Opcodes.DUP);
        m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
        Label label = new Label();
        m.visitJumpInsn(Opcodes.IFEQ, label);
        m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
        m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", "exception", "Ljava/lang/Throwable");
        m.visitInsn(Opcodes.ATHROW);
        m.visitInsn(Opcodes.POP);
        range1.toInclusive = m.instructions.getLast();
        m.visitLabel(label);
    }

    // line of "suspendingFunction"
    m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
            "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);

    m.visitInsn(Opcodes.DUP);
    final Range range2 = new Range();
    range2.fromInclusive = m.instructions.getLast();
    m.visitVarInsn(Opcodes.ALOAD, 3);
    final Label continuationLabelAfterLoadedResult = new Label();
    m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
    // line of "fun"
    m.visitVarInsn(Opcodes.ALOAD, 3);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(state1);

    {
        m.visitVarInsn(Opcodes.ALOAD, 1);
        m.visitInsn(Opcodes.DUP);
        m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
        final Label label = new Label();
        m.visitJumpInsn(Opcodes.IFEQ, label);
        m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
        m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", "exception", "Ljava/lang/Throwable");
        m.visitInsn(Opcodes.ATHROW);
        m.visitInsn(Opcodes.POP);
        m.visitLabel(label);
    }
    m.visitVarInsn(Opcodes.ALOAD, 1);
    range2.toInclusive = m.instructions.getLast();
    m.visitLabel(continuationLabelAfterLoadedResult);

    // line after "suspendingFunction"
    m.visitInsn(Opcodes.NOP);
    m.visitInsn(Opcodes.ARETURN);

    m.visitLabel(dflt);
    final Range range0 = new Range();
    range0.fromInclusive = m.instructions.getLast();
    m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
    m.visitInsn(Opcodes.DUP);
    m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
    m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalStateException", "<init>",
            "(Ljava/lang/String;)V", false);
    m.visitInsn(Opcodes.ATHROW);
    range0.toInclusive = m.instructions.getLast();

    filter.filter(m, context, output);

    assertIgnored(range0, range1, range2);
}