Example #1
0
        public PInvokeTargetNativeMethod(TypeDesc owningType, MethodSignature signature, PInvokeMetadata methodMetadata)
        {
            _owningType     = owningType;
            _signature      = signature;
            _methodMetadata = methodMetadata;

            _sequenceNumber = System.Threading.Interlocked.Increment(ref s_nativeMethodCounter);
        }
        private PInvokeMarshallingILEmitter(MethodDesc targetMethod)
        {
            Debug.Assert(targetMethod.IsPInvoke);
            Debug.Assert(RequiresMarshalling(targetMethod));

            _targetMethod   = targetMethod;
            _importMetadata = targetMethod.GetPInvokeMethodMetadata();

            _emitter = null;
            _marshallingCodeStream = null;
        }
Example #3
0
        private PInvokeILEmitter(MethodDesc targetMethod)
        {
            Debug.Assert(targetMethod.IsPInvoke);

            _targetMethod   = targetMethod;
            _context        = _targetMethod.Context;
            _importMetadata = targetMethod.GetPInvokeMethodMetadata();

            _emitter = null;
            _marshallingCodeStream            = null;
            _returnValueMarshallingCodeStream = null;
            _unmarshallingCodestream          = null;
        }
Example #4
0
 /// <summary>
 /// Gets an object representing the static data for RVA mapped fields from the PE image.
 /// </summary>
 public ObjectNode GetFieldRvaData(FieldDesc field)
 {
     if (field.GetType() == typeof(Internal.IL.Stubs.PInvokeLazyFixupField))
     {
         var             pInvokeFixup = (Internal.IL.Stubs.PInvokeLazyFixupField)field;
         PInvokeMetadata metadata     = pInvokeFixup.PInvokeMetadata;
         return(_nodeFactory.PInvokeMethodFixup(metadata.Module, metadata.Name));
     }
     else
     {
         return(_nodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
                                              ((EcmaField)field).GetFieldRvaData(), _typeSystemContext.Target.PointerSize));
     }
 }
