private void emitPushArguments(Name args, int start)
 {
     for (int i = start; i < args.arguments.Length; i++)
     {
         emitPushArgument(args, i);
     }
 }
    private void emitPushArgument(Name name, int paramIndex)
    {
        object arg   = name.arguments[paramIndex];
        Class  ptype = name.function.methodType().parameterType(paramIndex);

        emitPushArgument(ptype, arg);
    }
    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);
            }
        }
    }
    /**
     * Emit an invoke for the given name.
     */
    void emitInvoke(Name name)
    {
        //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
        if (true)
        {
            // push receiver
            MethodHandle target = name.function._resolvedHandle();
            //assert(target != null) : name.exprString();
            //mv.visitLdcInsn(constantPlaceholder(target));
            EmitConstant(target);
            emitReferenceCast(CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject, target);
        }
        else
        {
            // load receiver
            //emitAloadInsn(0);
            //emitReferenceCast(MethodHandle.class, null);
            //mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
            //mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
            // TODO more to come
        }

        // push arguments
        emitPushArguments(name);

        // invocation
        MethodType type = name.function.methodType();

        //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
        EmitInvokeBasic(type.basicType());
    }
    /**
     * 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);
    }
 /**
  * Store the name to its local, if necessary.
  */
 private void emitStoreResult(Name name)
 {
     if (name != null && name._type() != BasicType.V_TYPE)
     {
         // non-void: actually assign
         emitStoreInsn(name._type(), name.index());
     }
 }
    void emitNewArray(Name name)
    {
        Class rtype = name.function.methodType().returnType();

        if (name.arguments.Length == 0)
        {
            // The array will be a constant.
            object emptyArray;
            try {
                emptyArray = name.function._resolvedHandle().invoke();
            } catch (Exception ex) {
                throw new java.lang.InternalError(ex);
            }
            //assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
            //assert(emptyArray.getClass() == rtype);  // exact typing
            //mv.visitLdcInsn(constantPlaceholder(emptyArray));
            EmitConstant(emptyArray);
            emitReferenceCast(rtype, emptyArray);
            return;
        }
        Class arrayElementType = rtype.getComponentType();

        //assert(arrayElementType != null);
        emitIconstInsn(name.arguments.Length);
        OpCode xas = OpCodes.Stelem_Ref;

        if (!arrayElementType.isPrimitive())
        {
            TypeWrapper tw = TypeWrapper.FromClass(arrayElementType);
            if (tw.IsUnloadable || tw.IsGhost || tw.IsGhostArray || tw.IsNonPrimitiveValueType)
            {
                throw new BailoutException(Bailout.UnsupportedArrayType, tw);
            }
            ilgen.Emit(OpCodes.Newarr, tw.TypeAsArrayType);
        }
        else
        {
            byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
            xas = arrayInsnOpcode(tc);
            //mv.visitIntInsn(Opcodes.NEWARRAY, tc);
            ilgen.Emit(OpCodes.Newarr, TypeWrapper.FromClass(arrayElementType).TypeAsArrayType);
        }
        // store arguments
        for (int i = 0; i < name.arguments.Length; i++)
        {
            //mv.visitInsn(Opcodes.DUP);
            ilgen.Emit(OpCodes.Dup);
            emitIconstInsn(i);
            emitPushArgument(name, i);
            //mv.visitInsn(xas);
            ilgen.Emit(xas);
        }
        // the array is left on the stack
        assertStaticType(rtype, name);
    }
    void emitArrayLoad(Name name)
    {
        OpCode arrayOpcode = OpCodes.Ldelem_Ref;
        Class  elementType = name.function.methodType().parameterType(0).getComponentType();

        emitPushArguments(name);
        if (elementType.isPrimitive())
        {
            Wrapper w = Wrapper.forPrimitiveType(elementType);
            arrayOpcode = arrayLoadOpcode(arrayTypeCode(w));
        }
        ilgen.Emit(arrayOpcode);
    }
    /**
     * Emit bytecode for the selectAlternative idiom.
     *
     * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
     * <blockquote><pre>{@code
     *   Lambda(a0:L,a1:I)=>{
     *     t2:I=foo.test(a1:I);
     *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
     *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
     * }</pre></blockquote>
     */
    private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName)
    {
        //assert isStaticallyInvocable(invokeBasicName);

        Name receiver = (Name)invokeBasicName.arguments[0];

        CodeEmitterLabel L_fallback = ilgen.DefineLabel();
        CodeEmitterLabel L_done     = ilgen.DefineLabel();

        // load test result
        emitPushArgument(selectAlternativeName, 0);

        // if_icmpne L_fallback
        ilgen.EmitBrfalse(L_fallback);

        // invoke selectAlternativeName.arguments[1]
        //Class<?>[] preForkClasses = localClasses.clone();
        emitPushArgument(selectAlternativeName, 1); // get 2nd argument of selectAlternative
        emitAstoreInsn(receiver.index());           // store the MH in the receiver slot
        emitStaticInvoke(invokeBasicName);

        // goto L_done
        ilgen.EmitBr(L_done);

        // L_fallback:
        ilgen.MarkLabel(L_fallback);

        // invoke selectAlternativeName.arguments[2]
        //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
        emitPushArgument(selectAlternativeName, 2); // get 3rd argument of selectAlternative
        emitAstoreInsn(receiver.index());           // store the MH in the receiver slot
        emitStaticInvoke(invokeBasicName);

        // L_done:
        ilgen.MarkLabel(L_done);
        // for now do not bother to merge typestate; just reset to the dominator state
        //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);

        return(invokeBasicName);  // return what's on stack
    }
 void emitNewArray(Name name) {
     Class rtype = name.function.methodType().returnType();
     if (name.arguments.Length == 0) {
         // The array will be a constant.
         object emptyArray;
         try {
             emptyArray = name.function._resolvedHandle().invoke();
         } catch (Exception ex) {
             throw new java.lang.InternalError(ex);
         }
         //assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
         //assert(emptyArray.getClass() == rtype);  // exact typing
         //mv.visitLdcInsn(constantPlaceholder(emptyArray));
         EmitConstant(emptyArray);
         emitReferenceCast(rtype, emptyArray);
         return;
     }
     Class arrayElementType = rtype.getComponentType();
     //assert(arrayElementType != null);
     emitIconstInsn(name.arguments.Length);
     OpCode xas = OpCodes.Stelem_Ref;
     if (!arrayElementType.isPrimitive()) {
         TypeWrapper tw = TypeWrapper.FromClass(arrayElementType);
         if (tw.IsUnloadable || tw.IsGhost || tw.IsGhostArray || tw.IsNonPrimitiveValueType) {
             throw new BailoutException(Bailout.UnsupportedArrayType, tw);
         }
         ilgen.Emit(OpCodes.Newarr, tw.TypeAsArrayType);
     } else {
         byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
         xas = arrayInsnOpcode(tc);
         //mv.visitIntInsn(Opcodes.NEWARRAY, tc);
         ilgen.Emit(OpCodes.Newarr, TypeWrapper.FromClass(arrayElementType).TypeAsArrayType);
     }
     // store arguments
     for (int i = 0; i < name.arguments.Length; i++) {
         //mv.visitInsn(Opcodes.DUP);
         ilgen.Emit(OpCodes.Dup);
         emitIconstInsn(i);
         emitPushArgument(name, i);
         //mv.visitInsn(xas);
         ilgen.Emit(xas);
     }
     // the array is left on the stack
     assertStaticType(rtype, name);
 }
 private void emitPushArguments(Name args)
 {
     emitPushArguments(args, 0);
 }
    private NativeInvokerBytecodeGenerator(LambdaForm lambdaForm, MethodType invokerType)
    {
        if (invokerType != invokerType.basicType())
        {
            throw new BailoutException(Bailout.NotBasicType, invokerType);
        }
        this.lambdaForm   = lambdaForm;
        this.invokerType  = invokerType;
        this.delegateType = MethodHandleUtil.GetMemberWrapperDelegateType(invokerType);
        MethodInfo mi = MethodHandleUtil.GetDelegateInvokeMethod(delegateType);

        Type[] paramTypes = MethodHandleUtil.GetParameterTypes(typeof(object[]), mi);
        // HACK the code we generate is not verifiable (known issue: locals aren't typed correctly), so we stick the DynamicMethod into mscorlib (a security critical assembly)
        this.dm    = new DynamicMethod(lambdaForm.debugName, mi.ReturnType, paramTypes, typeof(object).Module, true);
        this.ilgen = CodeEmitter.Create(this.dm);
        if (invokerType.parameterCount() > MethodHandleUtil.MaxArity)
        {
            this.packedArgType = paramTypes[paramTypes.Length - 1];
            this.packedArgPos  = paramTypes.Length - 1;
        }
        else
        {
            this.packedArgPos = Int32.MaxValue;
        }

        locals = new CodeEmitterLocal[lambdaForm.names.Length];
        for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++)
        {
            Name name = lambdaForm.names[i];
            if (name.index() != i)
            {
                throw new BailoutException(Bailout.PreconditionViolated, "name.index() != i");
            }
            switch (name.typeChar())
            {
            case 'L':
                locals[i] = ilgen.DeclareLocal(Types.Object);
                break;

            case 'I':
                locals[i] = ilgen.DeclareLocal(Types.Int32);
                break;

            case 'J':
                locals[i] = ilgen.DeclareLocal(Types.Int64);
                break;

            case 'F':
                locals[i] = ilgen.DeclareLocal(Types.Single);
                break;

            case 'D':
                locals[i] = ilgen.DeclareLocal(Types.Double);
                break;

            case 'V':
                break;

            default:
                throw new BailoutException(Bailout.PreconditionViolated, "Unsupported typeChar(): " + name.typeChar());
            }
        }
    }
    /**
     * Emit bytecode for the guardWithCatch idiom.
     *
     * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch):
     * <blockquote><pre>{@code
     *  guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
     *    t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L);
     *    t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L);
     *   t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I}
     * }</pre></blockquote>
     *
     * It is compiled into bytecode equivalent of the following code:
     * <blockquote><pre>{@code
     *  try {
     *      return a1.invokeBasic(a6, a7);
     *  } catch (Throwable e) {
     *      if (!a2.isInstance(e)) throw e;
     *      return a3.invokeBasic(ex, a6, a7);
     *  }}</pre></blockquote>
     */
    private Name emitGuardWithCatch(int pos)
    {
        Name args    = lambdaForm.names[pos];
        Name invoker = lambdaForm.names[pos + 1];
        Name result  = lambdaForm.names[pos + 2];

        CodeEmitterLabel L_handler = ilgen.DefineLabel();
        CodeEmitterLabel L_done    = ilgen.DefineLabel();

        Class      returnType = result.function._resolvedHandle().type().returnType();
        MethodType type       = args.function._resolvedHandle().type()
                                .dropParameterTypes(0, 1)
                                .changeReturnType(returnType);

        // Normal case
        ilgen.BeginExceptionBlock();
        // load target
        emitPushArgument(invoker, 0);
        emitPushArguments(args, 1); // skip 1st argument: method handle
        EmitInvokeBasic(type.basicType());
        CodeEmitterLocal returnValue = null;

        if (returnType != java.lang.Void.TYPE)
        {
            returnValue = ilgen.DeclareLocal(TypeWrapper.FromClass(returnType).TypeAsLocalOrStackType);
            ilgen.Emit(OpCodes.Stloc, returnValue);
        }
        ilgen.EmitLeave(L_done);

        // Exceptional case
        ilgen.BeginCatchBlock(typeof(Exception));

        // [IKVM] map the exception and store it in a local and exit the handler
        ilgen.EmitLdc_I4(0);
        ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(typeof(Exception)));
        CodeEmitterLocal exception = ilgen.DeclareLocal(typeof(Exception));

        ilgen.Emit(OpCodes.Stloc, exception);
        ilgen.EmitLeave(L_handler);
        ilgen.EndExceptionBlock();

        // Check exception's type
        ilgen.MarkLabel(L_handler);
        // load exception class
        emitPushArgument(invoker, 1);
        ilgen.Emit(OpCodes.Ldloc, exception);
        CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("isInstance", "(Ljava.lang.Object;)Z", false).EmitCall(ilgen);
        CodeEmitterLabel L_rethrow = ilgen.DefineLabel();

        ilgen.EmitBrfalse(L_rethrow);

        // Invoke catcher
        // load catcher
        emitPushArgument(invoker, 2);
        ilgen.Emit(OpCodes.Ldloc, exception);
        emitPushArguments(args, 1); // skip 1st argument: method handle
        MethodType catcherType = type.insertParameterTypes(0, CoreClasses.java.lang.Throwable.Wrapper.ClassObject);

        EmitInvokeBasic(catcherType.basicType());
        if (returnValue != null)
        {
            ilgen.Emit(OpCodes.Stloc, returnValue);
        }
        ilgen.EmitBr(L_done);

        ilgen.MarkLabel(L_rethrow);
        ilgen.Emit(OpCodes.Ldloc, exception);
        ilgen.Emit(OpCodes.Call, Compiler.unmapExceptionMethod);
        ilgen.Emit(OpCodes.Throw);

        ilgen.MarkLabel(L_done);
        if (returnValue != null)
        {
            ilgen.Emit(OpCodes.Ldloc, returnValue);
        }

        return(result);
    }
    /**
     * Emit an invoke for the given name.
     */
    void emitInvoke(Name name) {
        //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
        if (true) {
            // push receiver
            MethodHandle target = name.function._resolvedHandle();
            //assert(target != null) : name.exprString();
            //mv.visitLdcInsn(constantPlaceholder(target));
            EmitConstant(target);
            emitReferenceCast(CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject, target);
        } else {
            // load receiver
            //emitAloadInsn(0);
            //emitReferenceCast(MethodHandle.class, null);
            //mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
            //mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
            // TODO more to come
        }

        // push arguments
        emitPushArguments(name);

        // invocation
        MethodType type = name.function.methodType();
        //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
        EmitInvokeBasic(type.basicType());
    }
 private void emitPushArgument(Name name, int paramIndex) {
     object arg = name.arguments[paramIndex];
     Class ptype = name.function.methodType().parameterType(paramIndex);
     emitPushArgument(ptype, arg);
 }
 private void emitPushArguments(Name args) {
     emitPushArguments(args, 0);
 }
    /*
     * static boolean isStaticallyNameable(Class<?> cls) {
     * if (cls == Object.class)
     *  return true;
     * while (cls.isArray())
     *  cls = cls.getComponentType();
     * if (cls.isPrimitive())
     *  return true;  // int[].class, for example
     * if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
     *  return false;
     * // could use VerifyAccess.isClassAccessible but the following is a safe approximation
     * if (cls.getClassLoader() != Object.class.getClassLoader())
     *  return false;
     * if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
     *  return true;
     * if (!Modifier.isPublic(cls.getModifiers()))
     *  return false;
     * for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
     *  if (VerifyAccess.isSamePackage(pkgcls, cls))
     *      return true;
     * }
     * return false;
     * }
     */

    void emitStaticInvoke(Name name)
    {
        emitStaticInvoke(name.function._member(), name);
    }
    /**
     * Generate an invoker method for the passed {@link LambdaForm}.
     */
    private Delegate generateCustomizedCodeBytes()
    {
        // iterate over the form's names, generating bytecode instructions for each
        // start iterating at the first name following the arguments
        Name onStack = null;

        for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++)
        {
            Name name = lambdaForm.names[i];

            emitStoreResult(onStack);
            onStack = name;  // unless otherwise modified below
            MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
            switch (intr.name())
            {
            case "SELECT_ALTERNATIVE":
                //assert isSelectAlternative(i);
                onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
                i++;      // skip MH.invokeBasic of the selectAlternative result
                continue;

            case "GUARD_WITH_CATCH":
                //assert isGuardWithCatch(i);
                onStack = emitGuardWithCatch(i);
                i       = i + 2; // Jump to the end of GWC idiom
                continue;

            case "NEW_ARRAY":
                Class rtype = name.function.methodType().returnType();
                if (InvokerBytecodeGenerator.isStaticallyNameable(rtype))
                {
                    emitNewArray(name);
                    continue;
                }
                break;

            case "ARRAY_LOAD":
                emitArrayLoad(name);
                continue;

            case "IDENTITY":
                //assert(name.arguments.length == 1);
                emitPushArguments(name);
                continue;

            case "NONE":
                // no intrinsic associated
                break;

            // [IKVM] ARRAY_STORE and ZERO appear to be unused
            default:
                throw new BailoutException(Bailout.UnsupportedIntrinsic, "Unknown intrinsic: " + intr);
            }

            MemberName member = name.function._member();
            if (isStaticallyInvocable(member))
            {
                emitStaticInvoke(member, name);
            }
            else
            {
                emitInvoke(name);
            }
        }

        // return statement
        emitReturn(onStack);

        ilgen.DoEmit();
        return(dm.CreateDelegate(delegateType, constants.ToArray()));
    }
 void emitArrayLoad(Name name) {
     OpCode arrayOpcode = OpCodes.Ldelem_Ref;
     Class elementType = name.function.methodType().parameterType(0).getComponentType();
     emitPushArguments(name);
     if (elementType.isPrimitive()) {
         Wrapper w = Wrapper.forPrimitiveType(elementType);
         arrayOpcode = arrayLoadOpcode(arrayTypeCode(w));
     }
     ilgen.Emit(arrayOpcode);
 }
 /** Update localClasses type map.  Return true if the information is already present. */
 private void assertStaticType(Class cls, Name n)
 {
     // [IKVM] not implemented
 }
    /**
     * 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);
    }
 /**
  * Store the name to its local, if necessary.
  */
 private void emitStoreResult(Name name) {
     if (name != null && name._type() != BasicType.V_TYPE) {
         // non-void: actually assign
         emitStoreInsn(name._type(), name.index());
     }
 }
    /**
     * Emit an invoke for the given name, using the MemberName directly.
     */
    void emitStaticInvoke(MemberName member, Name name) {
        // push arguments
        emitPushArguments(name);

        // invocation
        if (member.isMethod()) {
            if (IsMethodHandleLinkTo(member)) {
                MethodType mt = member.getMethodType();
                TypeWrapper[] args = new TypeWrapper[mt.parameterCount()];
                for (int j = 0; j < args.Length; j++) {
                    args[j] = TypeWrapper.FromClass(mt.parameterType(j));
                    args[j].Finish();
                }
                TypeWrapper ret = TypeWrapper.FromClass(mt.returnType());
                ret.Finish();
                Compiler.MethodHandleMethodWrapper.EmitLinkToCall(ilgen, args, ret);
                ret.EmitConvSignatureTypeToStackType(ilgen);
            } else if (IsMethodHandleInvokeBasic(member)) {
                EmitInvokeBasic(member.getMethodType());
            } else {
                switch (member.getReferenceKind()) {
                    case MethodHandleNatives.Constants.REF_invokeInterface:
                    case MethodHandleNatives.Constants.REF_invokeSpecial:
                    case MethodHandleNatives.Constants.REF_invokeStatic:
                    case MethodHandleNatives.Constants.REF_invokeVirtual:
                        break;
                    default:
                        throw new BailoutException(Bailout.UnsupportedRefKind, member);
                }
                MethodWrapper mw = GetMethodWrapper(member);
                if (!IsStaticallyInvocable(mw)) {
                    throw new BailoutException(Bailout.NotStaticallyInvocable, member);
                }
                mw.Link();
                mw.DeclaringType.Finish();
                mw.ResolveMethod();
                if (mw.HasCallerID) {
                    EmitConstant(DynamicCallerIDProvider.Instance);
                    ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicCallerID);
                }
                if (mw.IsStatic || member.getReferenceKind() == MethodHandleNatives.Constants.REF_invokeSpecial) {
                    mw.EmitCall(ilgen);
                } else {
                    mw.EmitCallvirt(ilgen);
                }
                mw.ReturnType.EmitConvSignatureTypeToStackType(ilgen);
            }
        } else if (member.isField()) {
            FieldWrapper fw = GetFieldWrapper(member);
            if (!IsStaticallyInvocable(fw)) {
                throw new BailoutException(Bailout.NotStaticallyInvocable, member);
            }
            fw.Link();
            fw.DeclaringType.Finish();
            fw.ResolveField();
            switch (member.getReferenceKind()) {
                case MethodHandleNatives.Constants.REF_getField:
                case MethodHandleNatives.Constants.REF_getStatic:
                    fw.EmitGet(ilgen);
                    fw.FieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen);
                    break;
                case MethodHandleNatives.Constants.REF_putField:
                case MethodHandleNatives.Constants.REF_putStatic:
                    fw.EmitSet(ilgen);
                    break;
                default:
                    throw new BailoutException(Bailout.UnsupportedRefKind, member);
            }
        } else {
            throw new BailoutException(Bailout.NotStaticallyInvocable, member);
        }
    }
    /**
     * Emit an invoke for the given name, using the MemberName directly.
     */
    void emitStaticInvoke(MemberName member, Name name)
    {
        // push arguments
        emitPushArguments(name);

        // invocation
        if (member.isMethod())
        {
            if (IsMethodHandleLinkTo(member))
            {
                MethodType    mt   = member.getMethodType();
                TypeWrapper[] args = new TypeWrapper[mt.parameterCount()];
                for (int j = 0; j < args.Length; j++)
                {
                    args[j] = TypeWrapper.FromClass(mt.parameterType(j));
                    args[j].Finish();
                }
                TypeWrapper ret = TypeWrapper.FromClass(mt.returnType());
                ret.Finish();
                Compiler.MethodHandleMethodWrapper.EmitLinkToCall(ilgen, args, ret);
                ret.EmitConvSignatureTypeToStackType(ilgen);
            }
            else if (IsMethodHandleInvokeBasic(member))
            {
                EmitInvokeBasic(member.getMethodType());
            }
            else
            {
                switch (member.getReferenceKind())
                {
                case MethodHandleNatives.Constants.REF_invokeInterface:
                case MethodHandleNatives.Constants.REF_invokeSpecial:
                case MethodHandleNatives.Constants.REF_invokeStatic:
                case MethodHandleNatives.Constants.REF_invokeVirtual:
                    break;

                default:
                    throw new BailoutException(Bailout.UnsupportedRefKind, member);
                }
                MethodWrapper mw = GetMethodWrapper(member);
                if (!IsStaticallyInvocable(mw))
                {
                    throw new BailoutException(Bailout.NotStaticallyInvocable, member);
                }
                mw.Link();
                mw.DeclaringType.Finish();
                mw.ResolveMethod();
                if (mw.HasCallerID)
                {
                    EmitConstant(DynamicCallerIDProvider.Instance);
                    ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicCallerID);
                }
                if (mw.IsStatic || member.getReferenceKind() == MethodHandleNatives.Constants.REF_invokeSpecial)
                {
                    mw.EmitCall(ilgen);
                }
                else
                {
                    mw.EmitCallvirt(ilgen);
                }
                mw.ReturnType.EmitConvSignatureTypeToStackType(ilgen);
            }
        }
        else if (member.isField())
        {
            FieldWrapper fw = GetFieldWrapper(member);
            if (!IsStaticallyInvocable(fw))
            {
                throw new BailoutException(Bailout.NotStaticallyInvocable, member);
            }
            fw.Link();
            fw.DeclaringType.Finish();
            fw.ResolveField();
            switch (member.getReferenceKind())
            {
            case MethodHandleNatives.Constants.REF_getField:
            case MethodHandleNatives.Constants.REF_getStatic:
                fw.EmitGet(ilgen);
                fw.FieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen);
                break;

            case MethodHandleNatives.Constants.REF_putField:
            case MethodHandleNatives.Constants.REF_putStatic:
                fw.EmitSet(ilgen);
                break;

            default:
                throw new BailoutException(Bailout.UnsupportedRefKind, member);
            }
        }
        else
        {
            throw new BailoutException(Bailout.NotStaticallyInvocable, member);
        }
    }
	/*
    static boolean isStaticallyNameable(Class<?> cls) {
        if (cls == Object.class)
            return true;
        while (cls.isArray())
            cls = cls.getComponentType();
        if (cls.isPrimitive())
            return true;  // int[].class, for example
        if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
            return false;
        // could use VerifyAccess.isClassAccessible but the following is a safe approximation
        if (cls.getClassLoader() != Object.class.getClassLoader())
            return false;
        if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
            return true;
        if (!Modifier.isPublic(cls.getModifiers()))
            return false;
        for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
            if (VerifyAccess.isSamePackage(pkgcls, cls))
                return true;
        }
        return false;
	}
	*/

    void emitStaticInvoke(Name name) {
        emitStaticInvoke(name.function._member(), name);
    }
    /**
     * Emit bytecode for the selectAlternative idiom.
     *
     * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
     * <blockquote><pre>{@code
     *   Lambda(a0:L,a1:I)=>{
     *     t2:I=foo.test(a1:I);
     *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
     *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
     * }</pre></blockquote>
     */
    private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
        //assert isStaticallyInvocable(invokeBasicName);

        Name receiver = (Name) invokeBasicName.arguments[0];

        CodeEmitterLabel L_fallback = ilgen.DefineLabel();
        CodeEmitterLabel L_done = ilgen.DefineLabel();

        // load test result
        emitPushArgument(selectAlternativeName, 0);

        // if_icmpne L_fallback
        ilgen.EmitBrfalse(L_fallback);

        // invoke selectAlternativeName.arguments[1]
        //Class<?>[] preForkClasses = localClasses.clone();
        emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
        emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
        emitStaticInvoke(invokeBasicName);

        // goto L_done
        ilgen.EmitBr(L_done);

        // L_fallback:
        ilgen.MarkLabel(L_fallback);

        // invoke selectAlternativeName.arguments[2]
        //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
        emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
        emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
        emitStaticInvoke(invokeBasicName);

        // L_done:
        ilgen.MarkLabel(L_done);
        // for now do not bother to merge typestate; just reset to the dominator state
        //System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);

        return invokeBasicName;  // return what's on stack
    }
 /** Update localClasses type map.  Return true if the information is already present. */
 private void assertStaticType(Class cls, Name n) {
     // [IKVM] not implemented
 }
 private void emitPushArguments(Name args, int start) {
     for (int i = start; i < args.arguments.Length; i++) {
         emitPushArgument(args, i);
     }
 }