Example usage for org.objectweb.asm Opcodes ALOAD

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

Introduction

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

Prototype

int ALOAD

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

Click Source Link

Usage

From source file:jpcsp.Allegrex.compiler.CodeBlock.java

License:Open Source License

private void addConstructor(ClassVisitor cv) {
    MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitCode();//  w  w  w.  ja v  a2 s  . c o m
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, objectInternalName, "<init>", "()V");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();
}

From source file:jpcsp.Allegrex.compiler.CodeBlock.java

License:Open Source License

private void addNonStaticMethods(CompilerContext context, ClassVisitor cv) {
    MethodVisitor mv;//from  ww  w  . jav a  2  s . c o  m

    // public int exec(int returnAddress, int alternativeReturnAddress, boolean isJump) throws Exception;
    mv = cv.visitMethod(Opcodes.ACC_PUBLIC, context.getExecMethodName(), context.getExecMethodDesc(), null,
            exceptions);
    mv.visitCode();
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, getClassName(), context.getStaticExecMethodName(),
            context.getStaticExecMethodDesc());
    mv.visitInsn(Opcodes.IRETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();

    // private static IExecutable e;
    FieldVisitor fv = cv.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, context.getReplaceFieldName(),
            executableDescriptor, null, null);
    fv.visitEnd();

    // public void setExecutable(IExecutable e);
    mv = cv.visitMethod(Opcodes.ACC_PUBLIC, context.getReplaceMethodName(), context.getReplaceMethodDesc(),
            null, exceptions);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 1);
    mv.visitFieldInsn(Opcodes.PUTSTATIC, getClassName(), context.getReplaceFieldName(), executableDescriptor);
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(1, 2);
    mv.visitEnd();

    // public IExecutable getExecutable();
    mv = cv.visitMethod(Opcodes.ACC_PUBLIC, context.getGetMethodName(), context.getGetMethodDesc(), null,
            exceptions);
    mv.visitCode();
    mv.visitFieldInsn(Opcodes.GETSTATIC, getClassName(), context.getReplaceFieldName(), executableDescriptor);
    mv.visitInsn(Opcodes.ARETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();
}

From source file:jpcsp.Allegrex.compiler.CompilerContext.java

License:Open Source License

private void loadCpu() {
    if (storeCpuLocal) {
        mv.visitVarInsn(Opcodes.ALOAD, LOCAL_CPU);
    } else {//from  w w w  .j  a va  2  s.  c  o  m
        mv.visitFieldInsn(Opcodes.GETSTATIC, runtimeContextInternalName, "cpu", cpuDescriptor);
    }
}

From source file:jpcsp.Allegrex.compiler.CompilerContext.java

License:Open Source License

/**
 * Generate the required Java code to call a syscall function.
 * The code generated must match the Java behavior implemented in
 * jpcsp.HLE.modules.HLEModuleFunctionReflection
 *
 * The following code is generated:// ww  w .j  a v  a  2s.  c o  m
 *     if (func.getFirmwareVersion() <= RuntimeContext.firmwareVersion) {
 *         if (!fastSyscall) {
 *             RuntimeContext.preSyscall();
 *         }
 *         if (func.checkInsideInterrupt()) {
 *             if (IntrManager.getInstance.isInsideInterrupt()) {
 *                 cpu.gpr[_v0] = SceKernelErrors.ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT;
 *                 goto afterSyscall;
 *             }
 *         }
 *         if (func.checkDispatchThreadEnabled()) {
 *             if (!Modules.ThreadManForUserModule.isDispatchThreadEnabled()) {
 *                 cpu.gpr[_v0] = SceKernelErrors.ERROR_KERNEL_WAIT_CAN_NOT_WAIT;
 *                 goto afterSyscall;
 *             }
 *         }
 *         if (func.isUnimplemented()) {
 *             Modules.getLogger(func.getModuleName()).warn("Unimplemented <function name> parameterName1=parameterValue1, parameterName2=parameterValue2, ...");
 *         }
 *         foreach parameter {
 *             loadParameter(parameter);
 *         }
 *         try {
 *             returnValue = <module name>.<function name>(...parameters...);
 *             storeReturnValue();
 *             if (parameterReader.hasErrorPointer()) {
 *                 errorPointer.setValue(0);
 *             }
 *         } catch (SceKernelErrorException e) {
 *             errorCode = e.errorCode;
 *             if (Modules.getLogger(func.getModuleName()).isDebugEnabled()) {
 *                 Modules.getLogger(func.getModuleName()).debug(String.format("<function name> return errorCode 0x%08X", errorCode));
 *             }
 *             if (parameterReader.hasErrorPointer()) {
 *                 errorPointer.setValue(errorCode);
 *                 cpu.gpr[_v0] = 0;
 *             } else {
 *                 cpu.gpr[_v0] = errorCode;
 *             }
 *             reload cpu.gpr[_ra]; // an exception is always clearing the whole stack
 *         }
 *         afterSyscall:
 *         if (fastSyscall) {
 *             RuntimeContext.postSyscallFast();
 *         } else {
 *             RuntimeContext.postSyscall();
 *         }
 *     } else {
 *         Modules.getLogger(func.getModuleName()).warn("<function name> is not supported in firmware version <firmwareVersion>, it requires at least firmware version <function firmwareVersion>");
 *         cpu.gpr[_v0] = -1;
 *     }
 *
 * @param func         the syscall function
 * @param fastSyscall  true if this is a fast syscall (i.e. without context switching)
 *                     false if not (i.e. a syscall where context switching could happen)
 */