Example #5
0
 /// <summary>
 /// Gets an object representing the static data for RVA mapped fields from the PE image.
 /// </summary>
 public ObjectNode GetFieldRvaData(FieldDesc field)
 {
     if (field.GetType() == typeof(PInvokeLazyFixupField))
     {
         var             pInvokeFixup = (PInvokeLazyFixupField)field;
         PInvokeMetadata metadata     = pInvokeFixup.PInvokeMetadata;
         return(NodeFactory.PInvokeMethodFixup(metadata.Module, metadata.Name));
     }
     else
     {
         // Use the typical field definition in case this is an instantiated generic type
         field = field.GetTypicalFieldDefinition();
         return(NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
                                             ((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize));
     }
 }
Example #6
0
        public PInvokeMethodData(PInvokeLazyFixupField pInvokeLazyFixupField)
        {
            PInvokeMetadata metadata        = pInvokeLazyFixupField.PInvokeMetadata;
            ModuleDesc      declaringModule = ((MetadataType)pInvokeLazyFixupField.TargetMethod.OwningType).Module;

            DllImportSearchPath?dllImportSearchPath = default;

            if (declaringModule.Assembly is EcmaAssembly asm)
            {
                // We look for [assembly:DefaultDllImportSearchPaths(...)]
                var attrHandle = asm.MetadataReader.GetCustomAttributeHandle(asm.AssemblyDefinition.GetCustomAttributes(),
                                                                             "System.Runtime.InteropServices", "DefaultDllImportSearchPathsAttribute");
                if (!attrHandle.IsNil)
                {
                    var attr    = asm.MetadataReader.GetCustomAttribute(attrHandle);
                    var decoded = attr.DecodeValue(new CustomAttributeTypeProvider(asm));
                    if (decoded.FixedArguments.Length == 1 &&
                        decoded.FixedArguments[0].Value is int searchPath)
                    {
                        dllImportSearchPath = (DllImportSearchPath)searchPath;
                    }
                }
            }
            ModuleData = new PInvokeModuleData(metadata.Module, dllImportSearchPath, declaringModule);

            EntryPointName = metadata.Name;

            CharSet charSetMangling = default;

            if (declaringModule.Context.Target.IsWindows && !metadata.Flags.ExactSpelling)
            {
                // Mirror CharSet normalization from Marshaller.CreateMarshaller
                bool isAnsi = metadata.Flags.CharSet switch
                {
                    CharSet.Ansi => true,
                    CharSet.Unicode => false,
                    CharSet.Auto => false,
                    _ => true
                };

                charSetMangling = isAnsi ? CharSet.Ansi : CharSet.Unicode;
            }
            CharSetMangling = charSetMangling;
        }
Example #7
0
        /// <summary>
        /// Gets an object representing the static data for RVA mapped fields from the PE image.
        /// </summary>
        public virtual ISymbolNode GetFieldRvaData(FieldDesc field)
        {
            if (field.GetType() == typeof(PInvokeLazyFixupField))
            {
                var                 pInvokeFixup        = (PInvokeLazyFixupField)field;
                PInvokeMetadata     metadata            = pInvokeFixup.PInvokeMetadata;
                ModuleDesc          callingModule       = ((MetadataType)pInvokeFixup.TargetMethod.OwningType).Module;
                DllImportSearchPath?dllImportSearchPath = default;
                if (callingModule.Assembly is EcmaAssembly asm)
                {
                    // We look for [assembly:DefaultDllImportSearchPaths(...)]
                    var attrHandle = asm.MetadataReader.GetCustomAttributeHandle(asm.AssemblyDefinition.GetCustomAttributes(),
                                                                                 "System.Runtime.InteropServices", "DefaultDllImportSearchPathsAttribute");
                    if (!attrHandle.IsNil)
                    {
                        var attr    = asm.MetadataReader.GetCustomAttribute(attrHandle);
                        var decoded = attr.DecodeValue(new CustomAttributeTypeProvider(asm));
                        if (decoded.FixedArguments.Length == 1 &&
                            decoded.FixedArguments[0].Value is int searchPath)
                        {
                            dllImportSearchPath = (DllImportSearchPath)searchPath;
                        }
                    }
                }

                PInvokeModuleData moduleData = new PInvokeModuleData(metadata.Module, dllImportSearchPath, callingModule);
                return(NodeFactory.PInvokeMethodFixup(moduleData, metadata.Name, metadata.Flags));
            }
            else if (field is ExternSymbolMappedField externField)
            {
                return(NodeFactory.ExternSymbol(externField.SymbolName));
            }
            else
            {
                // Use the typical field definition in case this is an instantiated generic type
                field = field.GetTypicalFieldDefinition();
                return(NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
                                                    ((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize));
            }
        }
Example #8
0
        public static bool IsMarshallingRequired(MethodDesc targetMethod)
        {
            Debug.Assert(targetMethod.IsPInvoke);

            if (targetMethod.IsUnmanagedCallersOnly)
            {
                return(true);
            }

            PInvokeMetadata metadata = targetMethod.GetPInvokeMethodMetadata();
            PInvokeFlags    flags    = metadata.Flags;

            if (flags.SetLastError)
            {
                return(true);
            }

            if (!flags.PreserveSig)
            {
                return(true);
            }

            if (MarshalHelpers.ShouldCheckForPendingException(targetMethod.Context.Target, metadata))
            {
                return(true);
            }

            var marshallers = GetMarshallersForMethod(targetMethod);

            for (int i = 0; i < marshallers.Length; i++)
            {
                if (marshallers[i].IsMarshallingRequired())
                {
                    return(true);
                }
            }

            return(false);
        }
Example #9
0
        private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager)
        {
            Debug.Assert(targetMethod.IsPInvoke || targetMethod is DelegateMarshallingMethodThunk || targetMethod is CalliMarshallingMethodThunk);
            _targetMethod = targetMethod;
            _pInvokeILEmitterConfiguration = pinvokeILEmitterConfiguration;
            _pInvokeMetadata     = targetMethod.GetPInvokeMethodMetadata();
            _interopStateManager = interopStateManager;

            //
            // targetMethod could be either a PInvoke or a DelegateMarshallingMethodThunk
            // ForwardNativeFunctionWrapper method thunks are marked as PInvokes, so it is
            // important to check them first here so that we get the right flags.
            //
            if (_targetMethod is DelegateMarshallingMethodThunk delegateMethod)
            {
                _flags = ((EcmaType)delegateMethod.DelegateType.GetTypeDefinition()).GetDelegatePInvokeFlags();
            }
            else
            {
                _flags = _pInvokeMetadata.Flags;
            }
            _marshallers = InitializeMarshallers(targetMethod, interopStateManager, _flags);
        }
 public PInvokeTargetNativeMethod(TypeDesc owningType, MethodSignature signature, PInvokeMetadata methodMetadata)
 {
     _owningType     = owningType;
     _signature      = signature;
     _methodMetadata = methodMetadata;
 }
Example #11
0
 public PInvokeLazyFixupField(DefType owningType, PInvokeMetadata pInvokeMetadata)
 {
     _owningType      = owningType;
     _pInvokeMetadata = pInvokeMetadata;
 }
Example #12
0
        public MethodIL EmitIL()
        {
            MethodSignature targetMethodSignature = _targetMethod.Signature;

            // We have 4 code streams:
            // - _marshallingCodeStream is used to convert each argument into a native type and
            // store that into the local
            // - callsiteSetupCodeStream is used to used to load each previously generated local
            // and call the actual target native method.
            // - _returnValueMarshallingCodeStream is used to convert the native return value
            // to managed one.
            // - _unmarshallingCodestream is used to propagate [out] native arguments values to
            // managed ones.
            _emitter = new ILEmitter();
            ILCodeStream fnptrLoadStream = _emitter.NewCodeStream();

            _marshallingCodeStream = _emitter.NewCodeStream();
            ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream();

            _returnValueMarshallingCodeStream = _emitter.NewCodeStream();
            _unmarshallingCodestream          = _emitter.NewCodeStream();

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

            //
            // Parameter marshalling
            //

            //
            // Convert each argument to something we can pass to native and store it in a local.
            // Then load the local in the second code stream.
            //
            for (int i = 0; i < targetMethodSignature.Length; i++)
            {
                // TODO: throw if there's custom marshalling

                _marshallingCodeStream.EmitLdArg(i);

                TypeDesc nativeType = MarshalArgument(targetMethodSignature[i]);

                nativeParameterTypes[i] = nativeType;

                ILLocalVariable vMarshalledTypeTemp = _emitter.NewLocal(nativeType);
                _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp);

                callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp);
            }

            //
            // Return value marshalling
            //

            // TODO: throw if SetLastError is true
            // TODO: throw if there's custom marshalling

            TypeDesc nativeReturnType = MarshalReturnValue(targetMethodSignature.ReturnType);

            if (UseLazyResolution(_targetMethod, _importMetadata.Module))
            {
                MetadataType lazyHelperType   = _targetMethod.Context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = new PInvokeLazyFixupField((DefType)_targetMethod.OwningType, _importMetadata);
                fnptrLoadStream.Emit(ILOpcode.ldsflda, _emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, _emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(_importMetadata.Attributes);

                MethodSignature nativeCalliSig = new MethodSignature(
                    targetMethodSignature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes);

                ILLocalVariable vNativeFunctionPointer = _emitter.NewLocal(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, _emitter.NewToken(nativeCalliSig));
            }
            else
            {
                // Eager call
                PInvokeMetadata nativeImportMetadata =
                    new PInvokeMetadata(_importMetadata.Module, _importMetadata.Name ?? _targetMethod.Name, _importMetadata.Attributes);

                MethodSignature nativeSig = new MethodSignature(
                    targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, nativeImportMetadata);

                callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod));
            }

            _unmarshallingCodestream.Emit(ILOpcode.ret);

            return(_emitter.Link(_targetMethod));
        }
