コード例 #1
0
ファイル: PInvokeILEmitter.cs プロジェクト: z77ma/runtime
        private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
        {
            ILEmitter         emitter = ilCodeStreams.Emitter;
            ILCodeStream      callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;
            TypeSystemContext context = _targetMethod.Context;

            TypeDesc nativeReturnType = _marshallers[0].NativeParameterType;

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

            MetadataType stubHelpersType = InteropTypes.GetStubHelpers(context);

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if (_importMetadata.Flags.SetLastError)
            {
                if (!MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module))
                {
                    // When runtime marshalling is disabled, we don't support generating the stub IL
                    // in Ready-to-Run so we can correctly throw an exception at runtime when the user tries to
                    // use SetLastError=true when marshalling is disabled.
                    throw new NotSupportedException();
                }
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 stubHelpersType.GetKnownMethod("ClearLastError", null)));
            }

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

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

            var rawTargetMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig);

            callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(rawTargetMethod));

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError
            // so that last error can be used later by calling Marshal.GetLastPInvokeError
            if (_importMetadata.Flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 stubHelpersType.GetKnownMethod("SetLastError", null)));
            }
        }
コード例 #2
0
        public override void AddDependeciesDueToPInvoke(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
        {
            if (method.IsPInvoke && method.OwningType is MetadataType type && MarshalHelpers.IsRuntimeMarshallingEnabled(type.Module))
            {
                dependencies = dependencies ?? new DependencyList();

                MethodSignature methodSig = method.Signature;
                AddParameterMarshallingDependencies(ref dependencies, factory, method, methodSig.ReturnType);

                for (int i = 0; i < methodSig.Length; i++)
                {
                    AddParameterMarshallingDependencies(ref dependencies, factory, method, methodSig[i]);
                }
            }

            if (method.HasInstantiation)
            {
                dependencies = dependencies ?? new DependencyList();
                AddMarshalAPIsGenericDependencies(ref dependencies, factory, method);
            }
        }
コード例 #3
0
        private static                                 Marshaller[] InitializeMarshallers(MethodDesc targetMethod, InteropStateManager interopStateManager, PInvokeFlags flags)
        {
            MarshalDirection direction = MarshalDirection.Forward;
            MethodSignature  methodSig;
            bool             runtimeMarshallingEnabled;

            switch (targetMethod)
            {
            case DelegateMarshallingMethodThunk delegateMethod:
                methodSig = delegateMethod.DelegateSignature;
                direction = delegateMethod.Direction;
                runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(delegateMethod.DelegateType.Module);
                break;

            case CalliMarshallingMethodThunk calliMethod:
                methodSig = calliMethod.TargetSignature;
                runtimeMarshallingEnabled = calliMethod.RuntimeMarshallingEnabled;
                break;

            default:
                methodSig = targetMethod.Signature;
                runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)targetMethod.OwningType).Module);
                break;
            }
            int indexOffset = 0;

            if (!methodSig.IsStatic && direction == MarshalDirection.Forward)
            {
                // For instance methods(eg. Forward delegate marshalling thunk), first argument is
                // the instance
                indexOffset = 1;
            }
            ParameterMetadata[] parameterMetadataArray = targetMethod.GetParameterMetadata();
            Marshaller[]        marshallers            = new Marshaller[methodSig.Length + 1];
            int parameterIndex = 0;
            ParameterMetadata parameterMetadata;

            for (int i = 0; i < marshallers.Length; i++)
            {
                Debug.Assert(parameterIndex == parameterMetadataArray.Length || i <= parameterMetadataArray[parameterIndex].Index);
                if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index)
                {
                    // if we don't have metadata for the parameter, create a dummy one
                    parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null);
                }
                else
                {
                    Debug.Assert(i == parameterMetadataArray[parameterIndex].Index);
                    parameterMetadata = parameterMetadataArray[parameterIndex++];
                }

                TypeDesc parameterType;
                bool     isHRSwappedRetVal = false;
                if (i == 0)
                {
                    // First item is the return type
                    parameterType = methodSig.ReturnType;
                    if (!flags.PreserveSig && !parameterType.IsVoid)
                    {
                        // PreserveSig = false can only show up an regular forward PInvokes
                        Debug.Assert(direction == MarshalDirection.Forward);

                        parameterType     = methodSig.Context.GetByRefType(parameterType);
                        isHRSwappedRetVal = true;
                    }
                }
                else
                {
                    parameterType = methodSig[i - 1];
                }

                if (runtimeMarshallingEnabled)
                {
                    marshallers[i] = Marshaller.CreateMarshaller(parameterType,
                                                                 parameterIndex,
                                                                 methodSig.GetEmbeddedSignatureData(),
                                                                 MarshallerType.Argument,
                                                                 parameterMetadata.MarshalAsDescriptor,
                                                                 direction,
                                                                 marshallers,
                                                                 interopStateManager,
                                                                 indexOffset + parameterMetadata.Index,
                                                                 flags,
                                                                 parameterMetadata.In,
                                                                 isHRSwappedRetVal ? true : parameterMetadata.Out,
                                                                 isHRSwappedRetVal ? false : parameterMetadata.Return
                                                                 );
                }
                else
                {
                    marshallers[i] = Marshaller.CreateDisabledMarshaller(
                        parameterType,
                        parameterIndex,
                        MarshallerType.Argument,
                        direction,
                        marshallers,
                        indexOffset + parameterMetadata.Index,
                        flags,
                        parameterMetadata.Return);
                }
            }

            return(marshallers);
        }
