Beispiel #1
0
        private MethodIL EmitIL()
        {
            PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
            ILEmitter            emitter = pInvokeILCodeStreams.Emitter;
            ILCodeStream         marshallingCodestream   = pInvokeILCodeStreams.MarshallingCodeStream;
            ILCodeStream         unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream;
            ILCodeStream         cleanupCodestream       = pInvokeILCodeStreams.CleanupCodeStream;

            // Marshalling is wrapped in a finally block to guarantee cleanup
            ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion();

            marshallingCodestream.BeginTry(tryFinally);
            cleanupCodestream.BeginHandler(tryFinally);

            // Marshal the arguments
            bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid;

            for (int i = isHRSwappedRetVal ? 1 : 0; i < _marshallers.Length; i++)
            {
                _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams);
            }

            if (isHRSwappedRetVal)
            {
                _marshallers[0].EmitMarshallingIL(pInvokeILCodeStreams);
            }

            // make the call
            switch (_targetMethod)
            {
            case DelegateMarshallingMethodThunk delegateMethod:
                EmitDelegateCall(delegateMethod, pInvokeILCodeStreams);
                break;

            case CalliMarshallingMethodThunk calliMethod:
                EmitCalli(pInvokeILCodeStreams, calliMethod);
                break;

            default:
                EmitPInvokeCall(pInvokeILCodeStreams);
                break;
            }

            ILCodeLabel lReturn = emitter.NewCodeLabel();

            unmarshallingCodestream.Emit(ILOpcode.leave, lReturn);
            unmarshallingCodestream.EndTry(tryFinally);

            cleanupCodestream.Emit(ILOpcode.endfinally);
            cleanupCodestream.EndHandler(tryFinally);

            cleanupCodestream.EmitLabel(lReturn);

            _marshallers[0].LoadReturnValue(cleanupCodestream);
            cleanupCodestream.Emit(ILOpcode.ret);

            return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired()));
        }
Beispiel #2
0
        private MethodIL EmitIL()
        {
            if (!_importMetadata.Flags.PreserveSig)
            {
                throw new NotSupportedException();
            }

            if (MarshalHelpers.ShouldCheckForPendingException(_targetMethod.Context.Target, _importMetadata))
            {
                throw new NotSupportedException();
            }

            if (_targetMethod.IsUnmanagedCallersOnly)
            {
                throw new NotSupportedException();
            }

            if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute"))
            {
                throw new NotSupportedException();
            }

            PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
            ILEmitter            emitter = pInvokeILCodeStreams.Emitter;
            ILCodeStream         marshallingCodestream   = pInvokeILCodeStreams.MarshallingCodeStream;
            ILCodeStream         unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream;
            ILCodeStream         cleanupCodestream       = pInvokeILCodeStreams.CleanupCodeStream;

            // Marshalling is wrapped in a finally block to guarantee cleanup
            ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion();

            marshallingCodestream.BeginTry(tryFinally);
            cleanupCodestream.BeginHandler(tryFinally);

            // Marshal the arguments
            for (int i = 0; i < _marshallers.Length; i++)
            {
                _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams);
            }

            EmitPInvokeCall(pInvokeILCodeStreams);

            ILCodeLabel lReturn = emitter.NewCodeLabel();

            unmarshallingCodestream.Emit(ILOpcode.leave, lReturn);
            unmarshallingCodestream.EndTry(tryFinally);

            cleanupCodestream.Emit(ILOpcode.endfinally);
            cleanupCodestream.EndHandler(tryFinally);

            cleanupCodestream.EmitLabel(lReturn);

            _marshallers[0].LoadReturnValue(cleanupCodestream);
            cleanupCodestream.Emit(ILOpcode.ret);

            return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod)));
        }