Example #13
0
        private MethodIL EmitIL()
        {
            PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
            ILEmitter            emitter                 = pInvokeILCodeStreams.Emitter;
            ILCodeStream         fnptrLoadStream         = pInvokeILCodeStreams.FunctionPointerLoadStream;
            ILCodeStream         callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream;
            ILCodeStream         unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream;

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

            // make the call
            TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;

            TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

            for (int i = 1; i < _marshallers.Length; i++)
            {
                nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
            }

            MethodDesc      targetMethod   = _methodData.TargetMethod;
            PInvokeMetadata importMetadata = _methodData.ImportMetadata;
            PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration;
            MethodSignature nativeSig;

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 _methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null)));
            }

            if (targetMethod is DelegateMarshallingMethodThunk)
            {
                nativeSig = new MethodSignature(MethodSignatureFlags.Static, 0, nativeReturnType, nativeParameterTypes);
                TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1];
                for (int i = 1; i < _marshallers.Length; i++)
                {
                    parameters[i - 1] = _marshallers[i].ManagedParameterType;
                }
                MethodSignature managedSignature = new MethodSignature(MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters);
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(targetMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetDelegateFunctionPointer", null)));
                ILLocalVariable vDelegateStub = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                fnptrLoadStream.EmitStLoc(vDelegateStub);
                callsiteSetupCodeStream.EmitLdLoc(vDelegateStub);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature));
            }
            else if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration))
            {
                MetadataType lazyHelperType   = targetMethod.Context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = new PInvokeLazyFixupField((DefType)targetMethod.OwningType, importMetadata);
                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(importMetadata.Attributes);

                nativeSig = new MethodSignature(
                    targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes);

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
            }
            else
            {
                // Eager call
                PInvokeMetadata nativeImportMetadata =
                    new PInvokeMetadata(importMetadata.Module, importMetadata.Name ?? targetMethod.Name, importMetadata.Attributes);

                nativeSig = new MethodSignature(
                    targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(targetMethod.OwningType, nativeSig, nativeImportMetadata, pinvokeILEmitterConfiguration.GetNextNativeMethodId());

                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later
            // by calling PInvokeMarshal.GetLastWin32Error
            if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 _methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null)));
            }

            unmarshallingCodestream.Emit(ILOpcode.ret);

            return(new  PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(targetMethod), IsStubRequired(), nativeSig));
        }