コード例 #4
0
        private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams)
        {
            ILEmitter         emitter                 = ilCodeStreams.Emitter;
            ILCodeStream      fnptrLoadStream         = ilCodeStreams.FunctionPointerLoadStream;
            ILCodeStream      callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream;
            TypeSystemContext context                 = _targetMethod.Context;

            bool     isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid;
            TypeDesc nativeReturnType  = _flags.PreserveSig ? _marshallers[0].NativeParameterType : context.GetWellKnownType(WellKnownType.Int32);

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

            bool runtimeMarshallingEnabled = MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)_targetMethod.OwningType).Module);

            // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke
            if (_flags.SetLastError)
            {
                if (!runtimeMarshallingEnabled)
                {
                    // When runtime marshalling is disabled, we don't support SetLastError
                    throw new NotSupportedException();
                }
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastError", null)));
            }

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

            if (isHRSwappedRetVal)
            {
                if (!runtimeMarshallingEnabled)
                {
                    // When runtime marshalling is disabled, we don't support HResult-return-swapping
                    throw new NotSupportedException();
                }
                nativeParameterTypes[_marshallers.Length - 1] = _marshallers[0].NativeParameterType;
            }

            if (!_pInvokeILEmitterConfiguration.GenerateDirectCall(_targetMethod, out _))
            {
                MetadataType lazyHelperType   = context.GetHelperType("InteropHelpers");
                FieldDesc    lazyDispatchCell = _interopStateManager.GetPInvokeLazyFixupField(_targetMethod);

                fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell));
                fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType
                                                                     .GetKnownMethod("ResolvePInvoke", null)));

                MethodSignatureFlags unmanagedCallingConvention = _flags.UnmanagedCallingConvention;
                if (unmanagedCallingConvention == MethodSignatureFlags.None)
                {
                    unmanagedCallingConvention = MethodSignatureFlags.UnmanagedCallingConvention;
                }

                EmbeddedSignatureData[] embeddedSignatureData = null;
                if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "SuppressGCTransitionAttribute"))
                {
                    embeddedSignatureData = new EmbeddedSignatureData[]
                    {
                        new EmbeddedSignatureData()
                        {
                            index = MethodSignature.IndexOfCustomModifiersOnReturnType,
                            kind  = EmbeddedSignatureDataKind.OptionalCustomModifier,
                            type  = context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "CallConvSuppressGCTransition")
                        }
                    };
                }

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

                ILLocalVariable vNativeFunctionPointer = emitter.NewLocal(context
                                                                          .GetWellKnownType(WellKnownType.IntPtr));

                fnptrLoadStream.EmitStLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.EmitLdLoc(vNativeFunctionPointer);
                callsiteSetupCodeStream.Emit(ILOpcode.calli, emitter.NewToken(nativeSig));
            }
            else
            {
                // Eager call
                MethodSignature nativeSig = new MethodSignature(
                    _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes);

                MethodDesc nativeMethod =
                    new PInvokeTargetNativeMethod(_targetMethod, nativeSig);

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

            if (!_flags.PreserveSig)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetMarshal(context)
                                                 .GetKnownMethod("ThrowExceptionForHR", null)));
            }

            // if the SetLastError flag is set in DllImport, call the PInvokeMarshal.SaveLastError
            // so that last error can be used later by calling Marshal.GetLastPInvokeError
            if (_flags.SetLastError)
            {
                callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
                                                 InteropTypes.GetPInvokeMarshal(context)
                                                 .GetKnownMethod("SaveLastError", null)));
            }
        }
コード例 #5
0
 public MethodDesc GetPInvokeCalliStub(MethodSignature signature, ModuleDesc moduleContext)
 {
     return(_pInvokeCalliHashtable.GetOrCreateValue(new CalliMarshallingMethodThunkKey(signature, MarshalHelpers.IsRuntimeMarshallingEnabled(moduleContext))));
 }
コード例 #6
0
        public MethodDesc GetPInvokeCalliStub(MethodSignature signature, ModuleDesc moduleContext)
        {
            // Normalize calling convention details on the signature
            var normalizedSignatureBuilder = new MethodSignatureBuilder(signature);

            normalizedSignatureBuilder.Flags = (signature.Flags & MethodSignatureFlags.Static) | MethodSignatureFlags.UnmanagedCallingConvention;
            normalizedSignatureBuilder.SetEmbeddedSignatureData(signature.GetStandaloneMethodSignatureCallingConventions().EncodeAsEmbeddedSignatureData(moduleContext.Context));
            return(_pInvokeCalliHashtable.GetOrCreateValue(new CalliMarshallingMethodThunkKey(normalizedSignatureBuilder.ToSignature(), MarshalHelpers.IsRuntimeMarshallingEnabled(moduleContext))));
        }