private void visitSyscall(HLEModuleFunction func, boolean fastSyscall) {
    // The compilation of a syscall requires more stack size than usual
    maxStackSize = SYSCALL_MAX_STACK_SIZE;

    boolean needFirmwareVersionCheck = true;
    if (func.getFirmwareVersion() >= 999) {
        // Dummy version number meaning valid for all versions
        needFirmwareVersionCheck = false;
    } else if (isCodeInstructionInKernelMemory()) {
        // When compiling code in the kernel memory space, do not perform any version check.
        // This is used by overwritten HLE functions.
        needFirmwareVersionCheck = false;
    } else {
        // When compiling code loaded from flash0, do not perform any version check.
        // This is used by overwritten HLE functions.
        SceModule module = Managers.modules.getModuleByAddress(codeInstruction.getAddress());
        if (module != null && module.pspfilename != null && module.pspfilename.startsWith("flash0:")) {
            if (log.isDebugEnabled()) {
                log.debug(String.format("syscall from a flash0 module(%s, '%s'), no firmware version check",
                        module, module.pspfilename));
            }
            needFirmwareVersionCheck = false;
        }
    }

    Label unsupportedVersionLabel = null;
    if (needFirmwareVersionCheck) {
        unsupportedVersionLabel = new Label();
        loadImm(func.getFirmwareVersion());
        mv.visitFieldInsn(Opcodes.GETSTATIC, runtimeContextInternalName, "firmwareVersion", "I");
        mv.visitJumpInsn(Opcodes.IF_ICMPGT, unsupportedVersionLabel);
    }

    // Save the syscall parameter to locals for debugging
    if (!fastSyscall) {
        saveParametersToLocals();
    }

    if (!fastSyscall) {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeContextInternalName, "preSyscall", "()V");
    }

    Label afterSyscallLabel = new Label();

    if (func.checkInsideInterrupt()) {
        // if (IntrManager.getInstance().isInsideInterrupt()) {
        //     if (Modules.getLogger(func.getModuleName()).isDebugEnabled()) {
        //         Modules.getLogger(func.getModuleName()).debug("<function name> return errorCode 0x80020064 (ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT)");
        //     }
        //     cpu.gpr[_v0] = SceKernelErrors.ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT;
        //     goto afterSyscall
        // }
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(IntrManager.class), "getInstance",
                "()" + Type.getDescriptor(IntrManager.class));
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(IntrManager.class), "isInsideInterrupt",
                "()Z");
        Label notInsideInterrupt = new Label();
        mv.visitJumpInsn(Opcodes.IFEQ, notInsideInterrupt);

        loadModuleLoggger(func);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Logger.class), "isDebugEnabled", "()Z");
        Label notDebug = new Label();
        mv.visitJumpInsn(Opcodes.IFEQ, notDebug);
        loadModuleLoggger(func);
        mv.visitLdcInsn(
                String.format("%s returning errorCode 0x%08X (ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT)",
                        func.getFunctionName(), SceKernelErrors.ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT));
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Logger.class), "debug",
                "(" + Type.getDescriptor(Object.class) + ")V");
        mv.visitLabel(notDebug);

        storeRegister(_v0, SceKernelErrors.ERROR_KERNEL_CANNOT_BE_CALLED_FROM_INTERRUPT);
        mv.visitJumpInsn(Opcodes.GOTO, afterSyscallLabel);
        mv.visitLabel(notInsideInterrupt);
    }

    if (func.checkDispatchThreadEnabled()) {
        // if (!Modules.ThreadManForUserModule.isDispatchThreadEnabled() || !Interrupts.isInterruptsEnabled()) {
        //     if (Modules.getLogger(func.getModuleName()).isDebugEnabled()) {
        //         Modules.getLogger(func.getModuleName()).debug("<function name> return errorCode 0x800201A7 (ERROR_KERNEL_WAIT_CAN_NOT_WAIT)");
        //     }
        //     cpu.gpr[_v0] = SceKernelErrors.ERROR_KERNEL_WAIT_CAN_NOT_WAIT;
        //     goto afterSyscall
        // }
        loadModule("ThreadManForUser");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(ThreadManForUser.class),
                "isDispatchThreadEnabled", "()Z");
        Label returnError = new Label();
        mv.visitJumpInsn(Opcodes.IFEQ, returnError);
        loadProcessor();
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Processor.class), "isInterruptsEnabled",
                "()Z");
        Label noError = new Label();
        mv.visitJumpInsn(Opcodes.IFNE, noError);

        mv.visitLabel(returnError);
        loadModuleLoggger(func);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Logger.class), "isDebugEnabled", "()Z");
        Label notDebug = new Label();
        mv.visitJumpInsn(Opcodes.IFEQ, notDebug);
        loadModuleLoggger(func);
        mv.visitLdcInsn(String.format("%s returning errorCode 0x%08X (ERROR_KERNEL_WAIT_CAN_NOT_WAIT)",
                func.getFunctionName(), SceKernelErrors.ERROR_KERNEL_WAIT_CAN_NOT_WAIT));
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Logger.class), "debug",
                "(" + Type.getDescriptor(Object.class) + ")V");
        mv.visitLabel(notDebug);

        storeRegister(_v0, SceKernelErrors.ERROR_KERNEL_WAIT_CAN_NOT_WAIT);
        mv.visitJumpInsn(Opcodes.GOTO, afterSyscallLabel);
        mv.visitLabel(noError);
    }

    logSyscallStart(func);

    if (func.hasStackUsage()) {
        loadMemory();
        loadRegister(_sp);
        loadImm(func.getStackUsage());
        mv.visitInsn(Opcodes.ISUB);
        loadImm(0);
        loadImm(func.getStackUsage());
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, memoryInternalName, "memset", "(IBI)V");
    }

    // Collecting the parameters and calling the module function...
    CompilerParameterReader parameterReader = new CompilerParameterReader(this);

    loadModule(func.getModuleName());
    parameterReader.incrementCurrentStackSize();

    Label tryStart = new Label();
    Label tryEnd = new Label();
    Label catchSceKernelErrorException = new Label();
    mv.visitTryCatchBlock(tryStart, tryEnd, catchSceKernelErrorException,
            Type.getInternalName(SceKernelErrorException.class));

    Class<?>[] parameterTypes = func.getHLEModuleMethod().getParameterTypes();
    Class<?> returnType = func.getHLEModuleMethod().getReturnType();
    StringBuilder methodDescriptor = new StringBuilder();
    methodDescriptor.append("(");

    Annotation[][] paramsAnotations = func.getHLEModuleMethod().getParameterAnnotations();
    int paramIndex = 0;
    for (Class<?> parameterType : parameterTypes) {
        methodDescriptor.append(Type.getDescriptor(parameterType));
        loadParameter(parameterReader, func, parameterType, paramsAnotations[paramIndex], afterSyscallLabel,
                catchSceKernelErrorException);
        paramIndex++;
    }
    methodDescriptor.append(")");
    methodDescriptor.append(Type.getDescriptor(returnType));

    mv.visitLabel(tryStart);

    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
            Type.getInternalName(func.getHLEModuleMethod().getDeclaringClass()), func.getFunctionName(),
            methodDescriptor.toString());

    storeReturnValue(func, returnType);

    if (parameterReader.hasErrorPointer()) {
        // errorPointer.setValue(0);
        mv.visitVarInsn(Opcodes.ALOAD, LOCAL_ERROR_POINTER);
        loadImm(0);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(TErrorPointer32.class), "setValue",
                "(I)V");
    }

    loadRegister(_v0);
    logSyscallEnd(func, false);
    mv.visitInsn(Opcodes.POP);

    mv.visitLabel(tryEnd);
    mv.visitJumpInsn(Opcodes.GOTO, afterSyscallLabel);

    // catch (SceKernelErrorException e) {
    //     errorCode = e.errorCode;
    //     if (Modules.log.isDebugEnabled()) {
    //         Modules.log.debug(String.format("<function name> return errorCode 0x%08X", errorCode));
    //     }
    //     if (hasErrorPointer()) {
    //         errorPointer.setValue(errorCode);
    //         cpu.gpr[_v0] = 0;
    //     } else {
    //         cpu.gpr[_v0] = errorCode;
    //     }
    // }
    mv.visitLabel(catchSceKernelErrorException);
    mv.visitFieldInsn(Opcodes.GETFIELD, Type.getInternalName(SceKernelErrorException.class), "errorCode", "I");
    logSyscallEnd(func, true);
    if (parameterReader.hasErrorPointer()) {
        // errorPointer.setValue(errorCode);
        // cpu.gpr[_v0] = 0;
        mv.visitVarInsn(Opcodes.ALOAD, LOCAL_ERROR_POINTER);
        mv.visitInsn(Opcodes.SWAP);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(TErrorPointer32.class), "setValue",
                "(I)V");
        storeRegister(_v0, 0);
    } else {
        // cpu.gpr[_v0] = errorCode;
        storeRegister(_v0);
    }

    // Reload the $ra register, the stack is lost after an exception
    CodeInstruction previousInstruction = codeBlock.getCodeInstruction(codeInstruction.getAddress() - 4);
    if (previousInstruction != null && previousInstruction.getInsn() == Instructions.JR) {
        int jumpRegister = (previousInstruction.getOpcode() >> 21) & 0x1F;
        loadRegister(jumpRegister);
    }

    mv.visitLabel(afterSyscallLabel);

    if (fastSyscall) {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeContextInternalName, "postSyscallFast", "()V");
    } else {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeContextInternalName, "postSyscall", "()V");
    }

    if (needFirmwareVersionCheck) {
        Label afterVersionCheckLabel = new Label();
        mv.visitJumpInsn(Opcodes.GOTO, afterVersionCheckLabel);

        mv.visitLabel(unsupportedVersionLabel);
        loadModuleLoggger(func);
        mv.visitLdcInsn(String.format(
                "%s is not supported in firmware version %d, it requires at least firmware version %d",
                func.getFunctionName(), RuntimeContext.firmwareVersion, func.getFirmwareVersion()));
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Logger.class), "warn",
                "(" + Type.getDescriptor(Object.class) + ")V");
        storeRegister(_v0, -1);

        mv.visitLabel(afterVersionCheckLabel);
    }
}

