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); } // 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))); } // make the call DelegateMarshallingMethodThunk delegateMethod = _targetMethod as DelegateMarshallingMethodThunk; if (delegateMethod != null) { EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); } else { 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; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { MetadataType lazyHelperType = _targetMethod.Context.GetHelperType("InteropHelpers"); FieldDesc lazyDispatchCell = new PInvokeLazyFixupField(_targetMethod); fnptrLoadStream.Emit(ILOpcode.ldsflda, emitter.NewToken(lazyDispatchCell)); fnptrLoadStream.Emit(ILOpcode.call, emitter.NewToken(lazyHelperType .GetKnownMethod("ResolvePInvoke", null))); MethodSignatureFlags unmanagedCallConv = _importMetadata.Flags.UnmanagedCallingConvention; MethodSignature 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 MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod, nativeSig); 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())); }
private void EmitPInvokeCall(PInvokeILCodeStreams ilCodeStreams) { ILEmitter emitter = ilCodeStreams.Emitter; ILCodeStream fnptrLoadStream = ilCodeStreams.FunctionPointerLoadStream; ILCodeStream callsiteSetupCodeStream = ilCodeStreams.CallsiteSetupCodeStream; TypeSystemContext context = _targetMethod.Context; TypeDesc nativeReturnType = _marshallers[0].NativeParameterType; TypeDesc[] nativeParameterTypes = new TypeDesc[_marshallers.Length - 1]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context).GetKnownMethod("ClearLastWin32Error", null))); } for (int i = 1; i < _marshallers.Length; i++) { nativeParameterTypes[i - 1] = _marshallers[i].NativeParameterType; } if (MarshalHelpers.UseLazyResolution(_targetMethod, _importMetadata.Module, _pInvokeILEmitterConfiguration)) { 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 unmanagedCallConv = _flags.UnmanagedCallingConvention; MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags | unmanagedCallConv, 0, nativeReturnType, nativeParameterTypes); 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 the SetLastError flag is set in DllImport, call the PInvokeMarshal. // SaveLastWin32Error so that last error can be used later by calling // PInvokeMarshal.GetLastWin32Error if (_flags.SetLastError) { callsiteSetupCodeStream.Emit(ILOpcode.call, emitter.NewToken( InteropTypes.GetPInvokeMarshal(context) .GetKnownMethod("SaveLastWin32Error", null))); } }
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]; // if the SetLastError flag is set in DllImport, clear the error code before doing P/Invoke if (_flags.SetLastError) { 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) { 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))); } }
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(); _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); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); _unmarshallingCodestream.Emit(ILOpcode.ret); return _emitter.Link(); }
public MethodIL EmitIL() { MethodSignature targetMethodSignature = _targetMethod.Signature; // We have two code streams - one is used to convert each argument into a native type // and store that into the local. The other is used to load each previously generated local // and call the actual target native method. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); _returnValueMarshallingCodeStream = _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 TypeDesc parameterType = targetMethodSignature[i]; _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType; if (parameterType.IsSzArray) { nativeType = EmitArrayMarshalling((ArrayType)parameterType); } else if (parameterType.IsByRef) { nativeType = EmitByRefMarshalling((ByRefType)parameterType); } else if (parameterType.IsString) { nativeType = EmitStringMarshalling(); } else if (parameterType.Category == TypeFlags.Boolean) { nativeType = EmitBooleanMarshalling(); } else { if (!IsBlittableType(parameterType)) throw new NotSupportedException(); nativeType = parameterType.UnderlyingType; } 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 returnType = targetMethodSignature.ReturnType; TypeDesc nativeReturnType; if (returnType.IsVoid) { nativeReturnType = returnType; } else if (returnType.Category == TypeFlags.Boolean) { nativeReturnType = EmitBooleanReturnValueMarshalling(); } else { if (!IsBlittableType(returnType)) throw new NotSupportedException(); nativeReturnType = returnType; } MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); callsiteSetupCodeStream.Emit(ILOpcode.ret); return _emitter.Link(); }
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(); _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); MethodSignature nativeSig = new MethodSignature( targetMethodSignature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); _unmarshallingCodestream.Emit(ILOpcode.ret); return(_emitter.Link()); }
public MethodIL EmitIL() { // We have two code streams - one is used to convert each argument into a native type // and store that into the local. The other is used to load each previously generated local // and call the actual target native method. _emitter = new ILEmitter(); _marshallingCodeStream = _emitter.NewCodeStream(); ILCodeStream callsiteSetupCodeStream = _emitter.NewCodeStream(); // TODO: throw if SetLastError is true // TODO: throw if there's custom marshalling TypeDesc nativeReturnType = _targetMethod.Signature.ReturnType; if (!IsSimpleType(nativeReturnType) && !nativeReturnType.IsVoid) { throw new NotSupportedException(); } TypeDesc[] nativeParameterTypes = new TypeDesc[_targetMethod.Signature.Length]; // // 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 < _targetMethod.Signature.Length; i++) { // TODO: throw if there's custom marshalling TypeDesc parameterType = _targetMethod.Signature[i]; _marshallingCodeStream.EmitLdArg(i); TypeDesc nativeType; if (parameterType.IsSzArray) { nativeType = EmitArrayMarshalling((ArrayType)parameterType); } else if (parameterType.IsByRef) { nativeType = EmitByRefMarshalling((ByRefType)parameterType); } else if (parameterType.IsString) { nativeType = EmitStringMarshalling(); } else { if (!IsSimpleType(parameterType)) { throw new NotSupportedException(); } nativeType = parameterType; } nativeParameterTypes[i] = nativeType; int vMarshalledTypeTemp = _emitter.NewLocal(nativeType); _marshallingCodeStream.EmitStLoc(vMarshalledTypeTemp); callsiteSetupCodeStream.EmitLdLoc(vMarshalledTypeTemp); } MethodSignature nativeSig = new MethodSignature( _targetMethod.Signature.Flags, 0, nativeReturnType, nativeParameterTypes); MethodDesc nativeMethod = new PInvokeTargetNativeMethod(_targetMethod.OwningType, nativeSig, _importMetadata); // Call the native method callsiteSetupCodeStream.Emit(ILOpcode.call, _emitter.NewToken(nativeMethod)); callsiteSetupCodeStream.Emit(ILOpcode.ret); return(_emitter.Link()); }
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); }
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)); }
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)); }
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())); }
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)); }
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))); MethodSignature nativeSig = new MethodSignature( MethodSignatureFlags.Static | MethodSignatureFlags.UnmanagedCallingConvention, 0, nativeReturnType, nativeParameterTypes, _targetMethod.GetPInvokeMethodCallingConventions().EncodeAsEmbeddedSignatureData(context)); 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))); } }