Example usage for org.objectweb.asm.commons InstructionAdapter visitInsn

List of usage examples for org.objectweb.asm.commons InstructionAdapter visitInsn

Introduction

In this page you can find the example usage for org.objectweb.asm.commons InstructionAdapter visitInsn.

Prototype

@Override
    public void visitInsn(final int opcode) 

Source Link

Usage

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void generateClassInit() {
    final InstructionAdapter mv = new InstructionAdapter(
            cw.visitMethod(ACC_STATIC, CLASS_INIT, Type.getMethodDescriptor(Type.VOID_TYPE), null, null));

    mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR, false);
    final Label initGlobal;
    if (samName != null) {
        // If the class is a SAM, allow having a ScriptFunction passed as class overrides
        final Label notAFunction = new Label();
        mv.dup();/* w  w  w  .ja v a 2s.co  m*/
        mv.instanceOf(SCRIPT_FUNCTION_TYPE);
        mv.ifeq(notAFunction);
        mv.checkcast(SCRIPT_FUNCTION_TYPE);

        // Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM
        // method(s).
        for (final MethodInfo mi : methodInfos) {
            if (mi.getName().equals(samName)) {
                mv.dup();
                loadMethodTypeAndGetHandle(mv, mi, GET_HANDLE_FUNCTION_DESCRIPTOR);
            } else {
                mv.visitInsn(ACONST_NULL);
            }
            mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
        }
        initGlobal = new Label();
        mv.goTo(initGlobal);
        mv.visitLabel(notAFunction);
    } else {
        initGlobal = null;
    }
    // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
    for (final MethodInfo mi : methodInfos) {
        mv.dup();
        mv.aconst(mi.getName());
        loadMethodTypeAndGetHandle(mv, mi, GET_HANDLE_OBJECT_DESCRIPTOR);
        mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
    }

    if (initGlobal != null) {
        mv.visitLabel(initGlobal);
    }
    // Assign "global = Context.getGlobal()"
    invokeGetGlobalWithNullCheck(mv);
    mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);

    generateConverterInit(mv, false);
    endInitMethod(mv);
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void generateConverterInit(final InstructionAdapter mv, final boolean samOnly) {
    assert !samOnly || !classOverride;
    for (final Map.Entry<Class<?>, String> converterField : converterFields.entrySet()) {
        final Class<?> returnType = converterField.getKey();
        if (!classOverride) {
            mv.visitVarInsn(ALOAD, 0);// w  w w.j ava2s  .  co m
        }

        if (samOnly && !samReturnTypes.contains(returnType)) {
            mv.visitInsn(ACONST_NULL);
        } else {
            mv.aconst(Type.getType(converterField.getKey()));
            mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getObjectConverter", GET_CONVERTER_METHOD_DESCRIPTOR,
                    false);
        }

        if (classOverride) {
            mv.putstatic(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR);
        } else {
            mv.putfield(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR);
        }
    }
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

/**
 * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype
 * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
 * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
 * all the method handle fields of the adapter instance with functions from the script object (or the script
 * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
 * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
 * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke
 * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType,
 * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity
 * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}.
 * The constructor that takes a script function will only initialize the methods with the same name as the single
 * abstract method. The constructor will also store the Nashorn global that was current at the constructor
 * invocation time in a field named "global". The generated constructor will be public, regardless of whether the
 * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the
 * supertype constructor was./*from  w w w  .  jav a2  s  .  c  o  m*/
 * @param ctor the supertype constructor that is serving as the base for the generated constructor.
 * @param fromFunction true if we're generating a constructor that initializes SAM types from a single
 * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a
 * ScriptObject passed to it.
 */
private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) {
    final Type originalCtorType = Type.getType(ctor);
    final Type[] originalArgTypes = originalCtorType.getArgumentTypes();
    final int argLen = originalArgTypes.length;
    final Type[] newArgTypes = new Type[argLen + 1];

    // Insert ScriptFunction|ScriptObject as the last argument to the constructor
    final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
    newArgTypes[argLen] = extraArgumentType;
    System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);

    // All constructors must be public, even if in the superclass they were protected.
    // Existing super constructor <init>(this, args...) triggers generating <init>(this, args..., scriptObj).
    // Any variable arity constructors become fixed-arity with explicit array arguments.
    final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
            Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));

    mv.visitCode();
    // First, invoke super constructor with original arguments. If the form of the constructor we're generating is
    // <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...).
    mv.visitVarInsn(ALOAD, 0);
    final Class<?>[] argTypes = ctor.getParameterTypes();
    int offset = 1; // First arg is at position 1, after this.
    for (int i = 0; i < argLen; ++i) {
        final Type argType = Type.getType(argTypes[i]);
        mv.load(offset, argType);
        offset += argType.getSize();
    }
    mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false);

    // Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method.
    final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR
            : GET_HANDLE_OBJECT_DESCRIPTOR;

    // Assign MethodHandle fields through invoking getHandle()
    for (final MethodInfo mi : methodInfos) {
        mv.visitVarInsn(ALOAD, 0);
        if (fromFunction && !mi.getName().equals(samName)) {
            // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
            // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overridden too. This
            // is a deliberate design choice. All other method handles are initialized to null.
            mv.visitInsn(ACONST_NULL);
        } else {
            mv.visitVarInsn(ALOAD, offset);
            if (!fromFunction) {
                mv.aconst(mi.getName());
            }
            loadMethodTypeAndGetHandle(mv, mi, getHandleDescriptor);
        }
        mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
    }

    // Assign "this.global = Context.getGlobal()"
    mv.visitVarInsn(ALOAD, 0);
    invokeGetGlobalWithNullCheck(mv);
    mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);

    // Initialize converters
    generateConverterInit(mv, fromFunction);
    endInitMethod(mv);

    if (!fromFunction) {
        newArgTypes[argLen] = OBJECT_TYPE;
        final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
                Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
        generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
    }
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv,
        final Constructor<?> ctor, final String ctorDescriptor) {
    mv.visitCode();/*from   w  w w.j  av  a2s  .  c  om*/
    mv.visitVarInsn(ALOAD, 0);
    final Class<?>[] argTypes = ctor.getParameterTypes();
    int offset = 1; // First arg is at position 1, after this.
    for (int i = 0; i < argTypes.length; ++i) {
        final Type argType = Type.getType(argTypes[i]);
        mv.load(offset, argType);
        offset += argType.getSize();
    }
    mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
    mv.visitVarInsn(ALOAD, offset);
    mv.visitInsn(ACONST_NULL);
    mv.visitInsn(ACONST_NULL);
    mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
    endInitMethod(mv);
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private static void endInitMethod(final InstructionAdapter mv) {
    mv.visitInsn(RETURN);
    endMethod(mv);
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

/**
 * Generates a method in the adapter class that adapts a method from the original class. The generated methods will
 * inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation
 * for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an
 * {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is
 * invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the
 * current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter
 * instance, the creating global is set to be the current global. In this case, the previously current global is
 * restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared
 * exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime
 * exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of
 * the method; this is guaranteed by the way constructors of the adapter class obtain them using
 * {@link #getHandle(Object, String, MethodType, boolean)}.
 * @param mi the method info describing the method to be generated.
 *//*from  w ww .j a v a 2s.co m*/
private void generateMethod(final MethodInfo mi) {
    final Method method = mi.method;
    final Class<?>[] exceptions = method.getExceptionTypes();
    final String[] exceptionNames = getExceptionNames(exceptions);
    final MethodType type = mi.type;
    final String methodDesc = type.toMethodDescriptorString();
    final String name = mi.getName();

    final Type asmType = Type.getMethodType(methodDesc);
    final Type[] asmArgTypes = asmType.getArgumentTypes();

    final InstructionAdapter mv = new InstructionAdapter(
            cw.visitMethod(getAccessModifiers(method), name, methodDesc, null, exceptionNames));
    mv.visitCode();

    final Label handleDefined = new Label();

    final Class<?> returnType = type.returnType();
    final Type asmReturnType = Type.getType(returnType);

    // See if we have overriding method handle defined
    if (classOverride) {
        mv.getstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
    } else {
        mv.visitVarInsn(ALOAD, 0);
        mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
    }
    // stack: [handle]
    mv.visitInsn(DUP);
    mv.visitJumpInsn(IFNONNULL, handleDefined);

    // No handle is available, fall back to default behavior
    if (Modifier.isAbstract(method.getModifiers())) {
        // If the super method is abstract, throw an exception
        mv.anew(UNSUPPORTED_OPERATION_TYPE);
        mv.dup();
        mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
        mv.athrow();
    } else {
        mv.visitInsn(POP);
        // If the super method is not abstract, delegate to it.
        emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
    }

    mv.visitLabel(handleDefined);
    // Load the creatingGlobal object
    if (classOverride) {
        // If class handle is defined, load the static defining global
        mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
    } else {
        mv.visitVarInsn(ALOAD, 0);
        mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
    }
    // stack: [creatingGlobal, handle]
    final Label setupGlobal = new Label();
    mv.visitLabel(setupGlobal);

    // Determine the first index for a local variable
    int nextLocalVar = 1; // "this" is at 0
    for (final Type t : asmArgTypes) {
        nextLocalVar += t.getSize();
    }
    // Set our local variable indices
    final int currentGlobalVar = nextLocalVar++;
    final int globalsDifferVar = nextLocalVar++;

    mv.dup();
    // stack: [creatingGlobal, creatingGlobal, handle]

    // Emit code for switching to the creating global
    // Global currentGlobal = Context.getGlobal();
    invokeGetGlobal(mv);
    mv.dup();

    mv.visitVarInsn(ASTORE, currentGlobalVar);
    // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
    // if(definingGlobal == currentGlobal) {
    final Label globalsDiffer = new Label();
    mv.ifacmpne(globalsDiffer);
    // stack: [creatingGlobal, handle]
    //     globalsDiffer = false
    mv.pop();
    // stack: [handle]
    mv.iconst(0); // false
    // stack: [false, handle]
    final Label invokeHandle = new Label();
    mv.goTo(invokeHandle);
    mv.visitLabel(globalsDiffer);
    // } else {
    //     Context.setGlobal(definingGlobal);
    // stack: [creatingGlobal, handle]
    invokeSetGlobal(mv);
    // stack: [handle]
    //     globalsDiffer = true
    mv.iconst(1);
    // stack: [true, handle]

    mv.visitLabel(invokeHandle);
    mv.visitVarInsn(ISTORE, globalsDifferVar);
    // stack: [handle]

    // Load all parameters back on stack for dynamic invocation. NOTE: since we're using a generic
    // Object(Object, Object, ...) type signature for the method, we must box all arguments here.
    int varOffset = 1;
    for (final Type t : asmArgTypes) {
        mv.load(varOffset, t);
        boxStackTop(mv, t);
        varOffset += t.getSize();
    }

    // Invoke the target method handle
    final Label tryBlockStart = new Label();
    mv.visitLabel(tryBlockStart);
    emitInvokeExact(mv, type.generic());
    convertReturnValue(mv, returnType, asmReturnType);
    final Label tryBlockEnd = new Label();
    mv.visitLabel(tryBlockEnd);
    emitFinally(mv, currentGlobalVar, globalsDifferVar);
    mv.areturn(asmReturnType);

    // If Throwable is not declared, we need an adapter from Throwable to RuntimeException
    final boolean throwableDeclared = isThrowableDeclared(exceptions);
    final Label throwableHandler;
    if (!throwableDeclared) {
        // Add "throw new RuntimeException(Throwable)" handler for Throwable
        throwableHandler = new Label();
        mv.visitLabel(throwableHandler);
        mv.anew(RUNTIME_EXCEPTION_TYPE);
        mv.dupX1();
        mv.swap();
        mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT,
                Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
        // Fall through to rethrow handler
    } else {
        throwableHandler = null;
    }
    final Label rethrowHandler = new Label();
    mv.visitLabel(rethrowHandler);
    // Rethrow handler for RuntimeException, Error, and all declared exception types
    emitFinally(mv, currentGlobalVar, globalsDifferVar);
    mv.athrow();
    final Label methodEnd = new Label();
    mv.visitLabel(methodEnd);

    mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd,
            currentGlobalVar);
    mv.visitLocalVariable("globalsDiffer", Type.BOOLEAN_TYPE.getDescriptor(), null, setupGlobal, methodEnd,
            globalsDifferVar);

    if (throwableDeclared) {
        mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
        assert throwableHandler == null;
    } else {
        mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
        mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
        for (final String excName : exceptionNames) {
            mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
        }
        mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
    }
    endMethod(mv);
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void convertReturnValue(final InstructionAdapter mv, final Class<?> returnType,
        final Type asmReturnType) {
    switch (asmReturnType.getSort()) {
    case Type.VOID:
        mv.pop();//ww  w  .j  a v  a  2 s. co m
        break;
    case Type.BOOLEAN:
        JSType.TO_BOOLEAN.invoke(mv);
        break;
    case Type.BYTE:
        JSType.TO_INT32.invoke(mv);
        mv.visitInsn(Opcodes.I2B);
        break;
    case Type.SHORT:
        JSType.TO_INT32.invoke(mv);
        mv.visitInsn(Opcodes.I2S);
        break;
    case Type.CHAR:
        // JSType doesn't have a TO_CHAR, so we have services supply us one.
        mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toCharPrimitive", TO_CHAR_PRIMITIVE_METHOD_DESCRIPTOR,
                false);
        break;
    case Type.INT:
        JSType.TO_INT32.invoke(mv);
        break;
    case Type.LONG:
        JSType.TO_LONG.invoke(mv);
        break;
    case Type.FLOAT:
        JSType.TO_NUMBER.invoke(mv);
        mv.visitInsn(Opcodes.D2F);
        break;
    case Type.DOUBLE:
        JSType.TO_NUMBER.invoke(mv);
        break;
    default:
        if (asmReturnType.equals(OBJECT_TYPE)) {
            // Must hide ConsString (and potentially other internal Nashorn types) from callers
            mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "exportReturnValue",
                    EXPORT_RETURN_VALUE_METHOD_DESCRIPTOR, false);
        } else if (asmReturnType.equals(STRING_TYPE)) {
            // Well-known conversion to String. Not using the JSType one as we want to preserve null as null instead
            // of the string "n,u,l,l".
            mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toString", TO_STRING_METHOD_DESCRIPTOR, false);
        } else {
            // Invoke converter method handle for everything else. Note that we could have just added an asType or
            // filterReturnValue to the invoked handle instead, but then every instance would have the function
            // method handle wrapped in a separate converter method handle, making handle.invokeExact() megamorphic.
            if (classOverride) {
                mv.getstatic(generatedClassName, converterFields.get(returnType),
                        METHOD_HANDLE_TYPE_DESCRIPTOR);
            } else {
                mv.visitVarInsn(ALOAD, 0);
                mv.getfield(generatedClassName, converterFields.get(returnType), METHOD_HANDLE_TYPE_DESCRIPTOR);
            }
            mv.swap();
            emitInvokeExact(mv, MethodType.methodType(returnType, Object.class));
        }
    }
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private static void boxStackTop(final InstructionAdapter mv, final Type t) {
    switch (t.getSort()) {
    case Type.BOOLEAN:
        invokeValueOf(mv, "Boolean", 'Z');
        break;// www .  ja v a  2 s  .com
    case Type.BYTE:
    case Type.SHORT:
    case Type.INT:
        // bytes and shorts get boxed as integers
        invokeValueOf(mv, "Integer", 'I');
        break;
    case Type.CHAR:
        invokeValueOf(mv, "Character", 'C');
        break;
    case Type.FLOAT:
        // floats get boxed as doubles
        mv.visitInsn(Opcodes.F2D);
        invokeValueOf(mv, "Double", 'D');
        break;
    case Type.LONG:
        invokeValueOf(mv, "Long", 'J');
        break;
    case Type.DOUBLE:
        invokeValueOf(mv, "Double", 'D');
        break;
    case Type.ARRAY:
    case Type.METHOD:
        // Already boxed
        break;
    case Type.OBJECT:
        if (t.equals(OBJECT_TYPE)) {
            mv.invokestatic(SCRIPTUTILS_TYPE_NAME, "unwrap", UNWRAP_METHOD_DESCRIPTOR, false);
        }
        break;
    default:
        // Not expecting anything else (e.g. VOID)
        assert false;
        break;
    }
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void generateFinalizerDelegate(final String finalizerDelegateName) {
    // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll
    // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see
    // generateFinalizerOverride()).
    final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
            finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE), null, null));

    // Simply invoke super.finalize()
    mv.visitVarInsn(ALOAD, 0);//from  w  ww  .  j  av  a 2 s  .  c o m
    mv.checkcast(Type.getType(generatedClassName));
    mv.invokespecial(superClassName, "finalize", Type.getMethodDescriptor(Type.VOID_TYPE), false);

    mv.visitInsn(RETURN);
    endMethod(mv);
}

From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java

License:Open Source License

private void generateFinalizerOverride(final String finalizerDelegateName) {
    final InstructionAdapter mv = new InstructionAdapter(
            cw.visitMethod(ACC_PUBLIC, "finalize", VOID_NOARG_METHOD_DESCRIPTOR, null, null));
    // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ...
    mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, finalizerDelegateName,
            Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE)));
    mv.visitVarInsn(ALOAD, 0);/*from w  ww.j a va  2 s .  co m*/
    // ...and invoke it through JavaAdapterServices.invokeNoPermissions
    mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "invokeNoPermissions",
            Type.getMethodDescriptor(METHOD_HANDLE_TYPE, OBJECT_TYPE), false);
    mv.visitInsn(RETURN);
    endMethod(mv);
}