From source file:jpcsp.Allegrex.compiler.CompilerContext.java

License:Open Source License

private void loadMemoryInt() {
    if (storeMemoryIntLocal) {
        mv.visitVarInsn(Opcodes.ALOAD, LOCAL_MEMORY_INT);
    } else {//from w  ww  .j ava  2  s .com
        mv.visitFieldInsn(Opcodes.GETSTATIC, runtimeContextInternalName, "memoryInt", "[I");
    }
}

From source file:lapin.comp.asm.ASMByteCodeGenerator.java

License:Open Source License

private void generateConstructor(Env env) {
    /*/*from   ww w .j av a2s . c  o m*/
     * local variables (reserved)
     * 0: this
     * 1: env
     */
    MethodVisitor mv = _cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
            //"(Llapin/lang/Env;)V",
            Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_ENV }), null, null);

    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitLdcInsn(super.classInfo.name().pname());
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "lapin/function/CompiledExpr", "<init>",
            //"(Ljava/lang/String;)V");
            Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_STRING }));

    Iterator it;

    // fields for constants
    it = constTable.keySet().iterator();
    while (it.hasNext()) {
        Object key = it.next(); // key: object (const)
        String val = Data.string(constTable.get(key));
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitLdcInsn(Printer.prin1ToString(key, env));
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "lapin/function/CompiledExpr", "toSexp",
                Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_STRING, TYPE_ENV }));
        mv.visitFieldInsn(Opcodes.PUTFIELD, toInternalName(super.classInfo.classname()), val,
                TYPE_OBJECT.getDescriptor());
    }

    // fields for vars
    it = varTable.keySet().iterator();
    while (it.hasNext()) {
        Object key = it.next(); // key: symbol (var)
        String val = Data.string(varTable.get(key));
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitLdcInsn(Printer.prin1ToString(key, env));
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "lapin/function/CompiledExpr", "toSexp",
                Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_STRING, TYPE_ENV }));
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "lapin/lang/Data", "symbol",
                Type.getMethodDescriptor(TYPE_SYMBOL, new Type[] { TYPE_OBJECT }));
        mv.visitFieldInsn(Opcodes.PUTFIELD, toInternalName(super.classInfo.classname()), val,
                TYPE_SYMBOL.getDescriptor());
    }

    // fields for lambdaLists
    it = llTable.keySet().iterator();
    while (it.hasNext()) {
        Object key = it.next(); // key: lambdaList
        String val = Data.string(llTable.get(key));
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitLdcInsn(Printer.prin1ToString(Data.lambdaList(key).params(), env));
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "lapin/function/CompiledExpr", "toLambdaList",
                Type.getMethodDescriptor(TYPE_LAMBDA_LIST, new Type[] { TYPE_STRING, TYPE_ENV }));
        mv.visitFieldInsn(Opcodes.PUTFIELD, toInternalName(super.classInfo.classname()), val,
                TYPE_LAMBDA_LIST.getDescriptor());
    }

    // field for SELF (static field)
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitFieldInsn(Opcodes.PUTSTATIC, toInternalName(super.classInfo.classname()), "SELF",
            toTypeDescriptor(super.classInfo.classname()));
    mv.visitInsn(Opcodes.RETURN);

    mv.visitMaxs(0, 0);
    mv.visitEnd();
}

