Ejemplo n.º 1
0
        /// <summary>
        /// Generates a calli sequence that is aware of fat function pointers and can unwrap them into
        /// a function pointer + instantiation argument if necessary.
        /// </summary>
        public static void EmitTransformedCalli(ILEmitter emitter, ILCodeStream codestream, MethodSignature targetSignature)
        {
            TypeSystemContext context = targetSignature.ReturnType.Context;

            int thisPointerParamDelta = 0;
            if (!targetSignature.IsStatic)
                thisPointerParamDelta = 1;

            // Start by saving the pointer to call and all the args into locals

            ILLocalVariable vPointerToCall = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr));
            codestream.EmitStLoc(vPointerToCall);

            ILLocalVariable[] vParameters = new ILLocalVariable[targetSignature.Length + thisPointerParamDelta];
            for (int i = thisPointerParamDelta; i < vParameters.Length; i++)
            {
                vParameters[vParameters.Length - i - 1 + thisPointerParamDelta] = emitter.NewLocal(targetSignature[targetSignature.Length - (i - thisPointerParamDelta) - 1]);
                codestream.EmitStLoc(vParameters[vParameters.Length - i - 1 + thisPointerParamDelta]);
            }
            if (!targetSignature.IsStatic)
            {
                vParameters[0] = emitter.NewLocal(context.GetWellKnownType(WellKnownType.Object));
                codestream.EmitStLoc(vParameters[0]);
            }

            // Is this a fat pointer?
            codestream.EmitLdLoc(vPointerToCall);
            Debug.Assert(((FatFunctionPointerConstants.Offset - 1) & FatFunctionPointerConstants.Offset) == 0);
            codestream.EmitLdc(FatFunctionPointerConstants.Offset);
            codestream.Emit(ILOpcode.and);

            ILCodeLabel notAFatPointer = emitter.NewCodeLabel();
            codestream.Emit(ILOpcode.brfalse, notAFatPointer);

            //
            // Fat pointer case
            //
            codestream.EmitLdLoc(vPointerToCall);
            codestream.EmitLdc(FatFunctionPointerConstants.Offset);
            codestream.Emit(ILOpcode.sub);

            // Get the pointer to call from the fat pointer
            codestream.Emit(ILOpcode.dup);
            codestream.Emit(ILOpcode.ldind_i);
            codestream.EmitStLoc(vPointerToCall);

            // Get the instantiation argument
            codestream.EmitLdc(context.Target.PointerSize);
            codestream.Emit(ILOpcode.add);
            codestream.Emit(ILOpcode.ldind_i);
            codestream.Emit(ILOpcode.ldind_i);
            ILLocalVariable instArg = emitter.NewLocal(context.GetWellKnownType(WellKnownType.IntPtr));
            codestream.EmitStLoc(instArg);

            // Load this
            int firstRealParameter = 0;
            if (!targetSignature.IsStatic)
            {
                codestream.EmitLdLoc(vParameters[0]);
                firstRealParameter = 1;
            }

            // Load hidden arg
            codestream.EmitLdLoc(instArg);

            // Load rest of args
            for (int i = firstRealParameter; i < vParameters.Length; i++)
            {
                codestream.EmitLdLoc(vParameters[i]);
            }
            codestream.EmitLdLoc(vPointerToCall);

            // The signature has a hidden argument
            TypeDesc[] newParameters = new TypeDesc[targetSignature.Length + 1];
            for (int i = 0; i < targetSignature.Length; i++)
                newParameters[i + 1] = targetSignature[i];
            newParameters[0] = context.GetWellKnownType(WellKnownType.IntPtr);
            MethodSignature newMethodSignature = new MethodSignature(targetSignature.Flags,
                targetSignature.GenericParameterCount, targetSignature.ReturnType, newParameters);

            codestream.Emit(ILOpcode.calli, emitter.NewToken(newMethodSignature));

            ILCodeLabel done = emitter.NewCodeLabel();
            codestream.Emit(ILOpcode.br, done);

            //
            // Not a fat pointer case
            //
            codestream.EmitLabel(notAFatPointer);

            for (int i = 0; i < vParameters.Length; i++)
            {
                codestream.EmitLdLoc(vParameters[i]);
            }
            codestream.EmitLdLoc(vPointerToCall);
            codestream.Emit(ILOpcode.calli, emitter.NewToken(targetSignature));

            codestream.EmitLabel(done);
        }
Ejemplo n.º 2
0
        public override MethodIL EmitIL()
        {
            ILEmitter    emitter                   = new ILEmitter();
            ILCodeStream argSetupStream            = emitter.NewCodeStream();
            ILCodeStream thisCallSiteSetupStream   = emitter.NewCodeStream();
            ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream();

            // This function will look like
            //
            // !For each parameter to the method
            //    !if (parameter is In Parameter)
            //       localX is TypeOfParameterX&
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperIn(RuntimeTypeHandle)
            //       stloc localX
            //    !else
            //       localX is TypeOfParameter
            //       ldtoken TypeOfParameterX
            //       call DynamicInvokeParamHelperRef(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, ...)
            // !if ((ReturnType == void)
            //    ldnull
            // !else
            //    box ReturnType
            // ret

            // *** 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, ...)
            // !if ((ReturnType == void)
            //    ldnull
            // !else
            //    box ReturnType
            // ret

            ILCodeLabel lStaticCall = 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);
                ILToken         tokParamType = emitter.NewToken(paramType);
                ILLocalVariable local        = emitter.NewLocal(paramType.MakeByRefType());

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

                argSetupStream.Emit(ILOpcode.ldtoken, tokParamType);

                if (_targetSignature[paramIndex] == DynamicInvokeMethodParameterKind.Reference)
                {
                    argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef);

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

                    thisCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType);
                    staticCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType);

                    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

            TypeDesc returnType = _targetSignature.HasReturnValue ?
                                  Context.GetSignatureVariable(_targetSignature.Length, true) :
                                  Context.GetWellKnownType(WellKnownType.Void);

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

            CalliIntrinsic.EmitTransformedCalli(emitter, thisCallSiteSetupStream, thisCallMethodSig);
            //thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig));

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

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

            if (_targetSignature.HasReturnValue)
            {
                ILToken tokReturnType = emitter.NewToken(returnType);
                thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
                staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType);
            }
            else
            {
                thisCallSiteSetupStream.Emit(ILOpcode.ldnull);
                staticCallSiteSetupStream.Emit(ILOpcode.ldnull);
            }

            thisCallSiteSetupStream.Emit(ILOpcode.ret);
            staticCallSiteSetupStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }