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

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

Introduction

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

Prototype

@Override
    public void visitLabel(final Label label) 

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 .j  a v a 2s. com*/
        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

/**
 * 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 www . j a  va2 s  . 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

/**
 * Emit code to restore the previous Nashorn Context when needed.
 * @param mv the instruction adapter/*from ww  w. ja  v a 2s .c  o m*/
 * @param currentGlobalVar index of the local variable holding the reference to the current global at method
 * entry.
 * @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored.
 */
private static void emitFinally(final InstructionAdapter mv, final int currentGlobalVar,
        final int globalsDifferVar) {
    // Emit code to restore the previous Nashorn global if needed
    mv.visitVarInsn(ILOAD, globalsDifferVar);
    final Label skip = new Label();
    mv.ifeq(skip);
    mv.visitVarInsn(ALOAD, currentGlobalVar);
    invokeSetGlobal(mv);
    mv.visitLabel(skip);
}