From source file:lapin.comp.asm.ASMByteCodeGenerator.java

License:Open Source License

private void generateCall(CallableInfo ci, Env env) {
    /*/*ww w.jav a 2 s  . c  o  m*/
     * local variables
     * <Callable#call>
     * 0: this
     * 1: args (list of arguments)
     * 2: env
     *
     * <Callable0#call0>
     * 0: this
     * 1: env
     *
     * <Callable1#call1>
     * 0: this
     * 1: arg0
     * 2: env
     *
     * <Callable2#call2>
     * 0: this
     * 1: arg0
     * 2: arg1
     * 3: env
     *
     * ...
     *
     */
    MethodVisitor mv = _cw.visitMethod(
            ci.mi.implCallable() ? Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL : Opcodes.ACC_FINAL, ci.mi.name(),
            Type.getMethodDescriptor(ci.retType, ci.paramTypes), null, null);

    // instruction list
    int len = ci.mi.instLen();
    // label
    Label label = null;

    // generate code
    for (int i = 0; i < len; i++) {
        Object inst = ci.mi.getInst(i);
        if (Logger.tracelevelp(env))
            Logger.trace("[asm:gen]" + i + ":\t~S", Lists.list(inst), env);

        // inst is symbol
        // -> convert tag (Symbol) to label (ASMe Label object)
        if (Data.isSymbol(inst)) {
            Symbol tag = Data.symbol(inst);
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label is null: ~S.", Lists.list(tag));
            } else if (l != label) {
                mv.visitLabel(l);
                label = l;
                if (Logger.tracelevelp(env))
                    Logger.trace("[asm:gen]" + i + ":\ttag ~S -> label ~S", Lists.list(tag, l), env);
            } else {
                if (Logger.tracelevelp(env))
                    Logger.trace("[asm:gen]" + i + ":\ttag ~S -> label ~S" + " (dup)", Lists.list(tag, l), env);
            }
            continue;
        }

        // inst must be the form of (id <arg1> <arg2> ....)
        Object id = Lists.car(inst);
        if (id == Insts.CONST) {
            /* push const on the stack. */
            Object obj = Lists.cadr(inst);
            String val = Data.string(constTable.get(obj));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_OBJECT.getDescriptor());
        } else if (id == Insts.VAR) {
            /* push var on the stack */
            Object var = Lists.cadr(inst);
            String val = Data.string(varTable.get(var));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_SYMBOL.getDescriptor());
        } else if (id == Insts.LAMBDA_LIST) {
            /* push lambdaList on the stack */
            Object var = Lists.cadr(inst);
            /* push _ll_<i> on the stack */
            String val = Data.string(llTable.get(var));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_LAMBDA_LIST.getDescriptor());
        } else if (id == Insts.ENV_GET) {
            /* env.get */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getInt",
                        Type.getMethodDescriptor(Type.INT_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getDouble",
                        Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getChar",
                        Type.getMethodDescriptor(Type.CHAR_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "get",
                        Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_SYMBOL }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_SET) {
            /* env.set */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.INT_TYPE }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.DOUBLE_TYPE }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.CHAR_TYPE }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, TYPE_OBJECT }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_BIND) {
            /* env.bind */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.INT_TYPE }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.DOUBLE_TYPE }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.CHAR_TYPE }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, TYPE_OBJECT }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_UNBIND) {
            /* env.unbind */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindInt",
                        Type.getMethodDescriptor(Type.INT_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindDouble",
                        Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindChar",
                        Type.getMethodDescriptor(Type.CHAR_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbind",
                        Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_SYMBOL }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_CHILD) {
            /* env.child */
            Object oldEnvVar = Lists.cadr(inst);
            Object newEnvVar = Lists.caddr(inst);
            Object oldSlot = Lists.cadr(oldEnvVar);
            Object newSlot = Lists.cadr(newEnvVar);
            int oldLocal = Data.fixnum(ci.localTable.get(oldSlot)).intValue();
            int newLocal = Data.fixnum(ci.localTable.get(newSlot)).intValue();
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tenv-child: local ~S -> ~S",
                        Lists.list(Data.toFixnum(oldLocal), Data.toFixnum(newLocal)), env);
            mv.visitVarInsn(Opcodes.ALOAD, oldLocal);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "child",
                    Type.getMethodDescriptor(TYPE_ENV, TYPE_NO_ARGS));
            mv.visitVarInsn(Opcodes.ASTORE, newLocal);
        } else if (id == Insts.CALL) {
            /* funcall */
            int nargs = Data.fixnum(Lists.cadr(inst)).intValue();
            String className = "lapin.eval.Funcall";
            String methodName = nargs < 0 ? "funcall" : "funcall" + nargs;
            Class rType = Object.class;
            Class[] pTypes;
            if (nargs < 0) {
                pTypes = new Class[] { Function.class, Object.class, // list of args
                        Env.class };
            } else {
                pTypes = new Class[nargs + 2];
                pTypes[0] = Function.class;
                for (int j = 0; j < nargs; j++) {
                    pTypes[j + 1] = Object.class;
                }
                pTypes[nargs + 1] = Env.class;
            }

            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            mv.visitMethodInsn(Opcodes.INVOKESTATIC, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.CALL_DIRECT) {
            /*
             * public class Foo
             *   extends CompiledExpr implements Callable2 {
             *  public Object call2(Object arg0, Object arg1, Env env) {
             *   ...
             *  }
             * }
             */
            MethodInfo mi = (MethodInfo) Lists.cadr(inst);
            String className = mi.classInfo().classname();
            int nargs = mi.nargs();
            boolean rest = mi.rest();
            String methodName = mi.name();
            Class rType = mi.retType();
            Class[] pTypes = mi.paramTypes();

            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.COMPILED_EXPR) {
            /*
             * public class Foo extends CompiledExpr {
             *  static public Foo SELF;
             *  ...
             * }
             */
            String className = Data.string(Lists.cadr(inst));
            String fieldName = "SELF";
            String typeName = className;
            mv.visitFieldInsn(Opcodes.GETSTATIC, toInternalName(className), fieldName,
                    toTypeDescriptor(typeName));
        } else if (id == Insts.RETURN) {
            /* return */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class) || type.equals(short.class) || type.equals(byte.class)
                    || type.equals(char.class)) {
                mv.visitInsn(Opcodes.IRETURN);
            } else if (type.equals(long.class)) {
                mv.visitInsn(Opcodes.LRETURN);
            } else if (type.equals(float.class)) {
                mv.visitInsn(Opcodes.FRETURN);
            } else if (type.equals(double.class)) {
                mv.visitInsn(Opcodes.DRETURN);
            } else if (type.equals(void.class)) {
                //mv.visitInsn(Opcodes.RETURN);
                throw new NotReachedException("unsupported returnType: ~S.", Lists.list(type));
            } else {
                mv.visitInsn(Opcodes.ARETURN);
            }
        } else if (id == Insts.IFEQ) {
            /* conditional jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.IFEQ, l);
        } else if (id == Insts.IFNE) {
            /* conditional jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.IFNE, l);
        } else if (id == Insts.GOTO) {
            /* jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.GOTO, l);
        } else if (id == Insts.LOAD) {
            /* local -> stack */
            Object localVar = Lists.cadr(inst);
            Object slot = Lists.cadr(localVar);
            Class type = Data.javaClass(Lists.caddr(localVar));
            int local = Data.fixnum(ci.localTable.get(slot)).intValue();
            int op = Type.getType(type).getOpcode(Opcodes.ILOAD);
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tload: local=~S type=~S",
                        Lists.list(Data.toFixnum(local), type), env);
            mv.visitVarInsn(op, local);
        } else if (id == Insts.STORE) {
            /* stack -> local */
            Object localVar = Lists.cadr(inst);
            Object slot = Lists.cadr(localVar);
            Class type = Data.javaClass(Lists.caddr(localVar));
            int local = Data.fixnum(ci.localTable.get(slot)).intValue();
            int op = Type.getType(type).getOpcode(Opcodes.ISTORE);
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tstore: local=~S type=~S",
                        Lists.list(Data.toFixnum(local), type), env);
            mv.visitVarInsn(op, local);
        } else if (id == Insts.POP) {
            /* pop a value and discard it */
            Class type = Data.javaClass(Lists.cadr(inst));
            int op;
            switch (Classes.sizeOf(type)) {
            case 1:
                op = Opcodes.POP;
                break;
            case 2:
                op = Opcodes.POP2;
                break;
            default:
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
            mv.visitInsn(op);
        } else if (id == Insts.DUP) {
            /* peek a value and duplicate it */
            Class type = Data.javaClass(Lists.cadr(inst));
            int op;
            switch (Classes.sizeOf(type)) {
            case 1:
                op = Opcodes.DUP;
                break;
            case 2:
                op = Opcodes.DUP2;
                break;
            default:
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
            mv.visitInsn(op);
        } else if (id == Insts.PUSH) {
            /* push a constant */
            Object val = Lists.cadr(inst);
            if (Data.isJavaBoolean(val)) {
                if (Data.javaBoolean(val).booleanValue())
                    mv.visitInsn(Opcodes.ICONST_1);
                else
                    mv.visitInsn(Opcodes.ICONST_0);
            } else if (val instanceof Byte || val instanceof Short || val instanceof Integer) {
                int n = Data.javaNumber(val).intValue();
                if (n == -1)
                    mv.visitInsn(Opcodes.ICONST_M1);
                else if (n == 0)
                    mv.visitInsn(Opcodes.ICONST_0);
                else if (n == 1)
                    mv.visitInsn(Opcodes.ICONST_1);
                else if (n == 2)
                    mv.visitInsn(Opcodes.ICONST_2);
                else if (n == 3)
                    mv.visitInsn(Opcodes.ICONST_3);
                else if (n == 4)
                    mv.visitInsn(Opcodes.ICONST_4);
                else if (n == 5)
                    mv.visitInsn(Opcodes.ICONST_5);
                else if (Byte.MIN_VALUE <= n && n <= Byte.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.BIPUSH, n);
                else if (Short.MIN_VALUE <= n && n <= Short.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.SIPUSH, n);
                else
                    mv.visitLdcInsn(Data.toFixnum(n));
            } else if (val instanceof Long) {
                long n = Data.javaNumber(val).longValue();
                if (n == 0L)
                    mv.visitInsn(Opcodes.LCONST_0);
                else if (n == 1L)
                    mv.visitInsn(Opcodes.LCONST_1);
                else
                    mv.visitLdcInsn(val);
            } else if (val instanceof Float) {
                float n = Data.javaNumber(val).floatValue();
                if (n == 0.0f)
                    mv.visitInsn(Opcodes.FCONST_0);
                else if (n == 1.0f)
                    mv.visitInsn(Opcodes.FCONST_1);
                else if (n == 2.0f)
                    mv.visitInsn(Opcodes.FCONST_2);
                else
                    mv.visitLdcInsn(val);
            } else if (val instanceof Double) {
                double n = Data.javaNumber(val).doubleValue();
                if (n == 0.0)
                    mv.visitInsn(Opcodes.DCONST_0);
                else if (n == 1.0)
                    mv.visitInsn(Opcodes.DCONST_1);
                else
                    mv.visitLdcInsn(val);
            } else if (Data.isCharacter(val)) {
                Character c = Data.character(val);
                int n = (int) c.charValue();
                if (Byte.MIN_VALUE <= n && n <= Byte.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.BIPUSH, n);
                else if (Short.MIN_VALUE <= n && n <= Short.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.SIPUSH, n);
                else
                    mv.visitLdcInsn(Data.toFixnum(n));
            } else if (Data.isString(val)) {
                mv.visitLdcInsn(val);
            } else {
                throw new NotReachedException("cannot push: ~S.", Lists.list(val));
            }
        } else if (id == Insts.GET) {
            Field f = Data.javaField(Lists.cadr(inst));
            String fieldName = f.getName();
            Class c = f.getDeclaringClass();
            String className = c.getName();
            Class t = f.getType();
            String typeName = t.getName();

            boolean isStatic = Classes.isStatic(f);
            int op = isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD;

            mv.visitFieldInsn(op, toInternalName(className), fieldName, toTypeDescriptor(typeName));
        } else if (id == Insts.PUT) {
            Field f = Data.javaField(Lists.cadr(inst));
            String fieldName = f.getName();
            Class c = f.getDeclaringClass();
            String className = c.getName();
            Class t = f.getType();
            String typeName = t.getName();

            boolean isStatic = Classes.isStatic(f);
            int op = isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD;

            mv.visitFieldInsn(op, toInternalName(className), fieldName, toTypeDescriptor(typeName));
        } else if (id == Insts.INVOKE) {
            Method m = Data.javaMethod(Lists.cadr(inst));
            String methodName = m.getName();
            Class c = m.getDeclaringClass();
            String className = c.getName();
            Class rType = m.getReturnType();
            Class[] pTypes = m.getParameterTypes();
            if (rType.equals(void.class)) {
                throw new NotReachedException("unsupported returnType: ~S.", Lists.list(rType));
            }
            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            boolean isStatic = Classes.isStatic(m);
            boolean isInterface = c.isInterface();
            int op = isStatic ? Opcodes.INVOKESTATIC
                    : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL;

            mv.visitMethodInsn(op, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.CHECKCAST) {
            Class c = Data.javaClass(Lists.cadr(inst));
            Type t = Type.getType(c);
            mv.visitTypeInsn(Opcodes.CHECKCAST, t.getInternalName());
        } else if (id == Insts.THROW) {
            mv.visitInsn(Opcodes.ATHROW);
        } else if (id == Insts.CATCH) {
            Symbol tagS = Data.symbol(Lists.cadr(inst));
            Symbol tagE = Data.symbol(Lists.caddr(inst));
            Symbol tagH = Data.symbol(Lists.cadddr(inst));
            String className;
            if (Lists.isEnd(Lists.cddddr(inst))) {
                className = null;
            } else {
                Class c = Data.javaClass(Lists.car(Lists.cddddr(inst)));
                className = toInternalName(c.getName());
            }
            Label labelS = (Label) ci.labelTable.get(tagS);
            if (labelS == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagS));
            }
            Label labelE = (Label) ci.labelTable.get(tagE);
            if (labelE == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagE));
            }
            Label labelH = (Label) ci.labelTable.get(tagH);
            if (labelH == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagH));
            }
            mv.visitTryCatchBlock(labelS, labelE, labelH, className);
        }
        //else if (id == Insts.CATCH_FROM ||
        //         id == Insts.CATCH_TO ||
        //         id == Insts.CATCH_HANDLER) {
        //    /* nothing emitted */
        //    continue;
        //}
        else {
            throw new NotReachedException("unknown inst: ~S.", Lists.list(inst));
        }
    }
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}