Example #14
0
 public PInvokeTargetNativeMethod(TypeDesc owningType, MethodSignature signature, PInvokeMetadata methodMetadata, int sequenceNumber)
 {
     _owningType     = owningType;
     _signature      = signature;
     _methodMetadata = methodMetadata;
     _sequenceNumber = sequenceNumber;
 }
Example #15
0
        private MethodIL EmitIL()
        {
            PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams();
            ILEmitter            emitter                 = pInvokeILCodeStreams.Emitter;
            ILCodeStream         fnptrLoadStream         = pInvokeILCodeStreams.FunctionPointerLoadStream;
            ILCodeStream         callsiteSetupCodeStream = pInvokeILCodeStreams.CallsiteSetupCodeStream;
            ILCodeStream         unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream;
            TypeSystemContext    context                 = _targetMethod.Context;

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

            // make the call
            TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;

            TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

            for (int i = 1; i < _marshallers.Length; i++)
            {
                nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType;
            }

            MethodSignature nativeSig;

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if (_importMetadata.Flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null)));
            }

            DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk;

            if (delegateMethod != null)
            {
                if (delegateMethod.IsOpenStaticDelegate)
                {
                    //
                    // For Open static delegates call
                    //     InteropHelpers.GetCurrentCalleeOpenStaticDelegateFunctionPointer()
                    // which returns a function pointer. Just call the function pointer and we are done.
                    //
                    TypeDesc[] parameters = new TypeDesc[_marshallers.Length - 1];
                    for (int i = 1; i < _marshallers.Length; i++)
                    {
                        parameters[i - 1] = _marshallers[i].ManagedParameterType;
                    }

                    MethodSignature managedSignature = new MethodSignature(MethodSignatureFlags.Static, 0, _marshallers[0].ManagedParameterType, parameters);
                    fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetCurrentCalleeOpenStaticDelegateFunctionPointer", null)));
                    ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                    fnptrLoadStream.EmitStLoc(vDelegateStub);
                    callsiteSetupCodeStream.EmitLdLoc(vDelegateStub);
                    callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(managedSignature));
                }
                else
                {
                    //
                    // For closed delegates call
                    //     InteropHelpers.GetCurrentCalleeDelegate<Delegate>
                    // which returns the delegate. Do a CallVirt on the invoke method.
                    //
                    MethodDesc instantiatedHelper = delegateMethod.Context.GetInstantiatedMethod(
                        delegateMethod.Context.GetHelperType("InteropHelpers").GetKnownMethod("GetCurrentCalleeDelegate", null),
                        new Instantiation((delegateMethod.DelegateType)));
                    fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(instantiatedHelper));

                    ILLocalVariable vDelegateStub = emitter.NewLocal(delegateMethod.DelegateType);
                    fnptrLoadStream.EmitStLoc(vDelegateStub);
                    fnptrLoadStream.EmitLdLoc(vDelegateStub);
                    MethodDesc invokeMethod = delegateMethod.DelegateType.GetKnownMethod("Invoke", null);
                    callsiteSetupCodeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod));
                }
            }
            else if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration))
            {
                MetadataType lazyHelperType   = _targetMethod.Context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = new PInvokeLazyFixupField((DefType)_targetMethod.OwningType, _importMetadata);
                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallConv = _importMetadata.Flags.UnmanagedCallingConvention;

                nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes);

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
            }
            else
            {
                // Eager call
                PInvokeMetadata nativeImportMetadata =
                    new PInvokeMetadata(_importMetadata.Module, _importMetadata.Name ?? _targetMethod.Name, _importMetadata.Flags);

                nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, nativeImportMetadata, _pInvokeILEmitterConfiguration.GetNextNativeMethodId());

                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later
            // by calling PInvokeMarshal.GetLastWin32Error
            if (_importMetadata.Flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("SaveLastWin32Error", null)));
            }

            unmarshallingCodestream.Emit(ILOpcode.ret);

            return(new  PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired()));
        }