Beispiel #3
0
        public override MethodIL EmitIL()
        {
            // We will generate the following code:
            //
            // object ret;
            // object[] args = new object[parameterCount];
            // args[0] = param0;
            // args[1] = param1;
            //  ...
            // try {
            //      ret = ((Func<object[], object>)dlg.m_helperObject)(args);
            // } finally {
            //      param0 = (T0)args[0];   // only generated for each byref argument
            // }
            // return (TRet)ret;

            ILEmitter    emitter    = new ILEmitter();
            ILCodeStream codeStream = emitter.NewCodeStream();

            TypeDesc objectType      = Context.GetWellKnownType(WellKnownType.Object);
            TypeDesc objectArrayType = objectType.MakeArrayType();

            ILLocalVariable argsLocal = emitter.NewLocal(objectArrayType);

            bool hasReturnValue = !Signature.ReturnType.IsVoid;

            bool hasRefArgs = false;

            if (Signature.Length > 0)
            {
                codeStream.EmitLdc(Signature.Length);
                codeStream.Emit(ILOpcode.newarr, emitter.NewToken(objectType));
                codeStream.EmitStLoc(argsLocal);

                for (int i = 0; i < Signature.Length; i++)
                {
                    TypeDesc paramType    = Signature[i];
                    bool     paramIsByRef = false;

                    if (paramType.IsByRef)
                    {
                        hasRefArgs  |= paramType.IsByRef;
                        paramIsByRef = true;
                        paramType    = ((ByRefType)paramType).ParameterType;
                    }

                    hasRefArgs |= paramType.IsByRef;

                    codeStream.EmitLdLoc(argsLocal);
                    codeStream.EmitLdc(i);
                    codeStream.EmitLdArg(i + 1);

                    ILToken paramToken = emitter.NewToken(paramType);

                    if (paramIsByRef)
                    {
                        codeStream.Emit(ILOpcode.ldobj, paramToken);
                    }
                    codeStream.Emit(ILOpcode.box, paramToken);
                    codeStream.Emit(ILOpcode.stelem_ref);
                }
            }
            else
            {
                MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray");
                codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod));
                codeStream.EmitStLoc(argsLocal);
            }

            ILExceptionRegionBuilder tryFinallyRegion = null;

            if (hasRefArgs)
            {
                // we emit a try/finally to update the args array even if an exception is thrown
                tryFinallyRegion = emitter.NewFinallyRegion();
                codeStream.BeginTry(tryFinallyRegion);
            }

            codeStream.EmitLdArg(0);
            codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField));

            MetadataType funcType         = Context.SystemModule.GetKnownType("System", "Func`2");
            TypeDesc     instantiatedFunc = funcType.MakeInstantiatedType(objectArrayType, objectType);

            codeStream.Emit(ILOpcode.castclass, emitter.NewToken(instantiatedFunc));

            codeStream.EmitLdLoc(argsLocal);

            MethodDesc invokeMethod = instantiatedFunc.GetKnownMethod("Invoke", null);

            codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod));

            ILLocalVariable retLocal = (ILLocalVariable)(-1);

            if (hasReturnValue)
            {
                retLocal = emitter.NewLocal(objectType);
                codeStream.EmitStLoc(retLocal);
            }
            else
            {
                codeStream.Emit(ILOpcode.pop);
            }

            if (hasRefArgs)
            {
                ILCodeLabel returnLabel = emitter.NewCodeLabel();
                codeStream.Emit(ILOpcode.leave, returnLabel);
                codeStream.EndTry(tryFinallyRegion);

                // copy back ref/out args
                codeStream.BeginHandler(tryFinallyRegion);
                for (int i = 0; i < Signature.Length; i++)
                {
                    TypeDesc paramType = Signature[i];
                    if (paramType.IsByRef)
                    {
                        paramType = ((ByRefType)paramType).ParameterType;
                        ILToken paramToken = emitter.NewToken(paramType);

                        // Update parameter
                        codeStream.EmitLdArg(i + 1);
                        codeStream.EmitLdLoc(argsLocal);
                        codeStream.EmitLdc(i);
                        codeStream.Emit(ILOpcode.ldelem_ref);
                        codeStream.Emit(ILOpcode.unbox_any, paramToken);
                        codeStream.Emit(ILOpcode.stobj, paramToken);
                    }
                }
                codeStream.Emit(ILOpcode.endfinally);
                codeStream.EndHandler(tryFinallyRegion);
                codeStream.EmitLabel(returnLabel);
            }

            if (hasReturnValue)
            {
                codeStream.EmitLdLoc(retLocal);
                codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(Signature.ReturnType));
            }

            codeStream.Emit(ILOpcode.ret);

            return(emitter.Link(this));
        }