From source file:lombok.patcher.MethodLogistics.java

License:Open Source License

/**
 * Writes the opcode to load 'this', or, for static methods, 'null'.
 * // w ww. j ava  2s .com
 * @param mv The opcode will be generated in this MethodVisitor object.
 */
public void generateLoadOpcodeForThis(MethodVisitor mv) {
    if (isStatic())
        mv.visitInsn(Opcodes.ACONST_NULL);
    else
        mv.visitVarInsn(Opcodes.ALOAD, 0);
}

From source file:lombok.patcher.MethodLogistics.java

License:Open Source License

private static int loadOpcodeFor(String spec) {
    switch (spec.charAt(0)) {
    case 'D':
        return Opcodes.DLOAD;
    case 'J':
        return Opcodes.LLOAD;
    case 'F':
        return Opcodes.FLOAD;
    case 'I':
    case 'S':
    case 'B':
    case 'Z':
        return Opcodes.ILOAD;
    case 'V':
        throw new IllegalArgumentException("There's no load opcode for 'void'");
    case 'L':
    case '[':
        return Opcodes.ALOAD;
    }/* w  w  w .ja va2  s.  c  o m*/

    throw new IllegalStateException("Uhoh - bug - unrecognized JVM type: " + spec);
}

From source file:lucee.transformer.bytecode.BodyBase.java

