/**
     * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
     */
    private void emitReturn(Name onStack)
    {
        // return statement
        Class     rclass = invokerType.returnType();
        BasicType rtype  = lambdaForm.returnType();

        //assert(rtype == basicType(rclass));  // must agree
        if (rtype == BasicType.V_TYPE)
        {
            // [IKVM] unlike the JVM, the CLR doesn't like left over values on the stack
            if (onStack != null && onStack._type() != BasicType.V_TYPE)
            {
                ilgen.Emit(OpCodes.Pop);
            }
        }
        else
        {
            LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];

            // put return value on the stack if it is not already there
            if (rn != onStack)
            {
                emitLoadInsn(rtype, lambdaForm.result);
            }

            emitImplicitConversion(rtype, rclass, rn);
        }
        ilgen.Emit(OpCodes.Ret);
    }
    /**
     * Emit an implicit conversion for an argument which must be of the given pclass.
     * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
     *
     * @param ptype type of value present on stack
     * @param pclass type of value required on stack
     * @param arg compile-time representation of value on stack (Node, constant) or null if none
     */
    private void emitImplicitConversion(BasicType ptype, Class pclass, object arg)
    {
        //assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
        if (pclass == ptype.basicTypeClass() && ptype != BasicType.L_TYPE)
        {
            return;   // nothing to do
        }
        switch (ptype.name())
        {
        case "L_TYPE":
            if (VerifyType.isNullConversion(CoreClasses.java.lang.Object.Wrapper.ClassObject, pclass, false))
            {
                //if (PROFILE_LEVEL > 0)
                //    emitReferenceCast(Object.class, arg);
                return;
            }
            emitReferenceCast(pclass, arg);
            return;

        case "I_TYPE":
            if (!VerifyType.isNullConversion(java.lang.Integer.TYPE, pclass, false))
            {
                emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
            }
            return;
        }
        throw new BailoutException(Bailout.PreconditionViolated, "bad implicit conversion: tc=" + ptype + ": " + pclass);
    }
    private void emitPushArgument(Class ptype, object arg)
    {
        BasicType bptype = BasicType.basicType(ptype);

        if (arg is Name)
        {
            Name n = (Name)arg;
            emitLoadInsn(n._type(), n.index());
            emitImplicitConversion(n._type(), ptype, n);
        }
        else if ((arg == null || arg is string) && bptype == BasicType.L_TYPE)
        {
            emitConst(arg);
        }
        else
        {
            if (Wrapper.isWrapperType(ikvm.extensions.ExtensionMethods.getClass(arg)) && bptype != BasicType.L_TYPE)
            {
                emitConst(arg);
            }
            else
            {
                EmitConstant(arg);
                emitImplicitConversion(BasicType.L_TYPE, ptype, arg);
            }
        }
    }
 /*
  * NOTE: These load/store methods use the localsMap to find the correct index!
  */
 private void emitLoadInsn(BasicType type, int index)
 {
     // [IKVM] we don't need the localsMap (it is used to correct for long/double taking two slots)
     if (locals[index] == null)
     {
         MethodHandleUtil.LoadPackedArg(ilgen, index, 1, packedArgPos, packedArgType);
     }
     else
     {
         ilgen.Emit(OpCodes.Ldloc, locals[index]);
     }
 }
 private void emitStoreInsn(BasicType type, int index)
 {
     ilgen.Emit(OpCodes.Stloc, locals[index]);
 }
 /**
  * Emit an implicit conversion for an argument which must be of the given pclass.
  * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
  *
  * @param ptype type of value present on stack
  * @param pclass type of value required on stack
  * @param arg compile-time representation of value on stack (Node, constant) or null if none
  */
 private void emitImplicitConversion(BasicType ptype, Class pclass, object arg) {
     //assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
     if (pclass == ptype.basicTypeClass() && ptype != BasicType.L_TYPE)
         return;   // nothing to do
     switch (ptype.name()) {
         case "L_TYPE":
             if (VerifyType.isNullConversion(CoreClasses.java.lang.Object.Wrapper.ClassObject, pclass, false)) {
                 //if (PROFILE_LEVEL > 0)
                 //    emitReferenceCast(Object.class, arg);
                 return;
             }
             emitReferenceCast(pclass, arg);
             return;
         case "I_TYPE":
             if (!VerifyType.isNullConversion(java.lang.Integer.TYPE, pclass, false))
                 emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
             return;
     }
     throw new BailoutException(Bailout.PreconditionViolated, "bad implicit conversion: tc=" + ptype + ": " + pclass);
 }
 private void emitStoreInsn(BasicType type, int index) {
     ilgen.Emit(OpCodes.Stloc, locals[index]);
 }
 /*
  * NOTE: These load/store methods use the localsMap to find the correct index!
  */
 private void emitLoadInsn(BasicType type, int index) {
     // [IKVM] we don't need the localsMap (it is used to correct for long/double taking two slots)
     if (locals[index] == null) {
         MethodHandleUtil.LoadPackedArg(ilgen, index, 1, packedArgPos, packedArgType);
     } else {
         ilgen.Emit(OpCodes.Ldloc, locals[index]);
     }
 }