public override MethodIL EmitIL()
        {
            ILEmitter    emitter    = new ILEmitter();
            ILCodeStream codeStream = emitter.NewCodeStream();

            // InstantiateAsOpen covers the weird case of generic enums
            TypeDesc owningTypeAsOpen = _owningType.InstantiateAsOpen();

            ILCodeLabel lNotEqual = emitter.NewCodeLabel();

            // if (!(obj is {enumtype}))
            //     return false;

            codeStream.EmitLdArg(1);
            codeStream.Emit(ILOpcode.isinst, emitter.NewToken(owningTypeAsOpen));
            codeStream.Emit(ILOpcode.dup);
            codeStream.Emit(ILOpcode.brfalse, lNotEqual);

            // return ({underlyingtype})this == ({underlyingtype})obj;

            // PREFER: ILOpcode.unbox, but the codegen for that is pretty bad
            codeStream.Emit(ILOpcode.ldflda, emitter.NewToken(Context.GetWellKnownType(WellKnownType.Object).GetKnownField("m_pEEType")));
            codeStream.EmitLdc(Context.Target.PointerSize);
            codeStream.Emit(ILOpcode.add);
            codeStream.EmitLdInd(owningTypeAsOpen);

            codeStream.EmitLdArg(0);
            codeStream.EmitLdInd(owningTypeAsOpen);

            codeStream.Emit(ILOpcode.ceq);

            codeStream.Emit(ILOpcode.ret);

            codeStream.EmitLabel(lNotEqual);
            codeStream.Emit(ILOpcode.pop);
            codeStream.EmitLdc(0);
            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }
Ejemplo n.º 2
0
        public override MethodIL EmitIL()
        {
            ILEmitter    emitter                   = new ILEmitter();
            ILCodeStream argSetupStream            = emitter.NewCodeStream();
            ILCodeStream thisCallSiteSetupStream   = emitter.NewCodeStream();
            ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream();
            ILCodeStream returnCodeStream          = emitter.NewCodeStream();

            // This function will look like
            //
            // !For each parameter to the method
            //    !if (parameter is In Parameter)
            //       localX is TypeOfParameterX&
            //       ldarg.2
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperIn(ref ArgSetupState, RuntimeTypeHandle)
            //       stloc localX
            //    !else
            //       localX is TypeOfParameter
            //       ldarg.2
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperRef(ref ArgSetupState, RuntimeTypeHandle)
            //       stloc localX

            // ldarg.2
            // call DynamicInvokeArgSetupComplete(ref ArgSetupState)

            // *** Thiscall instruction stream starts here ***

            // ldarg.3 // Load targetIsThisCall
            // brfalse Not_this_call

            // ldarg.0 // Load this pointer
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType thiscall(TypeOfParameter1, ...)
            // br Process_return

            // *** Static call instruction stream starts here ***

            // Not_this_call:
            // !For each parameter
            //    !if (parameter is In Parameter)
            //       ldloc localX
            //       ldobj TypeOfParameterX
            //    !else
            //       ldloc localX
            // ldarg.1
            // calli ReturnType (TypeOfParameter1, ...)

            // *** Return code stream starts here ***

            // Process_return:
            // !if (ReturnType is Byref)
            //    dup
            //    brfalse ByRefNull
            //    ldobj ReturnType
            // !if ((ReturnType == void)
            //    ldnull
            // !elif (ReturnType is pointer)
            //    System.Reflection.Pointer.Box(ReturnType)
            // !else
            //    box ReturnType
            // ret
            //
            // !if (ReturnType is ByRef)
            //   ByRefNull:
            //   pop
            //   call InvokeUtils.get_NullByRefValueSentinel
            //   ret

            ILCodeLabel lStaticCall    = emitter.NewCodeLabel();
            ILCodeLabel lProcessReturn = emitter.NewCodeLabel();

            thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall
            thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall);
            staticCallSiteSetupStream.EmitLabel(lStaticCall);

            thisCallSiteSetupStream.EmitLdArg(0); // thisPtr

            ILToken tokDynamicInvokeParamHelperRef =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null));
            ILToken tokDynamicInvokeParamHelperIn =
                emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null));

            TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length];

            for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++)
            {
                TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true);
                DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex];

                for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++)
                {
                    paramType = paramType.MakePointerType();
                }

                ILToken         tokParamType = emitter.NewToken(paramType);
                ILLocalVariable local        = emitter.NewLocal(paramType.MakeByRefType());

                thisCallSiteSetupStream.EmitLdLoc(local);
                staticCallSiteSetupStream.EmitLdLoc(local);

                argSetupStream.EmitLdArg(2); // argSetupState
                argSetupStream.Emit(ILOpcode.ldtoken, tokParamType);

                if (paramKind == DynamicInvokeMethodParameterKind.Reference)
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef);

                    targetMethodSignature[paramIndex] = paramType.MakeByRefType();
                }
                else
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn);

                    thisCallSiteSetupStream.EmitLdInd(paramType);
                    staticCallSiteSetupStream.EmitLdInd(paramType);

                    targetMethodSignature[paramIndex] = paramType;
                }
                argSetupStream.EmitStLoc(local);
            }

            argSetupStream.EmitLdArg(2); // argSetupState
            argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null)));

            thisCallSiteSetupStream.EmitLdArg(1);   // methodToCall
            staticCallSiteSetupStream.EmitLdArg(1); // methodToCall

            DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType;
            TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ?
                                  Context.GetSignatureVariable(_targetSignature.Length, true) :
                                  Context.GetWellKnownType(WellKnownType.Void);

            for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++)
            {
                returnType = returnType.MakePointerType();
            }

            if (returnKind == DynamicInvokeMethodParameterKind.Reference)
            {
                returnType = returnType.MakeByRefType();
            }

            MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature);

            thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig));
            thisCallSiteSetupStream.Emit(ILOpcode.br, lProcessReturn);

            MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature);

            staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig));

            returnCodeStream.EmitLabel(lProcessReturn);

            ILCodeLabel lByRefReturnNull = null;

            if (returnKind == DynamicInvokeMethodParameterKind.None)
            {
                returnCodeStream.Emit(ILOpcode.ldnull);
            }
            else
            {
                TypeDesc returnTypeForBoxing = returnType;

                if (returnType.IsByRef)
                {
                    // If this is a byref return, we need to dereference first
                    returnTypeForBoxing = ((ByRefType)returnType).ParameterType;
                    lByRefReturnNull    = emitter.NewCodeLabel();
                    returnCodeStream.Emit(ILOpcode.dup);
                    returnCodeStream.Emit(ILOpcode.brfalse, lByRefReturnNull);
                    returnCodeStream.EmitLdInd(returnTypeForBoxing);
                }

                if (returnTypeForBoxing.IsPointer)
                {
                    // Pointers box differently
                    returnCodeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnTypeForBoxing));
                    MethodDesc getTypeFromHandleMethod =
                        Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null);
                    returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod));

                    MethodDesc pointerBoxMethod =
                        Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null);
                    returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod));
                }
                else
                {
                    ILToken tokReturnType = emitter.NewToken(returnTypeForBoxing);
                    returnCodeStream.Emit(ILOpcode.box, tokReturnType);
                }
            }

            returnCodeStream.Emit(ILOpcode.ret);

            if (lByRefReturnNull != null)
            {
                returnCodeStream.EmitLabel(lByRefReturnNull);
                returnCodeStream.Emit(ILOpcode.pop);
                returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("get_NullByRefValueSentinel", null)));
                returnCodeStream.Emit(ILOpcode.ret);
            }

            return(emitter.Link(this));
        }