License:Open Source License

public static void writeOut(final BytecodeContext bc, List<Statement> statements) throws BytecodeException {
    GeneratorAdapter adapter = bc.getAdapter();
    boolean isOutsideMethod;
    GeneratorAdapter a = null;/* w  ww  .  j  ava  2s. c  om*/
    Method m;
    BytecodeContext _bc = bc;
    Iterator<Statement> it = statements.iterator();
    boolean split = bc.getPage().getSplitIfNecessary();

    //int lastLine=-1;
    while (it.hasNext()) {
        isOutsideMethod = bc.getMethod().getReturnType().equals(Types.VOID);
        Statement s = it.next();
        if (split && _bc.incCount() > MAX_STATEMENTS && bc.doSubFunctions()
                && (isOutsideMethod || !s.hasFlowController()) && s.getStart() != null) {
            if (a != null) {
                a.returnValue();
                a.endMethod();
            }
            //ExpressionUtil.visitLine(bc, s.getLine());
            String method = ASMUtil.createOverfowMethod(bc.getMethod().getName(),
                    bc.getPage().getMethodCount());
            ExpressionUtil.visitLine(bc, s.getStart());
            //ExpressionUtil.lastLine(bc);
            m = new Method(method, Types.VOID, new Type[] { Types.PAGE_CONTEXT });
            a = new GeneratorAdapter(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, m, null,
                    new Type[] { Types.THROWABLE }, bc.getClassWriter());

            _bc = new BytecodeContext(bc.getStaticConstructor(), bc.getConstructor(), bc.getKeys(), bc, a, m);
            if (bc.getRoot() != null)
                _bc.setRoot(bc.getRoot());
            else
                _bc.setRoot(bc);

            adapter.visitVarInsn(Opcodes.ALOAD, 0);
            adapter.visitVarInsn(Opcodes.ALOAD, 1);
            adapter.visitMethodInsn(Opcodes.INVOKEVIRTUAL, bc.getClassName(), method,
                    "(Llucee/runtime/PageContext;)V");
        }
        if (_bc != bc && s.hasFlowController()) {
            if (a != null) {
                a.returnValue();
                a.endMethod();
            }
            _bc = bc;
            a = null;
        }
        ExpressionUtil.writeOut(s, _bc);
    }
    if (a != null) {
        a.returnValue();
        a.endMethod();
    }
}