Example #16
0
        private MethodIL EmitIL()
        {
            // We have 4 code streams:
            // - _marshallingCodeStream is used to convert each argument into a native type and
            // store that into the local
            // - callsiteSetupCodeStream is used to used to load each previously generated local
            // and call the actual target native method.
            // - _returnValueMarshallingCodeStream is used to convert the native return value
            // to managed one.
            // - _unmarshallingCodestream is used to propagate [out] native arguments values to
            // managed ones.

            ILEmitter    emitter                          = new ILEmitter();
            ILCodeStream fnptrLoadStream                  = emitter.NewCodeStream();
            ILCodeStream marshallingCodeStream            = emitter.NewCodeStream();
            ILCodeStream callsiteSetupCodeStream          = emitter.NewCodeStream();
            ILCodeStream returnValueMarshallingCodeStream = emitter.NewCodeStream();
            ILCodeStream unmarshallingCodestream          = emitter.NewCodeStream();

            // Marshal the arguments
            for (int i = 0; i < _marshallers.Length; i++)
            {
                Marshaller marshaller = _marshallers[i];
                marshaller.EmitMarshallingIL(emitter, marshallingCodeStream, callsiteSetupCodeStream, unmarshallingCodestream, returnValueMarshallingCodeStream);
            }

            // make the call
            TypeDesc nativeReturnType = _marshallers[0].NativeType;

            TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1];

            for (int i = 1; i < _marshallers.Length; i++)
            {
                nativeParameterTypes[i - 1] = _marshallers[i].NativeType;
            }

            MethodDesc      targetMethod   = _methodData.TargetMethod;
            PInvokeMetadata importMetadata = _methodData.ImportMetadata;
            PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration = _methodData.PInvokeILEmitterConfiguration;

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 _methodData.PInvokeMarshal.GetKnownMethod("ClearLastWin32Error", null)));
            }

            if (MarshalHelpers.UseLazyResolution(targetMethod, importMetadata.Module, pinvokeILEmitterConfiguration))
            {
                MetadataType lazyHelperType   = targetMethod.Context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = new PInvokeLazyFixupField((DefType)targetMethod.OwningType, importMetadata);
                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType.GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallConv = PInvokeMetadata.GetUnmanagedCallingConvention(importMetadata.Attributes);

                MethodSignature nativeCalliSig = new MethodSignature(
                    targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes);

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr));
                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeCalliSig));
            }
            else
            {
                // Eager call
                PInvokeMetadata nativeImportMetadata =
                    new PInvokeMetadata(importMetadata.Module, importMetadata.Name ?? targetMethod.Name, importMetadata.Attributes);

                MethodSignature nativeSig = new MethodSignature(
                    targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(targetMethod.OwningType, nativeSig, nativeImportMetadata, pinvokeILEmitterConfiguration.GetNextNativeMethodId());

                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(nativeMethod));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastWin32Error so that last error can be used later
            // by calling PInvokeMarshal.GetLastWin32Error
            if ((importMetadata.Attributes & PInvokeAttributes.SetLastError) == PInvokeAttributes.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 _methodData.PInvokeMarshal.GetKnownMethod("SaveLastWin32Error", null)));
            }

            unmarshallingCodestream.Emit(ILOpcode.ret);

            return(emitter.Link(targetMethod));
        }