From e013c10a30b400a9ef690293d1f40ca1b3a623e2 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Mon, 6 Mar 2023 10:26:08 +0100 Subject: [PATCH] Add support for function pointers to BlockLiteral. (#17672) Add support for function pointers to BlockLiteral, and use it to update almost all manually bound block code to use function pointers (in .NET). Also add support to the linker for optimizing the new block API. Contributes towards https://github.com/xamarin/xamarin-macios/issues/15783. --- src/AddressBook/ABAddressBook.cs | 9 + src/AudioUnit/AudioComponent.cs | 9 + src/CoreFoundation/DispatchIO.cs | 14 ++ src/CoreGraphics/CGPDFArray.cs | 9 + src/CoreText/CTFontManager.cs | 40 ++++ src/CoreText/CTLine.cs | 11 + src/ImageIO/CGImageAnimation.cs | 16 ++ src/ImageIO/CGImageMetadata.cs | 11 + src/Metal/MTLDevice.cs | 9 + src/Network/NWBrowseResult.cs | 9 + src/Network/NWBrowser.cs | 18 ++ src/Network/NWConnection.cs | 94 +++++++++ src/Network/NWConnectionGroup.cs | 36 ++++ src/Network/NWContentContext.cs | 9 + src/Network/NWDataTransferReport.cs | 9 + src/Network/NWEstablishmentReport.cs | 27 +++ src/Network/NWEthernetChannel.cs | 28 ++- src/Network/NWFramer.cs | 63 ++++++ src/Network/NWFramerMessage.cs | 18 ++ src/Network/NWListener.cs | 38 ++++ src/Network/NWMulticastGroup.cs | 9 + src/Network/NWParameters.cs | 27 +++ src/Network/NWPath.cs | 18 ++ src/Network/NWPathMonitor.cs | 9 + src/Network/NWProtocolDefinition.cs | 9 + src/Network/NWProtocolStack.cs | 9 + src/Network/NWTxtRecord.cs | 33 +++ src/Network/NWWebSocketMetadata.cs | 9 + src/Network/NWWebSocketOptions.cs | 9 + src/Network/NWWebSocketRequest.cs | 18 ++ src/Network/NWWebSocketResponse.cs | 9 + src/ObjCRuntime/Blocks.cs | 191 +++++++++++++++-- src/Security/SecIdentity2.cs | 9 + src/Security/SecProtocolMetadata.cs | 45 ++++ src/Security/SecSharedCredential.cs | 27 ++- src/Security/SecTrust.cs | 18 ++ src/UIKit/UIAccessibility.cs | 9 + src/UIKit/UICellAccessory.cs | 4 + src/UIKit/UIConfigurationColorTransformer.cs | 4 + src/UIKit/UIGuidedAccessRestriction.cs | 15 +- tools/common/Driver.cs | 2 +- tools/common/Optimizations.cs | 2 +- tools/linker/CoreOptimizeGeneratedCode.cs | 204 ++++++++++++++++++- tools/linker/RegistrarRemovalTrackingStep.cs | 32 ++- tools/mtouch/Errors.designer.cs | 108 ++++++++++ tools/mtouch/Errors.resx | 49 +++++ 46 files changed, 1321 insertions(+), 34 deletions(-) diff --git a/src/AddressBook/ABAddressBook.cs b/src/AddressBook/ABAddressBook.cs index 390bfe51824a..80f8be5ea255 100644 --- a/src/AddressBook/ABAddressBook.cs +++ b/src/AddressBook/ABAddressBook.cs @@ -194,15 +194,24 @@ public void RequestAccess (Action onCompleted) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (onCompleted)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineCompletionHandler; + using var block = new BlockLiteral (trampoline, onCompleted, typeof (ABAddressBook), nameof (TrampolineCompletionHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_completionHandler, onCompleted); +#endif ABAddressBookRequestAccessWithCompletion (Handle, &block); } } +#if !NET internal delegate void InnerCompleted (IntPtr block, byte success, IntPtr error); static readonly InnerCompleted static_completionHandler = TrampolineCompletionHandler; [MonoPInvokeCallback (typeof (InnerCompleted))] +#else + [UnmanagedCallersOnly] +#endif static unsafe void TrampolineCompletionHandler (IntPtr block, byte success, IntPtr error) { var descriptor = (BlockLiteral*) block; diff --git a/src/AudioUnit/AudioComponent.cs b/src/AudioUnit/AudioComponent.cs index ad505387784d..09849e646e31 100644 --- a/src/AudioUnit/AudioComponent.cs +++ b/src/AudioUnit/AudioComponent.cs @@ -584,11 +584,15 @@ public AudioComponentValidationResult Validate (NSDictionary? validationParamete #endif public AudioComponentValidationResult Validate (NSDictionary? validationParameters = null) => Validate (validationParameters, out var _); +#if !NET delegate void TrampolineCallback (IntPtr blockPtr, AudioComponentValidationResult result, IntPtr dictionary); static unsafe readonly TrampolineCallback static_action = TrampolineAction; [MonoPInvokeCallback (typeof (TrampolineCallback))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineAction (IntPtr blockPtr, AudioComponentValidationResult result, IntPtr dictionary) { var del = BlockLiteral.GetTarget> (blockPtr); @@ -628,8 +632,13 @@ public void ValidateAsync (NSDictionary? validationParameters, ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (onCompletion)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineAction; + using var block = new BlockLiteral (trampoline, onCompletion, typeof (AudioComponent), nameof (TrampolineAction)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_action, onCompletion); +#endif resultCode = AudioComponentValidateWithResults (GetCheckedHandle (), validationParameters.GetHandle (), &block); } } diff --git a/src/CoreFoundation/DispatchIO.cs b/src/CoreFoundation/DispatchIO.cs index 841394166e60..ec3c3b5ebc7e 100644 --- a/src/CoreFoundation/DispatchIO.cs +++ b/src/CoreFoundation/DispatchIO.cs @@ -67,10 +67,14 @@ internal DispatchIO (NativeHandle handle) : this (handle, false) } #endif +#if !NET delegate void DispatchReadWrite (IntPtr block, IntPtr dispatchData, int error); static DispatchReadWrite static_DispatchReadWriteHandler = Trampoline_DispatchReadWriteHandler; [MonoPInvokeCallback (typeof (DispatchReadWrite))] +#else + [UnmanagedCallersOnly] +#endif static void Trampoline_DispatchReadWriteHandler (IntPtr block, IntPtr dispatchData, int error) { var del = BlockLiteral.GetTarget (block); @@ -95,8 +99,13 @@ public static void Read (int fd, nuint size, DispatchQueue dispatchQueue, Dispat ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (dispatchQueue)); unsafe { +#if NET + delegate* unmanaged trampoline = &Trampoline_DispatchReadWriteHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (DispatchIO), nameof (Trampoline_DispatchReadWriteHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_DispatchReadWriteHandler, handler); +#endif dispatch_read (fd, size, dispatchQueue.Handle, &block); } } @@ -115,8 +124,13 @@ public static void Write (int fd, DispatchData dispatchData, DispatchQueue dispa ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (dispatchQueue)); unsafe { +#if NET + delegate* unmanaged trampoline = &Trampoline_DispatchReadWriteHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (DispatchIO), nameof (Trampoline_DispatchReadWriteHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_DispatchReadWriteHandler, handler); +#endif dispatch_write (fd, dispatchData.Handle, dispatchQueue.Handle, &block); } } diff --git a/src/CoreGraphics/CGPDFArray.cs b/src/CoreGraphics/CGPDFArray.cs index f222f192dace..9de311ac3083 100644 --- a/src/CoreGraphics/CGPDFArray.cs +++ b/src/CoreGraphics/CGPDFArray.cs @@ -218,11 +218,15 @@ public bool GetString (int idx, out string? result) } #endif +#if !NET delegate byte ApplyBlockHandlerDelegate (IntPtr block, nint index, IntPtr value, IntPtr info); static readonly ApplyBlockHandlerDelegate applyblock_handler = ApplyBlockHandler; #if !MONOMAC [MonoPInvokeCallback (typeof (ApplyBlockHandlerDelegate))] +#endif +#else + [UnmanagedCallersOnly] #endif static byte ApplyBlockHandler (IntPtr block, nint index, IntPtr value, IntPtr info) { @@ -270,8 +274,13 @@ public bool Apply (ApplyCallback callback, object? info = null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &ApplyBlockHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (CGPDFArray), nameof (ApplyBlockHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (applyblock_handler, callback); +#endif var gc_handle = info is null ? default (GCHandle) : GCHandle.Alloc (info); try { return CGPDFArrayApplyBlock (Handle, &block, info is null ? IntPtr.Zero : GCHandle.ToIntPtr (gc_handle)); diff --git a/src/CoreText/CTFontManager.cs b/src/CoreText/CTFontManager.cs index 71982633bafb..c8dc20b10bdf 100644 --- a/src/CoreText/CTFontManager.cs +++ b/src/CoreText/CTFontManager.cs @@ -232,10 +232,14 @@ static NSArray EnsureNonNullArray (object [] items, string name) #endif public delegate bool CTFontRegistrationHandler (NSError [] errors, bool done); +#if !NET internal delegate byte InnerRegistrationHandler (IntPtr block, IntPtr errors, byte done); static readonly InnerRegistrationHandler callback = TrampolineRegistrationHandler; [MonoPInvokeCallback (typeof (InnerRegistrationHandler))] +#else + [UnmanagedCallersOnly] +#endif static unsafe byte TrampolineRegistrationHandler (IntPtr block, /* NSArray */ IntPtr errors, byte done) { var del = BlockLiteral.GetTarget (block); @@ -281,8 +285,13 @@ public static void RegisterFonts (NSUrl [] fontUrls, CTFontManagerScope scope, b } } else { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineRegistrationHandler; + using var block = new BlockLiteral (trampoline, registrationHandler, typeof (CTFontManager), nameof (TrampolineRegistrationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (callback, registrationHandler); +#endif CTFontManagerRegisterFontURLs (arr.Handle, scope, enabled, &block); } } @@ -385,8 +394,13 @@ public unsafe static void UnregisterFonts (NSUrl [] fontUrls, CTFontManagerScope if (registrationHandler is null) { CTFontManagerUnregisterFontURLs (arr.Handle, scope, null); } else { +#if NET + delegate* unmanaged trampoline = &TrampolineRegistrationHandler; + using var block = new BlockLiteral (trampoline, registrationHandler, typeof (CTFontManager), nameof (TrampolineRegistrationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (callback, registrationHandler); +#endif CTFontManagerUnregisterFontURLs (arr.Handle, scope, &block); } } @@ -548,8 +562,13 @@ public unsafe static void RegisterFontDescriptors (CTFontDescriptor [] fontDescr if (registrationHandler is null) { CTFontManagerRegisterFontDescriptors (arr.Handle, scope, enabled, null); } else { +#if NET + delegate* unmanaged trampoline = &TrampolineRegistrationHandler; + using var block = new BlockLiteral (trampoline, registrationHandler, typeof (CTFontManager), nameof (TrampolineRegistrationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (callback, registrationHandler); +#endif CTFontManagerRegisterFontDescriptors (arr.Handle, scope, enabled, &block); } } @@ -587,8 +606,13 @@ public unsafe static void UnregisterFontDescriptors (CTFontDescriptor [] fontDes if (registrationHandler is null) { CTFontManagerUnregisterFontDescriptors (arr.Handle, scope, null); } else { +#if NET + delegate* unmanaged trampoline = &TrampolineRegistrationHandler; + using var block = new BlockLiteral (trampoline, registrationHandler, typeof (CTFontManager), nameof (TrampolineRegistrationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (callback, registrationHandler); +#endif CTFontManagerUnregisterFontDescriptors (arr.Handle, scope, &block); } } @@ -709,8 +733,13 @@ public unsafe static void RegisterFonts (string[] assetNames, CFBundle bundle, C if (registrationHandler is null) { CTFontManagerRegisterFontsWithAssetNames (arr.Handle, bundle.GetHandle (), scope, enabled, null); } else { +#if NET + delegate* unmanaged trampoline = &TrampolineRegistrationHandler; + using var block = new BlockLiteral (trampoline, registrationHandler, typeof (CTFontManager), nameof (TrampolineRegistrationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (callback, registrationHandler); +#endif CTFontManagerRegisterFontsWithAssetNames (arr.Handle, bundle.GetHandle (), scope, enabled, &block); } } @@ -743,10 +772,16 @@ public unsafe static void RegisterFonts (string[] assetNames, CFBundle bundle, C [DllImport (Constants.CoreTextLibrary)] static extern unsafe void CTFontManagerRequestFonts (/* CFArrayRef */ IntPtr fontDescriptors, BlockLiteral* completionHandler); +#if !NET internal delegate void InnerRequestFontsHandler (IntPtr block, IntPtr fontDescriptors); static readonly InnerRequestFontsHandler requestCallback = TrampolineRequestFonts; +#endif +#if NET + [UnmanagedCallersOnly] +#else [MonoPInvokeCallback (typeof (InnerRequestFontsHandler))] +#endif static unsafe void TrampolineRequestFonts (IntPtr block, /* CFArray */ IntPtr fontDescriptors) { var del = BlockLiteral.GetTarget (block); @@ -773,8 +808,13 @@ public static void RequestFonts (CTFontDescriptor[] fontDescriptors, CTFontManag using (var arr = EnsureNonNullArray (fontDescriptors, nameof (fontDescriptors))) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineRequestFonts; + using var block = new BlockLiteral (trampoline, completionHandler, typeof (CTFontManager), nameof (TrampolineRequestFonts)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (requestCallback, completionHandler); +#endif CTFontManagerRequestFonts (arr.Handle, &block); } } diff --git a/src/CoreText/CTLine.cs b/src/CoreText/CTLine.cs index 5f3d7abe2300..6c654d18d043 100644 --- a/src/CoreText/CTLine.cs +++ b/src/CoreText/CTLine.cs @@ -208,7 +208,9 @@ public nfloat GetOffsetForStringIndex (nint charIndex) } public delegate void CaretEdgeEnumerator (double offset, nint charIndex, bool leadingEdge, ref bool stop); +#if !NET unsafe delegate void CaretEdgeEnumeratorProxy (IntPtr block, double offset, nint charIndex, byte leadingEdge, byte* stop); +#endif #if NET [SupportedOSPlatform ("ios9.0")] @@ -222,9 +224,13 @@ public nfloat GetOffsetForStringIndex (nint charIndex) [DllImport (Constants.CoreTextLibrary)] unsafe static extern void CTLineEnumerateCaretOffsets (IntPtr line, BlockLiteral* blockEnumerator); +#if !NET static unsafe readonly CaretEdgeEnumeratorProxy static_enumerate = TrampolineEnumerate; [MonoPInvokeCallback (typeof (CaretEdgeEnumeratorProxy))] +#else + [UnmanagedCallersOnly] +#endif unsafe static void TrampolineEnumerate (IntPtr blockPtr, double offset, nint charIndex, byte leadingEdge, byte* stopPointer) { var del = BlockLiteral.GetTarget (blockPtr); @@ -251,8 +257,13 @@ public void EnumerateCaretOffsets (CaretEdgeEnumerator enumerator) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (enumerator)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerate; + using var block = new BlockLiteral (trampoline, enumerator, typeof (CTLine), nameof (TrampolineEnumerate)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_enumerate, enumerator); +#endif CTLineEnumerateCaretOffsets (Handle, &block); } } diff --git a/src/ImageIO/CGImageAnimation.cs b/src/ImageIO/CGImageAnimation.cs index fc139868258f..9e0dcd0a6c7a 100644 --- a/src/ImageIO/CGImageAnimation.cs +++ b/src/ImageIO/CGImageAnimation.cs @@ -79,8 +79,13 @@ public static CGImageAnimationStatus AnimateImage (NSUrl url, CGImageAnimationOp ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &SDCGImageSourceAnimationBlock.Invoke; + using var block = new BlockLiteral (trampoline, handler, typeof (SDCGImageSourceAnimationBlock), nameof (SDCGImageSourceAnimationBlock.Invoke)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (SDCGImageSourceAnimationBlock.Handler, handler); +#endif return CGAnimateImageAtURLWithBlock (url.Handle, options.GetHandle (), &block); } #endif @@ -109,8 +114,13 @@ public static CGImageAnimationStatus AnimateImage (NSData data, CGImageAnimation ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &SDCGImageSourceAnimationBlock.Invoke; + using var block = new BlockLiteral (trampoline, handler, typeof (SDCGImageSourceAnimationBlock), nameof (SDCGImageSourceAnimationBlock.Invoke)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (SDCGImageSourceAnimationBlock.Handler, handler); +#endif return CGAnimateImageDataWithBlock (data.Handle, options.GetHandle (), &block); } #endif @@ -120,9 +130,13 @@ public static CGImageAnimationStatus AnimateImage (NSData data, CGImageAnimation // This class bridges native block invocations that call into C# // static internal class SDCGImageSourceAnimationBlock { +#if !NET unsafe static internal readonly DCGImageSourceAnimationBlock Handler = Invoke; [MonoPInvokeCallback (typeof (DCGImageSourceAnimationBlock))] +#else + [UnmanagedCallersOnly] +#endif internal unsafe static void Invoke (IntPtr block, nint index, IntPtr image, byte* stop) { var del = BlockLiteral.GetTarget (block); @@ -134,9 +148,11 @@ internal unsafe static void Invoke (IntPtr block, nint index, IntPtr image, byte } } /* class SDCGImageSourceAnimationBlock */ +#if !NET [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)] [UserDelegateType (typeof (CGImageSourceAnimationHandler))] unsafe internal delegate void DCGImageSourceAnimationBlock (IntPtr block, nint index, IntPtr imageHandle, byte* stop); +#endif } } diff --git a/src/ImageIO/CGImageMetadata.cs b/src/ImageIO/CGImageMetadata.cs index 9f336756a8bc..1116d5b5f84e 100644 --- a/src/ImageIO/CGImageMetadata.cs +++ b/src/ImageIO/CGImageMetadata.cs @@ -122,9 +122,13 @@ public CGImageMetadata (NSData data) extern unsafe static void CGImageMetadataEnumerateTagsUsingBlock (/* CGImageMetadataRef __nonnull */ IntPtr metadata, /* CFStringRef __nullable */ IntPtr rootPath, /* CFDictionaryRef __nullable */ IntPtr options, BlockLiteral* block); +#if !NET delegate byte TrampolineCallback (IntPtr blockPtr, NativeHandle key, NativeHandle value); [MonoPInvokeCallback (typeof (TrampolineCallback))] +#else + [UnmanagedCallersOnly] +#endif static byte TagEnumerator (IntPtr block, NativeHandle key, NativeHandle value) { var nsKey = Runtime.GetNSObject (key, false)!; @@ -133,15 +137,22 @@ static byte TagEnumerator (IntPtr block, NativeHandle key, NativeHandle value) return del (nsKey, nsValue) ? (byte) 1 : (byte) 0; } +#if !NET static unsafe readonly TrampolineCallback static_action = TagEnumerator; +#endif [BindingImpl (BindingImplOptions.Optimizable)] public void EnumerateTags (NSString? rootPath, CGImageMetadataEnumerateOptions? options, CGImageMetadataTagBlock block) { using var o = options?.ToDictionary (); unsafe { +#if NET + delegate* unmanaged trampoline = &TagEnumerator; + using var block_handler = new BlockLiteral (trampoline, block, typeof (CGImageMetadata), nameof (TagEnumerator)); +#else using var block_handler = new BlockLiteral (); block_handler.SetupBlockUnsafe (static_action, block); +#endif CGImageMetadataEnumerateTagsUsingBlock (Handle, rootPath.GetHandle (), o.GetHandle (), &block_handler); } } diff --git a/src/Metal/MTLDevice.cs b/src/Metal/MTLDevice.cs index a75f4761f467..ea1a900b2c7d 100644 --- a/src/Metal/MTLDevice.cs +++ b/src/Metal/MTLDevice.cs @@ -117,8 +117,13 @@ public static IMTLDevice [] GetAllDevices (MTLDeviceNotificationHandler handler, IntPtr observer_handle; unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineNotificationHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (MTLDevice), nameof (TrampolineNotificationHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_notificationHandler, handler); +#endif rv = MTLCopyAllDevicesWithObserver (out observer_handle, &block); } @@ -144,9 +149,13 @@ public static IMTLDevice [] GetAllDevices (ref NSObject? observer, MTLDeviceNoti } #endif // !NET +#if !NET internal delegate void InnerNotification (IntPtr block, IntPtr device, IntPtr notifyName); static readonly InnerNotification static_notificationHandler = TrampolineNotificationHandler; [MonoPInvokeCallback (typeof (InnerNotification))] +#else + [UnmanagedCallersOnly] +#endif public static unsafe void TrampolineNotificationHandler (IntPtr block, IntPtr device, IntPtr notifyName) { var descriptor = (BlockLiteral*) block; diff --git a/src/Network/NWBrowseResult.cs b/src/Network/NWBrowseResult.cs index 1fc9f9eedbbe..97b0f90c4e40 100644 --- a/src/Network/NWBrowseResult.cs +++ b/src/Network/NWBrowseResult.cs @@ -65,10 +65,14 @@ public static NWBrowseResultChange GetChanges (NWBrowseResult? oldResult, NWBrow [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_browse_result_enumerate_interfaces (OS_nw_browse_result result, BlockLiteral* enumerator); +#if !NET delegate void nw_browse_result_enumerate_interfaces_t (IntPtr block, IntPtr nwInterface); static nw_browse_result_enumerate_interfaces_t static_EnumerateInterfacesHandler = TrampolineEnumerateInterfacesHandler; [MonoPInvokeCallback (typeof (nw_browse_result_enumerate_interfaces_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEnumerateInterfacesHandler (IntPtr block, IntPtr inter) { var del = BlockLiteral.GetTarget> (block); @@ -85,8 +89,13 @@ public void EnumerateInterfaces (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateInterfacesHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWBrowseResult), nameof (TrampolineEnumerateInterfacesHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateInterfacesHandler, handler); +#endif nw_browse_result_enumerate_interfaces (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWBrowser.cs b/src/Network/NWBrowser.cs index 210d137ade65..508637bc72f9 100644 --- a/src/Network/NWBrowser.cs +++ b/src/Network/NWBrowser.cs @@ -131,10 +131,14 @@ public NWParameters Parameters [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_browser_set_browse_results_changed_handler (OS_nw_browser browser, BlockLiteral* handler); +#if !NET delegate void nw_browser_browse_results_changed_handler_t (IntPtr block, IntPtr oldResult, IntPtr newResult, byte completed); static nw_browser_browse_results_changed_handler_t static_ChangesHandler = TrampolineChangesHandler; [MonoPInvokeCallback (typeof (nw_browser_browse_results_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineChangesHandler (IntPtr block, IntPtr oldResult, IntPtr newResult, byte completed) { var del = BlockLiteral.GetTarget (block); @@ -199,8 +203,13 @@ void SetChangesHandler (NWBrowserChangesDelegate? handler) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineChangesHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWBrowser), nameof (TrampolineChangesHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ChangesHandler, handler); +#endif nw_browser_set_browse_results_changed_handler (GetCheckedHandle (), &block); } } @@ -214,10 +223,14 @@ void SetChangesHandler (NWBrowserChangesDelegate? handler) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_browser_set_state_changed_handler (OS_nw_browser browser, BlockLiteral* state_changed_handler); +#if !NET delegate void nw_browser_set_state_changed_handler_t (IntPtr block, NWBrowserState state, IntPtr error); static nw_browser_set_state_changed_handler_t static_StateChangesHandler = TrampolineStateChangesHandler; [MonoPInvokeCallback (typeof (nw_browser_set_state_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineStateChangesHandler (IntPtr block, NWBrowserState state, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -235,8 +248,13 @@ public void SetStateChangesHandler (Action handler) nw_browser_set_state_changed_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineStateChangesHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWBrowser), nameof (TrampolineStateChangesHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_StateChangesHandler, handler); +#endif nw_browser_set_state_changed_handler (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWConnection.cs b/src/Network/NWConnection.cs index 14322ee8c2df..7017375c3b0e 100644 --- a/src/Network/NWConnection.cs +++ b/src/Network/NWConnection.cs @@ -100,10 +100,14 @@ public NWParameters? Parameters { } } +#if !NET delegate void StateChangeCallback (IntPtr block, NWConnectionState state, IntPtr error); static StateChangeCallback static_stateChangeHandler = Trampoline_StateChangeCallback; [MonoPInvokeCallback (typeof (StateChangeCallback))] +#else + [UnmanagedCallersOnly] +#endif static void Trampoline_StateChangeCallback (IntPtr block, NWConnectionState state, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -125,16 +129,25 @@ public unsafe void SetStateChangeHandler (Action st } unsafe { +#if NET + delegate* unmanaged trampoline = &Trampoline_StateChangeCallback; + using var block = new BlockLiteral (trampoline, stateHandler, typeof (NWConnection), nameof (Trampoline_StateChangeCallback)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_stateChangeHandler, stateHandler); +#endif nw_connection_set_state_changed_handler (GetCheckedHandle (), &block); } } +#if !NET delegate void nw_connection_boolean_event_handler_t (IntPtr block, byte value); static nw_connection_boolean_event_handler_t static_BooleanChangeHandler = TrampolineBooleanChangeHandler; [MonoPInvokeCallback (typeof (nw_connection_boolean_event_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineBooleanChangeHandler (IntPtr block, byte value) { var del = BlockLiteral.GetTarget> (block); @@ -154,8 +167,13 @@ public unsafe void SetBooleanChangeHandler (Action callback) } unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineBooleanChangeHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineBooleanChangeHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_BooleanChangeHandler, callback); +#endif nw_connection_set_viability_changed_handler (GetCheckedHandle (), &block); } } @@ -172,16 +190,25 @@ public unsafe void SetBetterPathAvailableHandler (Action callback) } unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineBooleanChangeHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineBooleanChangeHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_BooleanChangeHandler, callback); +#endif nw_connection_set_better_path_available_handler (GetCheckedHandle (), &block); } } +#if !NET delegate void nw_connection_path_event_handler_t (IntPtr block, IntPtr path); static nw_connection_path_event_handler_t static_PathChanged = TrampolinePathChanged; [MonoPInvokeCallback (typeof (nw_connection_path_event_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolinePathChanged (IntPtr block, IntPtr path) { var del = BlockLiteral.GetTarget> (block); @@ -198,8 +225,13 @@ static void TrampolinePathChanged (IntPtr block, IntPtr path) public void SetPathChangedHandler (Action callback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolinePathChanged; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolinePathChanged)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_PathChanged, callback); +#endif nw_connection_set_path_changed_handler (GetCheckedHandle (), &block); } } @@ -239,6 +271,7 @@ public void SetQueue (DispatchQueue queue) public void CancelCurrentEndpoint () => nw_connection_cancel_current_endpoint (GetCheckedHandle ()); +#if !NET delegate void nw_connection_receive_completion_t (IntPtr block, IntPtr dispatchData, IntPtr contentContext, @@ -248,8 +281,13 @@ delegate void nw_connection_receive_completion_t (IntPtr block, static nw_connection_receive_completion_t static_ReceiveCompletion = TrampolineReceiveCompletion; static nw_connection_receive_completion_t static_ReceiveCompletionDispatchData = TrampolineReceiveCompletionData; static nw_connection_receive_completion_t static_ReceiveCompletionDispatchReadnOnlyData = TrampolineReceiveCompletionReadOnlyData; +#endif +#if !NET [MonoPInvokeCallback (typeof (nw_connection_receive_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineReceiveCompletion (IntPtr block, IntPtr dispatchDataPtr, IntPtr contentContext, byte isComplete, IntPtr error) { var del = BlockLiteral.GetTarget (block); @@ -276,7 +314,11 @@ static void TrampolineReceiveCompletion (IntPtr block, IntPtr dispatchDataPtr, I } } +#if !NET [MonoPInvokeCallback (typeof (nw_connection_receive_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineReceiveCompletionData (IntPtr block, IntPtr dispatchDataPtr, IntPtr contentContext, byte isComplete, IntPtr error) { var del = BlockLiteral.GetTarget (block); @@ -297,7 +339,11 @@ static void TrampolineReceiveCompletionData (IntPtr block, IntPtr dispatchDataPt } } +#if !NET [MonoPInvokeCallback (typeof (nw_connection_receive_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineReceiveCompletionReadOnlyData (IntPtr block, IntPtr dispatchDataPtr, IntPtr contentContext, byte isComplete, IntPtr error) { var del = BlockLiteral.GetTarget (block); @@ -326,8 +372,13 @@ public void Receive (uint minimumIncompleteLength, uint maximumLength, NWConnect ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletion; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletion)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletion, callback); +#endif nw_connection_receive (GetCheckedHandle (), minimumIncompleteLength, maximumLength, &block); } } @@ -339,8 +390,13 @@ public void ReceiveData (uint minimumIncompleteLength, uint maximumLength, NWCon ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletionData; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletionData)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletionDispatchData, callback); +#endif nw_connection_receive (GetCheckedHandle (), minimumIncompleteLength, maximumLength, &block); } } @@ -352,8 +408,13 @@ public void ReceiveReadOnlyData (uint minimumIncompleteLength, uint maximumLengt ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletionReadOnlyData; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletionReadOnlyData)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletionDispatchReadnOnlyData, callback); +#endif nw_connection_receive (GetCheckedHandle (), minimumIncompleteLength, maximumLength, &block); } } @@ -368,8 +429,13 @@ public void ReceiveMessage (NWConnectionReceiveCompletion callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletion; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletion)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletion, callback); +#endif nw_connection_receive_message (GetCheckedHandle (), &block); } @@ -382,8 +448,13 @@ public void ReceiveMessageData (NWConnectionReceiveDispatchDataCompletion callba ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletionData; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletionData)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletionDispatchData, callback); +#endif nw_connection_receive_message (GetCheckedHandle (), &block); } } @@ -395,16 +466,25 @@ public void ReceiveMessageReadOnlyData (NWConnectionReceiveReadOnlySpanCompletio ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveCompletionReadOnlyData; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineReceiveCompletionReadOnlyData)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveCompletionDispatchReadnOnlyData, callback); +#endif nw_connection_receive_message (GetCheckedHandle (), &block); } } +#if !NET delegate void nw_connection_send_completion_t (IntPtr block, IntPtr error); static nw_connection_send_completion_t static_SendCompletion = TrampolineSendCompletion; [MonoPInvokeCallback (typeof (nw_connection_send_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSendCompletion (IntPtr block, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -463,8 +543,13 @@ public void Send (DispatchData? buffer, NWContentContext context, bool isComplet ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineSendCompletion; + using var block = new BlockLiteral (trampoline, callback, typeof (NWConnection), nameof (TrampolineSendCompletion)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_SendCompletion, callback); +#endif LowLevelSend (GetCheckedHandle (), buffer, context.Handle, isComplete, &block); } } @@ -561,10 +646,14 @@ public void Batch (Action method) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_connection_access_establishment_report (IntPtr connection, IntPtr queue, BlockLiteral* access_block); +#if !NET delegate void nw_establishment_report_access_block_t (IntPtr block, nw_establishment_report_t report); static nw_establishment_report_access_block_t static_GetEstablishmentReportHandler = TrampolineGetEstablishmentReportHandler; [MonoPInvokeCallback (typeof (nw_establishment_report_access_block_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineGetEstablishmentReportHandler (IntPtr block, nw_establishment_report_t report) { var del = BlockLiteral.GetTarget> (block); @@ -594,8 +683,13 @@ public void GetEstablishmentReport (DispatchQueue queue, Action trampoline = &TrampolineGetEstablishmentReportHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWConnection), nameof (TrampolineGetEstablishmentReportHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_GetEstablishmentReportHandler, handler); +#endif nw_connection_access_establishment_report (GetCheckedHandle (), queue.Handle, &block); } } diff --git a/src/Network/NWConnectionGroup.cs b/src/Network/NWConnectionGroup.cs index 84104a4deb6e..9491ec966591 100644 --- a/src/Network/NWConnectionGroup.cs +++ b/src/Network/NWConnectionGroup.cs @@ -188,10 +188,14 @@ public void Reply (NWContentContext inboundMessage, NWContentContext outboundMes [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_connection_group_send_message (OS_nw_connection_group group, /* [NullAllowed] DispatchData */ IntPtr content, /* [NullAllowed] */ OS_nw_endpoint endpoint, OS_nw_content_context context, BlockLiteral* handler); +#if !NET delegate void nw_connection_group_send_completion_t (IntPtr block, IntPtr error); static nw_connection_group_send_completion_t static_SendCompletion = TrampolineSendCompletion; [MonoPInvokeCallback (typeof (nw_connection_group_send_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSendCompletion (IntPtr block, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -214,8 +218,13 @@ public void Send (DispatchData? content, NWEndpoint? endpoint, NWContentContext return; } +#if NET + delegate* unmanaged trampoline = &TrampolineSendCompletion; + using var block = new BlockLiteral (trampoline, handler, typeof (NWConnectionGroup), nameof (TrampolineSendCompletion)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_SendCompletion, handler); +#endif nw_connection_group_send_message (GetCheckedHandle (), content.GetHandle (), endpoint.GetHandle (), @@ -227,10 +236,14 @@ public void Send (DispatchData? content, NWEndpoint? endpoint, NWContentContext [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_connection_group_set_receive_handler (OS_nw_connection_group group, uint maximum_message_size, [MarshalAs (UnmanagedType.I1)] bool reject_oversized_messages, BlockLiteral* handler); +#if !NET delegate void nw_connection_group_receive_handler_t (IntPtr block, IntPtr content, IntPtr context, byte isCompleted); static nw_connection_group_receive_handler_t static_ReceiveHandler = TrampolineReceiveHandler; [MonoPInvokeCallback (typeof (nw_connection_group_receive_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineReceiveHandler (IntPtr block, IntPtr content, IntPtr context, byte isCompleted) { var del = BlockLiteral.GetTarget (block); @@ -250,8 +263,13 @@ public void SetReceiveHandler (uint maximumMessageSize, bool rejectOversizedMess return; } +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWConnectionGroup), nameof (TrampolineReceiveHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveHandler, handler); +#endif nw_connection_group_set_receive_handler (GetCheckedHandle (), maximumMessageSize, rejectOversizedMessages, &block); } } @@ -259,10 +277,14 @@ public void SetReceiveHandler (uint maximumMessageSize, bool rejectOversizedMess [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_connection_group_set_state_changed_handler (OS_nw_connection_group group, BlockLiteral* handler); +#if !NET delegate void nw_connection_group_state_changed_handler_t (IntPtr block, NWConnectionGroupState state, IntPtr error); static nw_connection_group_state_changed_handler_t static_StateChangedHandler = TrampolineStateChangedHandler; [MonoPInvokeCallback (typeof (nw_connection_group_state_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineStateChangedHandler (IntPtr block, NWConnectionGroupState state, IntPtr error) { var del = BlockLiteral.GetTarget (block); @@ -281,8 +303,13 @@ public void SetStateChangedHandler (NWConnectionGroupStateChangedDelegate handle return; } +#if NET + delegate* unmanaged trampoline= &TrampolineStateChangedHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWConnectionGroup), nameof (TrampolineStateChangedHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_StateChangedHandler, handler); +#endif nw_connection_group_set_state_changed_handler (GetCheckedHandle (), &block); } } @@ -442,10 +469,14 @@ public bool TryReinsertExtractedConnection (NWConnection connection) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_connection_group_set_new_connection_handler (OS_nw_connection_group group, BlockLiteral* connectionHandler); +#if !NET delegate void nw_connection_group_new_connection_handler_t (IntPtr block, IntPtr connection); static nw_connection_group_new_connection_handler_t static_SetNewConnectionHandler = TrampolineSetNewConnectionHandler; [MonoPInvokeCallback (typeof (nw_connection_group_new_connection_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSetNewConnectionHandler (IntPtr block, IntPtr connection) { var del = BlockLiteral.GetTarget> (block); @@ -475,8 +506,13 @@ public void SetNewConnectionHandler (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineSetNewConnectionHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWConnectionGroup), nameof (TrampolineSetNewConnectionHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_SetNewConnectionHandler, handler); +#endif nw_connection_group_set_new_connection_handler (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWContentContext.cs b/src/Network/NWContentContext.cs index 6b7000ca5c60..a660df3ddbfb 100644 --- a/src/Network/NWContentContext.cs +++ b/src/Network/NWContentContext.cs @@ -166,10 +166,14 @@ public void SetMetadata (NWProtocolMetadata protocolMetadata) nw_content_context_set_metadata_for_protocol (GetCheckedHandle (), protocolMetadata.Handle); } +#if !NET delegate void ProtocolIterator (IntPtr block, IntPtr definition, IntPtr metadata); static ProtocolIterator static_ProtocolIterator = TrampolineProtocolIterator; [MonoPInvokeCallback (typeof (ProtocolIterator))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineProtocolIterator (IntPtr block, IntPtr definition, IntPtr metadata) { var del = BlockLiteral.GetTarget> (block); @@ -188,8 +192,13 @@ static void TrampolineProtocolIterator (IntPtr block, IntPtr definition, IntPtr public void IterateProtocolMetadata (Action callback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineProtocolIterator; + using var block = new BlockLiteral (trampoline, callback, typeof (NWContentContext), nameof (TrampolineProtocolIterator)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ProtocolIterator, callback); +#endif nw_content_context_foreach_protocol_metadata (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWDataTransferReport.cs b/src/Network/NWDataTransferReport.cs index 342052222c89..aeda63e02bea 100644 --- a/src/Network/NWDataTransferReport.cs +++ b/src/Network/NWDataTransferReport.cs @@ -146,10 +146,14 @@ public ulong GetTransportSentIPPackageCount (uint pathIndex) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_data_transfer_report_collect (OS_nw_data_transfer_report report, IntPtr queue, BlockLiteral* collect_block); +#if !NET delegate void nw_data_transfer_report_collect_t (IntPtr block, IntPtr report); static nw_data_transfer_report_collect_t static_CollectHandler = TrampolineCollectHandler; [MonoPInvokeCallback (typeof (nw_data_transfer_report_collect_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineCollectHandler (IntPtr block, IntPtr report) { var del = BlockLiteral.GetTarget> (block); @@ -168,8 +172,13 @@ public void Collect (DispatchQueue queue, Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineCollectHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWDataTransferReport), nameof (TrampolineCollectHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_CollectHandler, handler); +#endif nw_data_transfer_report_collect (GetCheckedHandle (), queue.Handle, &block); } } diff --git a/src/Network/NWEstablishmentReport.cs b/src/Network/NWEstablishmentReport.cs index 9e7e00e1485a..cfe5fc3be3b5 100644 --- a/src/Network/NWEstablishmentReport.cs +++ b/src/Network/NWEstablishmentReport.cs @@ -75,10 +75,14 @@ internal NWEstablishmentReport (NativeHandle handle, bool owns) : base (handle, [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_establishment_report_enumerate_resolutions (OS_nw_establishment_report report, BlockLiteral* enumerate_block); +#if !NET delegate void nw_report_resolution_enumerator_t (IntPtr block, NWReportResolutionSource source, nuint milliseconds, int endpoint_count, nw_endpoint_t successful_endpoint, nw_endpoint_t preferred_endpoint); static nw_report_resolution_enumerator_t static_ResolutionEnumeratorHandler = TrampolineResolutionEnumeratorHandler; [MonoPInvokeCallback (typeof (nw_report_resolution_enumerator_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineResolutionEnumeratorHandler (IntPtr block, NWReportResolutionSource source, nuint milliseconds, int endpoint_count, nw_endpoint_t successful_endpoint, nw_endpoint_t preferred_endpoint) { var del = BlockLiteral.GetTarget> (block); @@ -96,8 +100,13 @@ public void EnumerateResolutions (Action trampoline = &TrampolineResolutionEnumeratorHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWEstablishmentReport),nameof (TrampolineResolutionEnumeratorHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ResolutionEnumeratorHandler, handler); +#endif nw_establishment_report_enumerate_resolutions (GetCheckedHandle (), &block); } } @@ -105,10 +114,14 @@ public void EnumerateResolutions (Action> (block); @@ -125,8 +138,13 @@ public void EnumerateProtocols (Action ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateProtocolsHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWEstablishmentReport), nameof (TrampolineEnumerateProtocolsHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateProtocolsHandler, handler); +#endif nw_establishment_report_enumerate_protocols (GetCheckedHandle (), &block); } } @@ -156,10 +174,14 @@ public NWEndpoint? ProxyEndpoint { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_establishment_report_enumerate_resolution_reports (OS_nw_establishment_report report, BlockLiteral* enumerateBlock); +#if !NET delegate void nw_report_resolution_report_enumerator_t (IntPtr block, nw_resolution_report_t report); static nw_report_resolution_report_enumerator_t static_EnumerateResolutionReport = TrampolineEnumerateResolutionReport; [MonoPInvokeCallback (typeof (nw_report_resolution_report_enumerator_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEnumerateResolutionReport (IntPtr block, nw_resolution_report_t report) { var del = BlockLiteral.GetTarget> (block); @@ -188,8 +210,13 @@ public void EnumerateResolutionReports (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateResolutionReport; + using var block = new BlockLiteral (trampoline, handler, typeof (NWEstablishmentReport), nameof (TrampolineEnumerateResolutionReport)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateResolutionReport, handler); +#endif nw_establishment_report_enumerate_protocols (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWEthernetChannel.cs b/src/Network/NWEthernetChannel.cs index 11fd91061f3f..b80fc19f310e 100644 --- a/src/Network/NWEthernetChannel.cs +++ b/src/Network/NWEthernetChannel.cs @@ -124,10 +124,14 @@ public void SetQueue (DispatchQueue queue) unsafe static extern void nw_ethernet_channel_send (OS_nw_ethernet_channel ethernet_channel, OS_dispatch_data content, ushort vlan_tag, string remote_address, BlockLiteral* completion); #endif +#if !NET delegate void nw_ethernet_channel_send_completion_t (IntPtr block, IntPtr error); static nw_ethernet_channel_send_completion_t static_SendCompletion = TrampolineSendCompletion; [MonoPInvokeCallback (typeof (nw_ethernet_channel_send_completion_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSendCompletion (IntPtr block, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -145,12 +149,14 @@ public void Send (ReadOnlySpan content, ushort vlanTag, string remoteAddre using (var dispatchData = DispatchData.FromReadOnlySpan (content)) { unsafe { - using var block = new BlockLiteral (); - block.SetupBlockUnsafe (static_SendCompletion, callback); #if NET + delegate* unmanaged trampoline = &TrampolineSendCompletion; + using var block = new BlockLiteral (trampoline, callback, typeof (NWEthernetChannel), nameof (TrampolineSendCompletion)); var remoteAddressStr = new TransientString (remoteAddress); nw_ethernet_channel_send (GetCheckedHandle (), dispatchData.GetHandle (), vlanTag, remoteAddressStr, &block); #else + using var block = new BlockLiteral (); + block.SetupBlockUnsafe (static_SendCompletion, callback); nw_ethernet_channel_send (GetCheckedHandle (), dispatchData.GetHandle (), vlanTag, remoteAddress, &block); #endif } @@ -160,10 +166,14 @@ public void Send (ReadOnlySpan content, ushort vlanTag, string remoteAddre [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_ethernet_channel_set_receive_handler (OS_nw_ethernet_channel ethernet_channel, /* [NullAllowed] */ BlockLiteral *handler); +#if !NET delegate void nw_ethernet_channel_receive_handler_t (IntPtr block, OS_dispatch_data content, ushort vlan_tag, IntPtr local_address, IntPtr remote_address); static nw_ethernet_channel_receive_handler_t static_ReceiveHandler = TrampolineReceiveHandler; [MonoPInvokeCallback (typeof (nw_ethernet_channel_receive_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineReceiveHandler (IntPtr block, OS_dispatch_data content, ushort vlanTag, IntPtr localAddressArray, IntPtr remoteAddressArray) { // localAddress and remoteAddress are defined as: @@ -188,8 +198,13 @@ public void SetReceiveHandler (NWEthernetChannelReceiveDelegate handler) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineReceiveHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWEthernetChannel), nameof (TrampolineReceiveHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ReceiveHandler, handler); +#endif nw_ethernet_channel_set_receive_handler (GetCheckedHandle (), &block); } } @@ -197,10 +212,14 @@ public void SetReceiveHandler (NWEthernetChannelReceiveDelegate handler) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_ethernet_channel_set_state_changed_handler (OS_nw_ethernet_channel ethernet_channel, /* [NullAllowed] */ BlockLiteral *handler); +#if !NET delegate void nw_ethernet_channel_state_changed_handler_t (IntPtr block, NWEthernetChannelState state, IntPtr error); static nw_ethernet_channel_state_changed_handler_t static_StateChangesHandler = TrampolineStateChangesHandler; [MonoPInvokeCallback (typeof (nw_ethernet_channel_state_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineStateChangesHandler (IntPtr block, NWEthernetChannelState state, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -219,8 +238,13 @@ public void SetStateChangesHandler (Action handler) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineStateChangesHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWEthernetChannel), nameof (TrampolineStateChangesHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_StateChangesHandler, handler); +#endif nw_ethernet_channel_set_state_changed_handler (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWFramer.cs b/src/Network/NWFramer.cs index 87a580b0a3dc..dcfcc5005d1b 100644 --- a/src/Network/NWFramer.cs +++ b/src/Network/NWFramer.cs @@ -78,10 +78,14 @@ public void WriteOutput (ReadOnlySpan data) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_set_wakeup_handler (OS_nw_framer framer, void* wakeup_handler); +#if !NET delegate void nw_framer_set_wakeup_handler_t (IntPtr block, OS_nw_framer framer); static nw_framer_set_wakeup_handler_t static_WakeupHandler = TrampolineWakeupHandler; [MonoPInvokeCallback (typeof (nw_framer_set_wakeup_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineWakeupHandler (IntPtr block, OS_nw_framer framer) { var del = BlockLiteral.GetTarget> (block); @@ -99,8 +103,13 @@ public Action WakeupHandler { nw_framer_set_wakeup_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineWakeupHandler; + using var block = new BlockLiteral (trampoline, value, typeof (NWFramer), nameof (TrampolineWakeupHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_WakeupHandler, value); +#endif nw_framer_set_wakeup_handler (GetCheckedHandle (), &block); } } @@ -109,10 +118,14 @@ public Action WakeupHandler { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_set_stop_handler (OS_nw_framer framer, void* stop_handler); +#if !NET delegate void nw_framer_set_stop_handler_t (IntPtr block, OS_nw_framer framer); static nw_framer_set_stop_handler_t static_StopHandler = TrampolineStopHandler; [MonoPInvokeCallback (typeof (nw_framer_set_stop_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineStopHandler (IntPtr block, OS_nw_framer framer) { var del = BlockLiteral.GetTarget> (block); @@ -130,8 +143,13 @@ public Action StopHandler { nw_framer_set_stop_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineStopHandler; + using var block = new BlockLiteral (trampoline, value, typeof (NWFramer), nameof (TrampolineStopHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_StopHandler, value); +#endif nw_framer_set_stop_handler (GetCheckedHandle (), &block); } } @@ -140,10 +158,14 @@ public Action StopHandler { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_set_output_handler (OS_nw_framer framer, void* output_handler); +#if !NET delegate void nw_framer_set_output_handler_t (IntPtr block, OS_nw_framer framer, OS_nw_protocol_metadata message, nuint message_length, byte is_complete); static nw_framer_set_output_handler_t static_OutputHandler = TrampolineOutputHandler; [MonoPInvokeCallback (typeof (nw_framer_set_output_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineOutputHandler (IntPtr block, OS_nw_framer framer, OS_nw_protocol_metadata message, nuint message_length, byte is_complete) { var del = BlockLiteral.GetTarget> (block); @@ -162,8 +184,13 @@ public Action OutputHandler { nw_framer_set_output_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineOutputHandler; + using var block = new BlockLiteral (trampoline, value, typeof (NWFramer), nameof (TrampolineOutputHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_OutputHandler, value); +#endif nw_framer_set_output_handler (GetCheckedHandle (), &block); } } @@ -172,10 +199,14 @@ public Action OutputHandler { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_set_input_handler (OS_nw_framer framer, void* input_handler); +#if !NET delegate nuint nw_framer_set_input_handler_t (IntPtr block, OS_nw_framer framer); static nw_framer_set_input_handler_t static_InputHandler = TrampolineInputHandler; [MonoPInvokeCallback (typeof (nw_framer_set_input_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static nuint TrampolineInputHandler (IntPtr block, OS_nw_framer framer) { var del = BlockLiteral.GetTarget (block); @@ -194,8 +225,13 @@ public NWFramerInputDelegate InputHandler { nw_framer_set_input_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineInputHandler; + using var block = new BlockLiteral (trampoline, value, typeof (NWFramer), nameof (TrampolineInputHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_InputHandler, value); +#endif nw_framer_set_input_handler (GetCheckedHandle (), &block); } } @@ -204,10 +240,14 @@ public NWFramerInputDelegate InputHandler { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_set_cleanup_handler (OS_nw_framer framer, void* cleanup_handler); +#if !NET delegate void nw_framer_set_cleanup_handler_t (IntPtr block, OS_nw_framer framer); static nw_framer_set_cleanup_handler_t static_CleanupHandler = TrampolineCleanupHandler; [MonoPInvokeCallback (typeof (nw_framer_set_cleanup_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineCleanupHandler (IntPtr block, OS_nw_framer framer) { var del = BlockLiteral.GetTarget> (block); @@ -225,8 +265,13 @@ public Action CleanupHandler { nw_framer_set_cleanup_handler (GetCheckedHandle (), null); return; } +#if NET + delegate* unmanaged trampoline = &TrampolineCleanupHandler; + using var block = new BlockLiteral (trampoline, value, typeof (NWFramer), nameof (TrampolineCleanupHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_CleanupHandler, value); +#endif nw_framer_set_cleanup_handler (GetCheckedHandle (), &block); } } @@ -331,10 +376,14 @@ public void ScheduleAsync (Action handler) [return: MarshalAs (UnmanagedType.I1)] static extern unsafe bool nw_framer_parse_output (OS_nw_framer framer, nuint minimum_incomplete_length, nuint maximum_length, byte* temp_buffer, BlockLiteral* parse); +#if !NET delegate void nw_framer_parse_output_t (IntPtr block, IntPtr buffer, nuint buffer_length, byte is_complete); static nw_framer_parse_output_t static_ParseOutputHandler = TrampolineParseOutputHandler; [MonoPInvokeCallback (typeof (nw_framer_parse_output_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineParseOutputHandler (IntPtr block, IntPtr buffer, nuint buffer_length, byte is_complete) { var del = BlockLiteral.GetTarget, bool>> (block); @@ -352,8 +401,13 @@ public bool ParseOutput (nuint minimumIncompleteLength, nuint maximumLength, Mem if (handler is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineParseOutputHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWFramer), nameof (TrampolineParseOutputHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ParseOutputHandler, handler); +#endif using (var mh = tempBuffer.Pin ()) return nw_framer_parse_output (GetCheckedHandle (), minimumIncompleteLength, maximumLength, (byte*) mh.Pointer, &block); } @@ -363,10 +417,14 @@ public bool ParseOutput (nuint minimumIncompleteLength, nuint maximumLength, Mem [return: MarshalAs (UnmanagedType.I1)] static extern unsafe bool nw_framer_parse_input (OS_nw_framer framer, nuint minimum_incomplete_length, nuint maximum_length, byte* temp_buffer, BlockLiteral* parse); +#if !NET delegate nuint nw_framer_parse_input_t (IntPtr block, IntPtr buffer, nuint buffer_length, byte is_complete); static nw_framer_parse_input_t static_ParseInputHandler = TrampolineParseInputHandler; [MonoPInvokeCallback (typeof (nw_framer_parse_input_t))] +#else + [UnmanagedCallersOnly] +#endif static nuint TrampolineParseInputHandler (IntPtr block, IntPtr buffer, nuint buffer_length, byte is_complete) { var del = BlockLiteral.GetTarget (block); @@ -385,8 +443,13 @@ public bool ParseInput (nuint minimumIncompleteLength, nuint maximumLength, Memo if (handler is null) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineParseInputHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWFramer), nameof (TrampolineParseInputHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ParseInputHandler, handler); +#endif using (var mh = tempBuffer.Pin ()) return nw_framer_parse_input (GetCheckedHandle (), minimumIncompleteLength, maximumLength, (byte*) mh.Pointer, &block); } diff --git a/src/Network/NWFramerMessage.cs b/src/Network/NWFramerMessage.cs index f5f964fd0ad6..8f570d3d7f57 100644 --- a/src/Network/NWFramerMessage.cs +++ b/src/Network/NWFramerMessage.cs @@ -60,10 +60,14 @@ public static NWFramerMessage Create (NWProtocolDefinition protocolDefinition) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_framer_message_set_value (OS_nw_protocol_metadata message, IntPtr key, IntPtr value, BlockLiteral* dispose_value); +#if !NET delegate void nw_framer_message_set_value_t (IntPtr block, IntPtr data); static nw_framer_message_set_value_t static_SetDataHandler = TrampolineSetDataHandler; [MonoPInvokeCallback (typeof (nw_framer_message_set_value_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSetDataHandler (IntPtr block, IntPtr data) { // get and call, this is internal and we are trying to do all the magic in the call @@ -86,8 +90,13 @@ public void SetData (string key, byte [] value) pinned.Free (); }; unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineSetDataHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWFramerMessage), nameof (TrampolineSetDataHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_SetDataHandler, callback); +#endif using var keyPtr = new TransientString (key); nw_framer_message_set_value (GetCheckedHandle (), keyPtr, pinned.AddrOfPinnedObject (), &block); } @@ -96,11 +105,15 @@ public void SetData (string key, byte [] value) [DllImport (Constants.NetworkLibrary)] [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_framer_message_access_value (OS_nw_protocol_metadata message, IntPtr key, BlockLiteral* access_value); +#if !NET delegate byte nw_framer_message_access_value_t (IntPtr block, IntPtr data); static nw_framer_message_access_value_t static_AccessValueHandler = TrampolineAccessValueHandler; [MonoPInvokeCallback (typeof (nw_framer_message_access_value_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineAccessValueHandler (IntPtr block, IntPtr data) { // get and call, this is internal and we are trying to do all the magic in the call @@ -126,8 +139,13 @@ public bool GetData (string key, int dataLength, out ReadOnlySpan outData) }; unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineAccessValueHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWFramerMessage), nameof (TrampolineAccessValueHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_AccessValueHandler, callback); +#endif // the callback is inlined!!! using var keyPtr = new TransientString (key); var found = nw_framer_message_access_value (GetCheckedHandle (), keyPtr, &block); diff --git a/src/Network/NWListener.cs b/src/Network/NWListener.cs index d11b02b29652..98ba604b01c4 100644 --- a/src/Network/NWListener.cs +++ b/src/Network/NWListener.cs @@ -131,10 +131,14 @@ public void Start () public void Cancel () => nw_listener_cancel (GetCheckedHandle ()); +#if !NET delegate void nw_listener_state_changed_handler_t (IntPtr block, NWListenerState state, IntPtr nwerror); static nw_listener_state_changed_handler_t static_ListenerStateChanged = TrampolineListenerStateChanged; [MonoPInvokeCallback (typeof (nw_listener_state_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineListenerStateChanged (IntPtr block, NWListenerState state, IntPtr nwerror) { var del = BlockLiteral.GetTarget> (block); @@ -157,16 +161,25 @@ public void SetStateChangedHandler (Action callback) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineListenerStateChanged; + using var block = new BlockLiteral (trampoline, callback, typeof (NWListener), nameof (TrampolineListenerStateChanged)); +#else var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ListenerStateChanged, callback); +#endif nw_listener_set_state_changed_handler (GetCheckedHandle (), &block); } } +#if !NET delegate void nw_listener_new_connection_handler_t (IntPtr block, IntPtr connection); static nw_listener_new_connection_handler_t static_NewConnection = TrampolineNewConnection; [MonoPInvokeCallback (typeof (nw_listener_new_connection_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineNewConnection (IntPtr block, IntPtr connection) { var del = BlockLiteral.GetTarget> (block); @@ -189,20 +202,31 @@ public void SetNewConnectionHandler (Action callback) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineNewConnection; + using var block = new BlockLiteral (trampoline, callback, typeof (NWListener), nameof (TrampolineNewConnection)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_NewConnection, callback); +#endif nw_listener_set_new_connection_handler (GetCheckedHandle (), &block); connectionHandlerWasSet = true; } } } +#if !NET delegate void nw_listener_advertised_endpoint_changed_handler_t (IntPtr block, IntPtr endpoint, byte added); static nw_listener_advertised_endpoint_changed_handler_t static_AdvertisedEndpointChangedHandler = TrampolineAdvertisedEndpointChangedHandler; +#endif public delegate void AdvertisedEndpointChanged (NWEndpoint endpoint, bool added); +#if !NET [MonoPInvokeCallback (typeof (nw_listener_advertised_endpoint_changed_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineAdvertisedEndpointChangedHandler (IntPtr block, IntPtr endpoint, byte added) { var del = BlockLiteral.GetTarget (block); @@ -224,8 +248,13 @@ public void SetAdvertisedEndpointChangedHandler (AdvertisedEndpointChanged callb return; } +#if NET + delegate* unmanaged trampoline = &TrampolineAdvertisedEndpointChangedHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWListener), nameof (TrampolineAdvertisedEndpointChangedHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_AdvertisedEndpointChangedHandler, callback); +#endif nw_listener_set_advertised_endpoint_changed_handler (GetCheckedHandle (), &block); } } @@ -294,10 +323,14 @@ public uint ConnectionLimit { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_listener_set_new_connection_group_handler (IntPtr listener, /* [NullAllowed] */ BlockLiteral* handler); +#if !NET delegate void nw_listener_new_connection_group_handler_t (IntPtr block, nw_connection_group_t group); static nw_listener_new_connection_group_handler_t static_NewConnectionGroup = TrampolineNewConnectionGroup; [MonoPInvokeCallback (typeof (nw_listener_new_connection_group_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineNewConnectionGroup (IntPtr block, nw_connection_group_t connectionGroup) { var del = BlockLiteral.GetTarget> (block); @@ -323,8 +356,13 @@ static void TrampolineNewConnectionGroup (IntPtr block, nw_connection_group_t co public void SetNewConnectionGroupHandler (Action handler) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineNewConnectionGroup; + using var block = new BlockLiteral (trampoline, handler, typeof (NWListener), nameof (TrampolineNewConnectionGroup)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_NewConnectionGroup, handler); +#endif nw_listener_set_new_connection_group_handler (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWMulticastGroup.cs b/src/Network/NWMulticastGroup.cs index a8a54661fd47..56130206f909 100644 --- a/src/Network/NWMulticastGroup.cs +++ b/src/Network/NWMulticastGroup.cs @@ -77,10 +77,14 @@ public void SetSpecificSource (NWEndpoint endpoint) [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_group_descriptor_enumerate_endpoints (OS_nw_group_descriptor descriptor, BlockLiteral* enumerate_block); +#if !NET delegate byte nw_group_descriptor_enumerate_endpoints_block_t (IntPtr block, OS_nw_endpoint endpoint); static nw_group_descriptor_enumerate_endpoints_block_t static_EnumerateEndpointsHandler = TrampolineEnumerateEndpointsHandler; [MonoPInvokeCallback (typeof (nw_group_descriptor_enumerate_endpoints_block_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineEnumerateEndpointsHandler (IntPtr block, OS_nw_endpoint endpoint) { var del = BlockLiteral.GetTarget> (block); @@ -98,8 +102,13 @@ public void EnumerateEndpoints (Func handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateEndpointsHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWMulticastGroup), nameof (TrampolineEnumerateEndpointsHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateEndpointsHandler, handler); +#endif nw_group_descriptor_enumerate_endpoints (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWParameters.cs b/src/Network/NWParameters.cs index 9350d9a537e6..e2c8151c600f 100644 --- a/src/Network/NWParameters.cs +++ b/src/Network/NWParameters.cs @@ -77,10 +77,14 @@ public NWParameters (NativeHandle handle, bool owns) : base (handle, owns) { } static unsafe BlockLiteral* DISABLE_PROTOCOL () => (BlockLiteral*) NWParametersConstants._ProtocolDisable; +#if !NET delegate void nw_parameters_configure_protocol_block_t (IntPtr block, IntPtr iface); static nw_parameters_configure_protocol_block_t static_ConfigureHandler = TrampolineConfigureHandler; [MonoPInvokeCallback (typeof (nw_parameters_configure_protocol_block_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineConfigureHandler (IntPtr block, IntPtr iface) { var del = BlockLiteral.GetTarget> (block); @@ -121,8 +125,13 @@ static void TrampolineConfigureHandler (IntPtr block, IntPtr iface) return DEFAULT_CONFIGURATION (); } +#if NET + delegate* unmanaged trampoline = &TrampolineConfigureHandler; + var block = new BlockLiteral (trampoline, callback, typeof (NWParameters), nameof (TrampolineConfigureHandler)); +#else var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ConfigureHandler, callback); +#endif *callbackBlock = block; disposeReturnValue = true; return callbackBlock; @@ -382,10 +391,14 @@ public void ClearProhibitedInterfaceTypes () nw_parameters_clear_prohibited_interface_types (GetCheckedHandle ()); } +#if !NET delegate byte nw_parameters_iterate_interfaces_block_t (IntPtr block, IntPtr iface); static nw_parameters_iterate_interfaces_block_t static_iterateProhibitedHandler = TrampolineIterateProhibitedHandler; [MonoPInvokeCallback (typeof (nw_parameters_iterate_interfaces_block_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineIterateProhibitedHandler (IntPtr block, IntPtr iface) { var del = BlockLiteral.GetTarget> (block); @@ -405,16 +418,25 @@ static byte TrampolineIterateProhibitedHandler (IntPtr block, IntPtr iface) public void IterateProhibitedInterfaces (Func iterationCallback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineIterateProhibitedHandler; + using var block = new BlockLiteral (trampoline, iterationCallback, typeof (NWParameters), nameof (TrampolineIterateProhibitedHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_iterateProhibitedHandler, iterationCallback); +#endif nw_parameters_iterate_prohibited_interfaces (GetCheckedHandle (), &block); } } +#if !NET delegate byte nw_parameters_iterate_interface_types_block_t (IntPtr block, NWInterfaceType type); static nw_parameters_iterate_interface_types_block_t static_IterateProhibitedTypeHandler = TrampolineIterateProhibitedTypeHandler; [MonoPInvokeCallback (typeof (nw_parameters_iterate_interface_types_block_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineIterateProhibitedTypeHandler (IntPtr block, NWInterfaceType type) { var del = BlockLiteral.GetTarget> (block); @@ -430,8 +452,13 @@ static byte TrampolineIterateProhibitedTypeHandler (IntPtr block, NWInterfaceTyp public void IterateProhibitedInterfaces (Func callback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineIterateProhibitedTypeHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWParameters), nameof (TrampolineIterateProhibitedTypeHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_IterateProhibitedTypeHandler, callback); +#endif nw_parameters_iterate_prohibited_interface_types (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWPath.cs b/src/Network/NWPath.cs index 71520adba6c9..f531af8e383c 100644 --- a/src/Network/NWPath.cs +++ b/src/Network/NWPath.cs @@ -114,10 +114,14 @@ public bool EqualsTo (NWPath other) } // Returning 'byte' since 'bool' isn't blittable +#if !NET delegate byte nw_path_enumerate_interfaces_block_t (IntPtr block, IntPtr iface); static nw_path_enumerate_interfaces_block_t static_Enumerator = TrampolineEnumerator; [MonoPInvokeCallback (typeof (nw_path_enumerate_interfaces_block_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineEnumerator (IntPtr block, IntPtr iface) { var del = BlockLiteral.GetTarget> (block); @@ -153,8 +157,13 @@ public void EnumerateInterfaces (Func callback) return; unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerator; + using var block = new BlockLiteral (trampoline, callback, typeof (NWPath), nameof (TrampolineEnumerator)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_Enumerator, callback); +#endif nw_path_enumerate_interfaces (GetCheckedHandle (), &block); } } @@ -199,10 +208,14 @@ public void EnumerateInterfaces (Func callback) unsafe static extern void nw_path_enumerate_gateways (IntPtr path, BlockLiteral* enumerate_block); // Returning 'byte' since 'bool' isn't blittable +#if !NET delegate byte nw_path_enumerate_gateways_t (IntPtr block, IntPtr endpoint); static nw_path_enumerate_gateways_t static_EnumerateGatewaysHandler = TrampolineGatewaysHandler; [MonoPInvokeCallback (typeof (nw_path_enumerate_gateways_t))] +#else + [UnmanagedCallersOnly] +#endif static byte TrampolineGatewaysHandler (IntPtr block, IntPtr endpoint) { var del = BlockLiteral.GetTarget> (block); @@ -253,8 +266,13 @@ public void EnumerateGateways (Func callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineGatewaysHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWPath), nameof (TrampolineGatewaysHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateGatewaysHandler, callback); +#endif nw_path_enumerate_gateways (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWPathMonitor.cs b/src/Network/NWPathMonitor.cs index 919a3f319bca..416f4c045c63 100644 --- a/src/Network/NWPathMonitor.cs +++ b/src/Network/NWPathMonitor.cs @@ -85,10 +85,14 @@ public void SetQueue (DispatchQueue queue) nw_path_monitor_set_queue (GetCheckedHandle (), queue.Handle); } +#if !NET delegate void nw_path_monitor_update_handler_t (IntPtr block, IntPtr path); static nw_path_monitor_update_handler_t static_UpdateSnapshot = TrampolineUpdatedSnapshot; [MonoPInvokeCallback (typeof (nw_path_monitor_update_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineUpdatedSnapshot (IntPtr block, IntPtr path) { var del = BlockLiteral.GetTarget> (block); @@ -110,8 +114,13 @@ void _SetUpdatedSnapshotHandler (Action callback) return; } +#if NET + delegate* unmanaged trampoline = &TrampolineUpdatedSnapshot; + using var block = new BlockLiteral (trampoline, callback, typeof (NWPathMonitor), nameof (TrampolineUpdatedSnapshot)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_UpdateSnapshot, callback); +#endif nw_path_monitor_set_update_handler (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWProtocolDefinition.cs b/src/Network/NWProtocolDefinition.cs index c8e9cae71125..b6f110c1623d 100644 --- a/src/Network/NWProtocolDefinition.cs +++ b/src/Network/NWProtocolDefinition.cs @@ -141,10 +141,14 @@ public bool Equals (object other) #endif [DllImport (Constants.NetworkLibrary)] static extern unsafe OS_nw_protocol_definition nw_framer_create_definition (IntPtr identifier, NWFramerCreateFlags flags, BlockLiteral* start_handler); +#if !NET delegate NWFramerStartResult nw_framer_create_definition_t (IntPtr block, IntPtr framer); static nw_framer_create_definition_t static_CreateFramerHandler = TrampolineCreateFramerHandler; [MonoPInvokeCallback (typeof (nw_framer_create_definition_t))] +#else + [UnmanagedCallersOnly] +#endif static NWFramerStartResult TrampolineCreateFramerHandler (IntPtr block, IntPtr framer) { // get and call, this is internal and we are trying to do all the magic in the call @@ -170,8 +174,13 @@ static NWFramerStartResult TrampolineCreateFramerHandler (IntPtr block, IntPtr f public static NWProtocolDefinition CreateFramerDefinition (string identifier, NWFramerCreateFlags flags, Func startCallback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineCreateFramerHandler; + using var block = new BlockLiteral (trampoline, startCallback, typeof (NWProtocolDefinition), nameof (TrampolineCreateFramerHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_CreateFramerHandler, startCallback); +#endif using var identifierPtr = new TransientString (identifier); return new NWProtocolDefinition (nw_framer_create_definition (identifierPtr, flags, &block), owns: true); } diff --git a/src/Network/NWProtocolStack.cs b/src/Network/NWProtocolStack.cs index 2f7987b717cb..27accdb4cd6a 100644 --- a/src/Network/NWProtocolStack.cs +++ b/src/Network/NWProtocolStack.cs @@ -64,10 +64,14 @@ public void ClearApplicationProtocols () nw_protocol_stack_clear_application_protocols (GetCheckedHandle ()); } +#if !NET delegate void nw_protocol_stack_iterate_protocols_block_t (IntPtr block, IntPtr options); static nw_protocol_stack_iterate_protocols_block_t static_iterateHandler = TrampolineIterateHandler; [MonoPInvokeCallback (typeof (nw_protocol_stack_iterate_protocols_block_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineIterateHandler (IntPtr block, IntPtr options) { var del = BlockLiteral.GetTarget> (block); @@ -101,8 +105,13 @@ static void TrampolineIterateHandler (IntPtr block, IntPtr options) public void IterateProtocols (Action callback) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineIterateHandler; + using var block = new BlockLiteral (trampoline, callback, typeof (NWProtocolStack), nameof (TrampolineIterateHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_iterateHandler, callback); +#endif nw_protocol_stack_iterate_application_protocols (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWTxtRecord.cs b/src/Network/NWTxtRecord.cs index a7813248c188..dbe8f98deb96 100644 --- a/src/Network/NWTxtRecord.cs +++ b/src/Network/NWTxtRecord.cs @@ -144,8 +144,10 @@ public bool Equals (NWTxtRecord other) [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_txt_record_apply (OS_nw_txt_record txt_record, BlockLiteral* applier); +#if !NET delegate byte nw_txt_record_apply_t (IntPtr block, IntPtr key, NWTxtRecordFindKey found, IntPtr value, nuint valueLen); unsafe static nw_txt_record_apply_t static_ApplyHandler = TrampolineApplyHandler; +#endif #if NET public delegate bool NWTxtRecordApplyDelegate (string? key, NWTxtRecordFindKey result, ReadOnlySpan value); @@ -154,7 +156,11 @@ public bool Equals (NWTxtRecord other) public delegate bool NWTxtRecordApplyDelegate2 (string? key, NWTxtRecordFindKey result, ReadOnlySpan value); #endif +#if !NET [MonoPInvokeCallback (typeof (nw_txt_record_apply_t))] +#else + [UnmanagedCallersOnly] +#endif unsafe static byte TrampolineApplyHandler (IntPtr block, IntPtr keyPointer, NWTxtRecordFindKey found, IntPtr value, nuint valueLen) { #if NET @@ -191,8 +197,13 @@ public bool Apply (NWTxtRecordApplyDelegate handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineApplyHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWTxtRecord), nameof (TrampolineApplyHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ApplyHandler, handler); +#endif return nw_txt_record_apply (GetCheckedHandle (), &block); } } @@ -216,12 +227,18 @@ public bool Apply (NWTxtRecordApplyDelegate2 handler) [return: MarshalAs (UnmanagedType.I1)] static extern unsafe bool nw_txt_record_access_key (OS_nw_txt_record txt_record, IntPtr key, BlockLiteral* access_value); +#if !NET unsafe delegate void nw_txt_record_access_key_t (IntPtr IntPtr, IntPtr key, NWTxtRecordFindKey found, IntPtr value, nuint valueLen); unsafe static nw_txt_record_access_key_t static_AccessKeyHandler = TrampolineAccessKeyHandler; +#endif public delegate void NWTxtRecordGetValueDelegete (string? key, NWTxtRecordFindKey result, ReadOnlySpan value); +#if !NET [MonoPInvokeCallback (typeof (nw_txt_record_access_key_t))] +#else + [UnmanagedCallersOnly] +#endif unsafe static void TrampolineAccessKeyHandler (IntPtr block, IntPtr keyPointer, NWTxtRecordFindKey found, IntPtr value, nuint valueLen) { var del = BlockLiteral.GetTarget (block); @@ -243,8 +260,13 @@ public bool GetValue (string key, NWTxtRecordGetValueDelegete handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineAccessKeyHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWTxtRecord), nameof (TrampolineAccessKeyHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_AccessKeyHandler, handler); +#endif using var keyPtr = new TransientString (key); return nw_txt_record_access_key (GetCheckedHandle (), keyPtr, &block); } @@ -254,12 +276,18 @@ public bool GetValue (string key, NWTxtRecordGetValueDelegete handler) [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_txt_record_access_bytes (OS_nw_txt_record txt_record, BlockLiteral* access_bytes); +#if !NET unsafe delegate void nw_txt_record_access_bytes_t (IntPtr block, IntPtr value, nuint valueLen); unsafe static nw_txt_record_access_bytes_t static_RawBytesHandler = TrampolineRawBytesHandler; +#endif public delegate void NWTxtRecordGetRawByteDelegate (ReadOnlySpan value); +#if !NET [MonoPInvokeCallback (typeof (nw_txt_record_access_bytes_t))] +#else + [UnmanagedCallersOnly] +#endif unsafe static void TrampolineRawBytesHandler (IntPtr block, IntPtr value, nuint valueLen) { var del = BlockLiteral.GetTarget (block); @@ -276,8 +304,13 @@ public bool GetRawBytes (NWTxtRecordGetRawByteDelegate handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineRawBytesHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWTxtRecord), nameof (TrampolineRawBytesHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_RawBytesHandler, handler); +#endif return nw_txt_record_access_bytes (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWWebSocketMetadata.cs b/src/Network/NWWebSocketMetadata.cs index 44a4040858ed..71814506ca55 100644 --- a/src/Network/NWWebSocketMetadata.cs +++ b/src/Network/NWWebSocketMetadata.cs @@ -66,10 +66,14 @@ public NWWebSocketCloseCode CloseCode { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_ws_metadata_set_pong_handler (OS_nw_protocol_metadata metadata, dispatch_queue_t client_queue, BlockLiteral* pong_handler); +#if !NET delegate void nw_ws_metadata_set_pong_handler_t (IntPtr block, IntPtr error); static nw_ws_metadata_set_pong_handler_t static_PongHandler = TrampolinePongHandler; [MonoPInvokeCallback (typeof (nw_ws_metadata_set_pong_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolinePongHandler (IntPtr block, IntPtr error) { var del = BlockLiteral.GetTarget> (block); @@ -89,8 +93,13 @@ public void SetPongHandler (DispatchQueue queue, Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolinePongHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWWebSocketMetadata), nameof (TrampolinePongHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_PongHandler, handler); +#endif nw_ws_metadata_set_pong_handler (GetCheckedHandle (), queue.Handle, &block); } } diff --git a/src/Network/NWWebSocketOptions.cs b/src/Network/NWWebSocketOptions.cs index ec68d372a71d..2f97ce437129 100644 --- a/src/Network/NWWebSocketOptions.cs +++ b/src/Network/NWWebSocketOptions.cs @@ -108,10 +108,14 @@ public bool SkipHandShake { [DllImport (Constants.NetworkLibrary)] unsafe static extern void nw_ws_options_set_client_request_handler (OS_nw_protocol_options options, IntPtr client_queue, BlockLiteral* handler); +#if !NET delegate void nw_ws_options_set_client_request_handler_t (IntPtr block, nw_ws_request_t request); static nw_ws_options_set_client_request_handler_t static_ClientRequestHandler = TrampolineClientRequestHandler; [MonoPInvokeCallback (typeof (nw_ws_options_set_client_request_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineClientRequestHandler (IntPtr block, nw_ws_request_t request) { var del = BlockLiteral.GetTarget> (block); @@ -130,8 +134,13 @@ public void SetClientRequestHandler (DispatchQueue queue, Action trampoline = &TrampolineClientRequestHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWWebSocketOptions), nameof (TrampolineClientRequestHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_ClientRequestHandler, handler); +#endif nw_ws_options_set_client_request_handler (GetCheckedHandle (), queue.Handle, &block); } } diff --git a/src/Network/NWWebSocketRequest.cs b/src/Network/NWWebSocketRequest.cs index ebc7fc1f1e27..aa3dcffb57f2 100644 --- a/src/Network/NWWebSocketRequest.cs +++ b/src/Network/NWWebSocketRequest.cs @@ -43,10 +43,14 @@ internal NWWebSocketRequest (NativeHandle handle, bool owns) : base (handle, own [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_ws_request_enumerate_additional_headers (OS_nw_ws_request request, BlockLiteral* enumerator); +#if !NET delegate void nw_ws_request_enumerate_additional_headers_t (IntPtr block, IntPtr header, IntPtr value); static nw_ws_request_enumerate_additional_headers_t static_EnumerateHeaderHandler = TrampolineEnumerateHeaderHandler; [MonoPInvokeCallback (typeof (nw_ws_request_enumerate_additional_headers_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEnumerateHeaderHandler (IntPtr block, IntPtr headerPointer, IntPtr valuePointer) { var del = BlockLiteral.GetTarget> (block); @@ -64,8 +68,13 @@ public void EnumerateAdditionalHeaders (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateHeaderHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWWebSocketRequest), nameof (TrampolineEnumerateHeaderHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateHeaderHandler, handler); +#endif nw_ws_request_enumerate_additional_headers (GetCheckedHandle (), &block); } } @@ -74,10 +83,14 @@ public void EnumerateAdditionalHeaders (Action handler) [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_ws_request_enumerate_subprotocols (OS_nw_ws_request request, BlockLiteral* enumerator); +#if !NET delegate void nw_ws_request_enumerate_subprotocols_t (IntPtr block, IntPtr subprotocol); static nw_ws_request_enumerate_subprotocols_t static_EnumerateSubprotocolHandler = TrampolineEnumerateSubprotocolHandler; [MonoPInvokeCallback (typeof (nw_ws_request_enumerate_subprotocols_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEnumerateSubprotocolHandler (IntPtr block, IntPtr subprotocolPointer) { var del = BlockLiteral.GetTarget> (block); @@ -94,8 +107,13 @@ public void EnumerateSubprotocols (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateSubprotocolHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWWebSocketRequest), nameof (TrampolineEnumerateSubprotocolHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateSubprotocolHandler, handler); +#endif nw_ws_request_enumerate_subprotocols (GetCheckedHandle (), &block); } } diff --git a/src/Network/NWWebSocketResponse.cs b/src/Network/NWWebSocketResponse.cs index 5e723c3751b7..70150602a84e 100644 --- a/src/Network/NWWebSocketResponse.cs +++ b/src/Network/NWWebSocketResponse.cs @@ -72,10 +72,14 @@ static string nw_ws_response_get_selected_subprotocol (OS_nw_ws_response respons [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool nw_ws_response_enumerate_additional_headers (OS_nw_ws_response response, BlockLiteral* enumerator); +#if !NET delegate void nw_ws_response_enumerate_additional_headers_t (IntPtr block, IntPtr header, IntPtr value); static nw_ws_response_enumerate_additional_headers_t static_EnumerateHeadersHandler = TrampolineEnumerateHeadersHandler; [MonoPInvokeCallback (typeof (nw_ws_response_enumerate_additional_headers_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEnumerateHeadersHandler (IntPtr block, IntPtr headerPointer, IntPtr valuePointer) { var del = BlockLiteral.GetTarget> (block); @@ -93,8 +97,13 @@ public bool EnumerateAdditionalHeaders (Action handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEnumerateHeadersHandler; + using var block = new BlockLiteral (trampoline, handler, typeof (NWWebSocketResponseStatus), nameof (TrampolineEnumerateHeadersHandler)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_EnumerateHeadersHandler, handler); +#endif return nw_ws_response_enumerate_additional_headers (GetCheckedHandle (), &block); } } diff --git a/src/ObjCRuntime/Blocks.cs b/src/ObjCRuntime/Blocks.cs index 71799bdc025a..d6c017945127 100644 --- a/src/ObjCRuntime/Blocks.cs +++ b/src/ObjCRuntime/Blocks.cs @@ -34,6 +34,10 @@ using Foundation; using ObjCRuntime; +#if !COREBUILD +using Xamarin.Bundler; +#endif + // http://clang.llvm.org/docs/Block-ABI-Apple.html namespace ObjCRuntime { @@ -91,8 +95,95 @@ static IntPtr NSConcreteStackBlock { [DllImport ("__Internal")] static extern IntPtr xamarin_get_block_descriptor (); +#if NET + /// + /// Creates a block literal. + /// + /// A function pointer that will be called when the block is called. This function must have an [UnmanagedCallersOnly] attribute. + /// A context object that can be retrieved from the trampoline. This is typically a delegate to the managed function to call. + /// The type where the trampoline is located. + /// The name of the trampoline method. + /// + /// The 'trampolineType' and 'trampolineMethod' must uniquely define the trampoline method (it will be looked up using reflection). + /// If there are multiple methods with the same name, use the overload that takes a MethodInfo instead. + /// + public BlockLiteral (void* trampoline, object context, Type trampolineType, string trampolineMethod) + : this (trampoline, context, FindTrampoline (trampolineType, trampolineMethod)) + { + } + + /// + /// Creates a block literal. + /// + /// A function pointer that will be called when the block is called. This function must have an [UnmanagedCallersOnly] attribute. + /// A context object that can be retrieved from the trampoline. This is typically a delegate to the managed function to call. + /// The MethodInfo instance corresponding with the trampoline method. + public BlockLiteral (void* trampoline, object context, MethodInfo trampolineMethod) + : this (trampoline, context, GetBlockSignature (trampoline, trampolineMethod)) + { + } + + /// + /// Creates a block literal. + /// + /// A function pointer that will be called when the block is called. This function must have an [UnmanagedCallersOnly] attribute. + /// A context object that can be retrieved from the trampoline. This is typically a delegate to the managed function to call. + /// The Objective-C signature of the trampoline method. + public BlockLiteral (void* trampoline, object context, string trampolineSignature) + { + isa = IntPtr.Zero; + flags = (BlockFlags) 0; + reserved = 0; + invoke = IntPtr.Zero; + block_descriptor = IntPtr.Zero; + local_handle = IntPtr.Zero; + global_handle = IntPtr.Zero; + SetupFunctionPointerBlock ((IntPtr) trampoline, context, System.Text.Encoding.UTF8.GetBytes (trampolineSignature)); + } + + static MethodInfo FindTrampoline (Type trampolineType, string trampolineMethod) + { + var rv = trampolineType.GetMethod (trampolineMethod, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + + if (rv is null) + throw ErrorHelper.CreateError (8046, Errors.MX8046 /* Unable to find the method '{0}' in the type '{1}' */, trampolineMethod, trampolineType.FullName); + + return rv; + } + [BindingImpl (BindingImplOptions.Optimizable)] - void SetupBlock (Delegate trampoline, Delegate userDelegate, bool safe) + static string GetBlockSignature (void* trampoline, MethodInfo trampolineMethod) + { + if (!Runtime.DynamicRegistrationSupported) + throw ErrorHelper.CreateError (8050, Errors.MX8050 /* BlockLiteral.GetBlockSignature is not supported when the dynamic registrar has been linked away. */); + + // Verify that the function pointer matches the trampoline + var functionPointer = trampolineMethod.MethodHandle.GetFunctionPointer (); + if (functionPointer != (IntPtr) trampoline) + throw ErrorHelper.CreateError (8047, Errors.MX8047 /* The trampoline method {0} does not match the function pointer 0x{1} for the trampolineMethod argument (they're don't refer to the same method) */, trampolineMethod.DeclaringType.FullName + "." + trampolineMethod.Name, ((IntPtr) trampoline).ToString ("x")); + + // Verify that there's at least one parameter, and it must be System.IntPtr, void* or ObjCRuntime.BlockLiteral*. + var parameters = trampolineMethod.GetParameters (); + if (parameters.Length < 1) + throw ErrorHelper.CreateError (8048, Errors.MX8048 /* The trampoline method {0} must have at least one parameter. */, trampolineMethod.DeclaringType.FullName + "." + trampolineMethod.Name); + var firstParameterType = parameters [0].ParameterType; + if (firstParameterType != typeof (IntPtr) && + firstParameterType != typeof (void*) && + firstParameterType != typeof (BlockLiteral*)) { + throw ErrorHelper.CreateError (8049, Errors.MX8049 /* The first parameter in the trampoline method {0} must be either 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*'. */, trampolineMethod.DeclaringType.FullName + "." + trampolineMethod.Name); + } + + // Verify that the method as an [UnmanagedCallersOnly] attribute + if (!trampolineMethod.IsDefined (typeof (UnmanagedCallersOnlyAttribute), false)) + throw ErrorHelper.CreateError (8051, Errors.MX8051 /* The trampoline method {0} must have an [UnmanagedCallersOnly] attribute. */, trampolineMethod.DeclaringType.FullName + "." + trampolineMethod.Name); + + // We're good to go! + return Runtime.ComputeSignature (trampolineMethod, true); + } +#endif // NET + + [BindingImpl (BindingImplOptions.Optimizable)] + void SetupBlock (Delegate trampoline, Delegate target, bool safe) { if (!Runtime.DynamicRegistrationSupported) throw ErrorHelper.CreateError (8026, "BlockLiteral.SetupBlock is not supported when the dynamic registrar has been linked away."); @@ -119,23 +210,40 @@ void SetupBlock (Delegate trampoline, Delegate userDelegate, bool safe) } var signature = Runtime.ComputeSignature (userMethod, blockSignature); - SetupBlockImpl (trampoline, userDelegate, safe, signature); + SetupBlockImpl (trampoline, target, safe, System.Text.Encoding.UTF8.GetBytes (signature)); } - // This method is not to be called manually by user code. - // This is enforced by making it private. If the SetupBlock optimization is enabled, - // the linker will make it public so that it's callable from optimized user code. - unsafe void SetupBlockImpl (Delegate trampoline, Delegate userDelegate, bool safe, string signature) + void SetupBlockImpl (Delegate trampoline, Delegate target, bool safe, string signature) + { + SetupBlockImpl (trampoline, target, safe, System.Text.Encoding.UTF8.GetBytes (signature)); + } + + void SetupBlockImpl (Delegate trampoline, Delegate target, bool safe, byte [] utf8Signature) + { + var invoke = Marshal.GetFunctionPointerForDelegate (trampoline); + SetupFunctionPointerBlock (invoke, GetContext (trampoline, target, safe), utf8Signature); + } + + static object GetContext (Delegate trampoline, Delegate target, bool safe) { - isa = NSConcreteStackBlock; - invoke = Marshal.GetFunctionPointerForDelegate (trampoline); - object delegates; if (safe) { - delegates = new Tuple (trampoline, userDelegate); + return new Tuple (trampoline, target); } else { - delegates = userDelegate; + return target; } - local_handle = (IntPtr) GCHandle.Alloc (delegates); + } + + void SetupFunctionPointerBlock (IntPtr invokeMethod, object context, byte [] utf8Signature) + { + if (utf8Signature is null) + ThrowHelper.ThrowArgumentNullException (nameof (utf8Signature)); + + if (utf8Signature.Length == 0) + ThrowHelper.ThrowArgumentException (nameof (utf8Signature), Errors.MX8052 /* The signature must be a non-empty string. */); + + isa = NSConcreteStackBlock; + invoke = invokeMethod; + local_handle = (IntPtr) GCHandle.Alloc (context); global_handle = IntPtr.Zero; flags = BlockFlags.BLOCK_HAS_COPY_DISPOSE | BlockFlags.BLOCK_HAS_SIGNATURE; @@ -146,8 +254,9 @@ unsafe void SetupBlockImpl (Delegate trampoline, Delegate userDelegate, bool saf // for the signature if we can avoid it). One descriptor is allocated for every // Block; this is potentially something the static registrar can fix, since it // should know every possible trampoline signature. - var bytes = System.Text.Encoding.UTF8.GetBytes (signature); - var desclen = sizeof (XamarinBlockDescriptor) + bytes.Length + 1 /* null character */; + var bytes = utf8Signature; + var hasNull = utf8Signature [utf8Signature.Length - 1] == 0; + var desclen = sizeof (XamarinBlockDescriptor) + bytes.Length + (hasNull ? 0 : 1 /* null character */); var descptr = Marshal.AllocHGlobal (desclen); block_descriptor = descptr; @@ -156,7 +265,8 @@ unsafe void SetupBlockImpl (Delegate trampoline, Delegate userDelegate, bool saf xblock_descriptor->descriptor.signature = descptr + sizeof (BlockDescriptor) + 4 /* signature_length */; xblock_descriptor->ref_count = 1; Marshal.Copy (bytes, 0, xblock_descriptor->descriptor.signature, bytes.Length); - Marshal.WriteByte (xblock_descriptor->descriptor.signature + bytes.Length, 0); // null terminate string + if (!hasNull) + Marshal.WriteByte (xblock_descriptor->descriptor.signature + bytes.Length, 0); // null terminate string } // trampoline must be static, and someone else needs to keep a ref to it @@ -167,6 +277,7 @@ public void SetupBlockUnsafe (Delegate trampoline, Delegate userDelegate) } // trampoline must be static, but it's not necessary to keep a ref to it + [EditorBrowsable (EditorBrowsableState.Never)] public void SetupBlock (Delegate trampoline, Delegate userDelegate) { if (trampoline is null) @@ -236,10 +347,19 @@ public void Dispose () } } - public object Target { + /// + /// This is the 'context' value that was specified when creating the BlockLiteral. + /// + public object Context { get { var handle = global_handle != IntPtr.Zero ? global_handle : local_handle; - var target = GCHandle.FromIntPtr (handle).Target; + return GCHandle.FromIntPtr (handle).Target; + } + } + + public object Target { + get { + var target = Context; var tuple = target as Tuple; if (tuple != null) return tuple.Item2; @@ -318,6 +438,24 @@ static Type GetDelegateProxyType (MethodInfo minfo, uint token_ref, out MethodIn throw ErrorHelper.CreateError (8011, $"Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}. {Constants.PleaseFileBugReport}"); } +#if NET + [BindingImpl (BindingImplOptions.Optimizable)] + unsafe static IntPtr GetBlockForFunctionPointer (MethodInfo delegateInvokeMethod, object @delegate, string signature) + { + void* invokeFunctionPointer = (void *) delegateInvokeMethod.MethodHandle.GetFunctionPointer (); + if (signature is null) { + if (!Runtime.DynamicRegistrationSupported) + throw ErrorHelper.CreateError (8026, $"BlockLiteral.GetBlockForDelegate with a null signature is not supported when the dynamic registrar has been linked away (delegate type: {@delegate.GetType ().FullName})."); + + using (var block = new BlockLiteral (invokeFunctionPointer, @delegate, delegateInvokeMethod)) + return _Block_copy (&block); + } else { + using (var block = new BlockLiteral (invokeFunctionPointer, @delegate, signature)) + return _Block_copy (&block); + } + } +#endif // NET + [BindingImpl (BindingImplOptions.Optimizable)] internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, uint token_ref, string signature) { @@ -333,6 +471,12 @@ internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, if (delegateProxyType == null) throw ErrorHelper.CreateError (8012, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: DelegateType is null. {Constants.PleaseFileBugReport}"); +#if NET + var delegateInvokeMethod = delegateProxyType.GetMethod ("Invoke", BindingFlags.NonPublic | BindingFlags.Static); + if (delegateInvokeMethod is not null && delegateInvokeMethod.IsDefined (typeof (UnmanagedCallersOnlyAttribute), false)) + return GetBlockForFunctionPointer (delegateInvokeMethod, @delegate, signature); +#endif + var delegateProxyField = delegateProxyType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static); if (delegateProxyField is null) throw ErrorHelper.CreateError (8013, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: DelegateType ({delegateProxyType.FullName}) specifies a type without a 'Handler' field. {Constants.PleaseFileBugReport}"); @@ -386,10 +530,14 @@ internal static IntPtr Copy (IntPtr block) // first use of the class internal class BlockStaticDispatchClass { +#if !NET internal delegate void dispatch_block_t (IntPtr block); [MonoPInvokeCallback (typeof (dispatch_block_t))] - static unsafe void TrampolineDispatchBlock (IntPtr block) +#else + [UnmanagedCallersOnly] +#endif + internal static unsafe void TrampolineDispatchBlock (IntPtr block) { var del = BlockLiteral.GetTarget (block); if (del != null) { @@ -400,12 +548,19 @@ static unsafe void TrampolineDispatchBlock (IntPtr block) [BindingImpl (BindingImplOptions.Optimizable)] unsafe internal static BlockLiteral CreateBlock (Action action) { +#if NET + delegate* unmanaged trampoline = &BlockStaticDispatchClass.TrampolineDispatchBlock; + return new BlockLiteral (trampoline, action, typeof (BlockStaticDispatchClass), nameof (TrampolineDispatchBlock)); +#else var block = new BlockLiteral (); block.SetupBlockUnsafe (static_dispatch_block, action); return block; +#endif } +#if !NET internal static dispatch_block_t static_dispatch_block = TrampolineDispatchBlock; +#endif } // This class will free the specified block when it's collected by the GC. diff --git a/src/Security/SecIdentity2.cs b/src/Security/SecIdentity2.cs index 396de85a64b9..00d2648b5cf4 100644 --- a/src/Security/SecIdentity2.cs +++ b/src/Security/SecIdentity2.cs @@ -107,10 +107,14 @@ public SecCertificate [] Certificates { [return: MarshalAs (UnmanagedType.I1)] unsafe static extern bool sec_identity_access_certificates (IntPtr identity, BlockLiteral* block); +#if !NET internal delegate void AccessCertificatesHandler (IntPtr block, IntPtr cert); static readonly AccessCertificatesHandler access = TrampolineAccessCertificates; [MonoPInvokeCallback (typeof (AccessCertificatesHandler))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineAccessCertificates (IntPtr block, IntPtr cert) { var del = BlockLiteral.GetTarget> (block); @@ -137,8 +141,13 @@ public bool AccessCertificates (Action hand ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineAccessCertificates; + using var block = new BlockLiteral (trampoline, handler, typeof (SecIdentity2), nameof (TrampolineAccessCertificates)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (access, handler); +#endif return sec_identity_access_certificates (GetCheckedHandle (), &block); } } diff --git a/src/Security/SecProtocolMetadata.cs b/src/Security/SecProtocolMetadata.cs index efad1387522b..6a1d6ceacec1 100644 --- a/src/Security/SecProtocolMetadata.cs +++ b/src/Security/SecProtocolMetadata.cs @@ -191,10 +191,14 @@ public static bool PeersAreEqual (SecProtocolMetadata metadataA, SecProtocolMeta return sec_protocol_metadata_peers_are_equal (metadataA.GetCheckedHandle (), metadataB.GetCheckedHandle ()); } +#if !NET delegate void sec_protocol_metadata_access_distinguished_names_handler_t (IntPtr block, IntPtr dispatchData); static sec_protocol_metadata_access_distinguished_names_handler_t static_DistinguishedNamesForPeer = TrampolineDistinguishedNamesForPeer; [MonoPInvokeCallback (typeof (sec_protocol_metadata_access_distinguished_names_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineDistinguishedNamesForPeer (IntPtr block, IntPtr data) { var del = BlockLiteral.GetTarget> (block); @@ -215,17 +219,26 @@ public void SetDistinguishedNamesForPeerHandler (Action callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineDistinguishedNamesForPeer; + using var block = new BlockLiteral (trampoline, callback, typeof (SecProtocolMetadata), nameof (TrampolineDistinguishedNamesForPeer)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_DistinguishedNamesForPeer, callback); +#endif if (!sec_protocol_metadata_access_distinguished_names (GetCheckedHandle (), &block)) throw new InvalidOperationException ("Distinguished names are not accessible."); } } +#if !NET delegate void sec_protocol_metadata_access_ocsp_response_handler_t (IntPtr block, IntPtr dispatchData); static sec_protocol_metadata_access_ocsp_response_handler_t static_OcspReposeForPeer = TrampolineOcspReposeForPeer; [MonoPInvokeCallback (typeof (sec_protocol_metadata_access_ocsp_response_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineOcspReposeForPeer (IntPtr block, IntPtr data) { var del = BlockLiteral.GetTarget> (block); @@ -246,17 +259,26 @@ public void SetOcspResponseForPeerHandler (Action callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineOcspReposeForPeer; + using var block = new BlockLiteral (trampoline, callback, typeof (SecProtocolMetadata), nameof (TrampolineOcspReposeForPeer)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_OcspReposeForPeer, callback); +#endif if (!sec_protocol_metadata_access_ocsp_response (GetCheckedHandle (), &block)) throw new InvalidOperationException ("The OSCP response is not accessible."); } } +#if !NET delegate void sec_protocol_metadata_access_peer_certificate_chain_handler_t (IntPtr block, IntPtr certificate); static sec_protocol_metadata_access_peer_certificate_chain_handler_t static_CertificateChainForPeer = TrampolineCertificateChainForPeer; [MonoPInvokeCallback (typeof (sec_protocol_metadata_access_peer_certificate_chain_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineCertificateChainForPeer (IntPtr block, IntPtr certificate) { var del = BlockLiteral.GetTarget> (block); @@ -277,17 +299,26 @@ public void SetCertificateChainForPeerHandler (Action callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineCertificateChainForPeer; + using var block = new BlockLiteral (trampoline, callback, typeof (SecProtocolMetadata), nameof (TrampolineCertificateChainForPeer)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_CertificateChainForPeer, callback); +#endif if (!sec_protocol_metadata_access_peer_certificate_chain (GetCheckedHandle (), &block)) throw new InvalidOperationException ("The peer certificates are not accessible."); } } +#if !NET delegate void sec_protocol_metadata_access_supported_signature_algorithms_handler_t (IntPtr block, ushort signatureAlgorithm); static sec_protocol_metadata_access_supported_signature_algorithms_handler_t static_SignatureAlgorithmsForPeer = TrampolineSignatureAlgorithmsForPeer; [MonoPInvokeCallback (typeof (sec_protocol_metadata_access_supported_signature_algorithms_handler_t))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineSignatureAlgorithmsForPeer (IntPtr block, ushort signatureAlgorithm) { var del = BlockLiteral.GetTarget> (block); @@ -307,8 +338,13 @@ public void SetSignatureAlgorithmsForPeerHandler (Action callback) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (callback)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineSignatureAlgorithmsForPeer; + using var block = new BlockLiteral (trampoline, callback, typeof (SecProtocolMetadata), nameof (TrampolineSignatureAlgorithmsForPeer)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (static_SignatureAlgorithmsForPeer, callback); +#endif if (sec_protocol_metadata_access_supported_signature_algorithms (GetCheckedHandle (), &block) != 0) throw new InvalidOperationException ("The supported signature list is not accessible."); } @@ -390,10 +426,14 @@ public void SetSignatureAlgorithmsForPeerHandler (Action callback) public delegate void SecAccessPreSharedKeysHandler (DispatchData psk, DispatchData pskIdentity); +#if !NET internal delegate void AccessPreSharedKeysHandler (IntPtr block, IntPtr dd_psk, IntPtr dd_psk_identity); static readonly AccessPreSharedKeysHandler presharedkeys = TrampolineAccessPreSharedKeys; [MonoPInvokeCallback (typeof (AccessPreSharedKeysHandler))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineAccessPreSharedKeys (IntPtr block, IntPtr psk, IntPtr psk_identity) { var del = BlockLiteral.GetTarget> (block); @@ -420,8 +460,13 @@ public bool AccessPreSharedKeys (SecAccessPreSharedKeysHandler handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineAccessPreSharedKeys; + using var block = new BlockLiteral (trampoline, handler, typeof (SecProtocolMetadata), nameof (TrampolineAccessPreSharedKeys)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (presharedkeys, handler); +#endif return sec_protocol_metadata_access_pre_shared_keys (GetCheckedHandle (), &block); } } diff --git a/src/Security/SecSharedCredential.cs b/src/Security/SecSharedCredential.cs index 83dd64234a43..7b349fb053f8 100644 --- a/src/Security/SecSharedCredential.cs +++ b/src/Security/SecSharedCredential.cs @@ -18,15 +18,21 @@ public static partial class SecSharedCredential { unsafe extern static void SecAddSharedWebCredential (IntPtr /* CFStringRef */ fqdn, IntPtr /* CFStringRef */ account, IntPtr /* CFStringRef */ password, BlockLiteral* /* void (^completionHandler)( CFErrorRef error) ) */ completionHandler); +#if !NET [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)] internal delegate void DActionArity1V12 (IntPtr block, IntPtr obj); +#endif // This class bridges native block invocations that call into C# static internal class ActionTrampoline { +#if !NET static internal readonly DActionArity1V12 Handler = Invoke; [MonoPInvokeCallback (typeof (DActionArity1V12))] - static unsafe void Invoke (IntPtr block, IntPtr obj) { +#else + [UnmanagedCallersOnly] +#endif + internal static unsafe void Invoke (IntPtr block, IntPtr obj) { var descriptor = (BlockLiteral *) block; var del = (global::System.Action) (descriptor->Target); if (del is not null) { @@ -48,8 +54,14 @@ public static void AddSharedWebCredential (string domainName, string account, st using var nsDomain = new NSString (domainName); using var nsAccount = new NSString (account); using var nsPassword = (NSString?) password; + +#if NET + delegate* unmanaged trampoline = &ActionTrampoline.Invoke; + using var block = new BlockLiteral (trampoline, handler, typeof (ActionTrampoline), nameof (ActionTrampoline.Invoke)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (ActionTrampoline.Handler, handler); +#endif SecAddSharedWebCredential (nsDomain.Handle, nsAccount.Handle, nsPassword.GetHandle (), &block); } } @@ -69,18 +81,24 @@ public static void AddSharedWebCredential (string domainName, string account, st unsafe extern static void SecRequestSharedWebCredential ( IntPtr /* CFStringRef */ fqdn, IntPtr /* CFStringRef */ account, BlockLiteral* /* void (^completionHandler)( CFArrayRef credentials, CFErrorRef error) */ completionHandler); +#if !NET [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)] internal delegate void ArrayErrorAction (IntPtr block, IntPtr array, IntPtr err); +#endif // // This class bridges native block invocations that call into C# because we cannot use the decorator, we have to create // it for our use here. // static internal class ArrayErrorActionTrampoline { +#if !NET static internal readonly ArrayErrorAction Handler = Invoke; [MonoPInvokeCallback (typeof (ArrayErrorAction))] - static unsafe void Invoke (IntPtr block, IntPtr array, IntPtr err) { +#else + [UnmanagedCallersOnly] +#endif + internal static unsafe void Invoke (IntPtr block, IntPtr array, IntPtr err) { var descriptor = (BlockLiteral *) block; var del = (global::System.Action) (descriptor->Target); if (del is not null) @@ -123,8 +141,13 @@ public static void RequestSharedWebCredential (string domainName, string account using var nsAccount = (NSString?) account; unsafe { +#if NET + delegate* unmanaged trampoline = &ArrayErrorActionTrampoline.Invoke; + using var block = new BlockLiteral (trampoline, handler, typeof (ArrayErrorActionTrampoline), nameof (ArrayErrorActionTrampoline.Invoke)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (ArrayErrorActionTrampoline.Handler, onComplete); +#endif SecRequestSharedWebCredential (nsDomain.GetHandle (), nsAccount.GetHandle (), &block); } } diff --git a/src/Security/SecTrust.cs b/src/Security/SecTrust.cs index 9f8bf119c9da..64931599c0e1 100644 --- a/src/Security/SecTrust.cs +++ b/src/Security/SecTrust.cs @@ -181,10 +181,14 @@ public SecCertificate [] GetCustomAnchorCertificates () [DllImport (Constants.SecurityLibrary)] unsafe extern static SecStatusCode /* OSStatus */ SecTrustEvaluateAsync (IntPtr /* SecTrustRef */ trust, IntPtr /* dispatch_queue_t */ queue, BlockLiteral* block); +#if !NET internal delegate void TrustEvaluateHandler (IntPtr block, IntPtr trust, SecTrustResult trustResult); static readonly TrustEvaluateHandler evaluate = TrampolineEvaluate; [MonoPInvokeCallback (typeof (TrustEvaluateHandler))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEvaluate (IntPtr block, IntPtr trust, SecTrustResult trustResult) { var del = BlockLiteral.GetTarget (block); @@ -218,8 +222,13 @@ public SecStatusCode Evaluate (DispatchQueue queue, SecTrustCallback handler) ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEvaluate; + using var block = new BlockLiteral (trampoline, handler, typeof (SecTrust), nameof (TrampolineEvaluate)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (evaluate, handler); +#endif return SecTrustEvaluateAsync (Handle, queue.Handle, &block); } } @@ -238,10 +247,14 @@ public SecStatusCode Evaluate (DispatchQueue queue, SecTrustCallback handler) [DllImport (Constants.SecurityLibrary)] unsafe static extern SecStatusCode SecTrustEvaluateAsyncWithError (IntPtr /* SecTrustRef */ trust, IntPtr /* dispatch_queue_t */ queue, BlockLiteral* block); +#if !NET internal delegate void TrustEvaluateErrorHandler (IntPtr block, IntPtr trust, byte result, IntPtr /* CFErrorRef _Nullable */ error); static readonly TrustEvaluateErrorHandler evaluate_error = TrampolineEvaluateError; [MonoPInvokeCallback (typeof (TrustEvaluateErrorHandler))] +#else + [UnmanagedCallersOnly] +#endif static void TrampolineEvaluateError (IntPtr block, IntPtr trust, byte result, IntPtr /* CFErrorRef _Nullable */ error) { var del = BlockLiteral.GetTarget (block); @@ -272,8 +285,13 @@ public SecStatusCode Evaluate (DispatchQueue queue, SecTrustWithErrorCallback ha ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (handler)); unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineEvaluateError; + using var block = new BlockLiteral (trampoline, handler, typeof (SecTrust), nameof (TrampolineEvaluateError)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (evaluate_error, handler); +#endif return SecTrustEvaluateAsyncWithError (Handle, queue.Handle, &block); } } diff --git a/src/UIKit/UIAccessibility.cs b/src/UIKit/UIAccessibility.cs index ccf7e6752167..dcb4634e17ad 100644 --- a/src/UIKit/UIAccessibility.cs +++ b/src/UIKit/UIAccessibility.cs @@ -248,8 +248,13 @@ public static CGRect ConvertFrameToScreenCoordinates (CGRect rect, UIView view) public static void RequestGuidedAccessSession (bool enable, Action completionHandler) { unsafe { +#if NET + delegate* unmanaged trampoline = &TrampolineRequestGuidedAccessSession; + using var block = new BlockLiteral (trampoline, completionHandler, typeof (UIAccessibility), nameof (TrampolineRequestGuidedAccessSession)); +#else using var block = new BlockLiteral (); block.SetupBlock (callback, completionHandler); +#endif UIAccessibilityRequestGuidedAccessSession (enable, &block); } } @@ -268,10 +273,14 @@ public static Task RequestGuidedAccessSessionAsync (bool enable) return tcs.Task; } +#if !NET internal delegate void InnerRequestGuidedAccessSession (IntPtr block, byte enable); static readonly InnerRequestGuidedAccessSession callback = TrampolineRequestGuidedAccessSession; [MonoPInvokeCallback (typeof (InnerRequestGuidedAccessSession))] +#else + [UnmanagedCallersOnly] +#endif static unsafe void TrampolineRequestGuidedAccessSession (IntPtr block, byte enable) { var descriptor = (BlockLiteral*) block; diff --git a/src/UIKit/UICellAccessory.cs b/src/UIKit/UICellAccessory.cs index 6912d14e4cfe..2bab9fd3ba2d 100644 --- a/src/UIKit/UICellAccessory.cs +++ b/src/UIKit/UICellAccessory.cs @@ -62,9 +62,13 @@ public static UICellAccessoryPosition GetPositionAfterAccessory (Class accessory // This class bridges native block invocations that call into C# // static internal class SDUICellAccessoryPosition { +#if !NET static internal readonly DUICellAccessoryPosition Handler = Invoke; [MonoPInvokeCallback (typeof (DUICellAccessoryPosition))] +#else + [UnmanagedCallersOnly] +#endif static unsafe nuint Invoke (IntPtr block, IntPtr accessories) { var descriptor = (BlockLiteral*) block; diff --git a/src/UIKit/UIConfigurationColorTransformer.cs b/src/UIKit/UIConfigurationColorTransformer.cs index fe37bf99b2df..2590bdbd4bc1 100644 --- a/src/UIKit/UIConfigurationColorTransformer.cs +++ b/src/UIKit/UIConfigurationColorTransformer.cs @@ -46,9 +46,13 @@ public static UIConfigurationColorTransformerHandler MonochromeTint { // This class bridges native block invocations that call into C# // static internal class SDUIConfigurationColorTransformerHandler { +#if !NET static internal readonly DUIConfigurationColorTransformerHandler Handler = Invoke; [MonoPInvokeCallback (typeof (DUIConfigurationColorTransformerHandler))] +#else + [UnmanagedCallersOnly] +#endif static unsafe IntPtr Invoke (IntPtr block, IntPtr color) { var descriptor = (BlockLiteral*) block; diff --git a/src/UIKit/UIGuidedAccessRestriction.cs b/src/UIKit/UIGuidedAccessRestriction.cs index fbfd2cfbf9a5..63243a60915c 100644 --- a/src/UIKit/UIGuidedAccessRestriction.cs +++ b/src/UIKit/UIGuidedAccessRestriction.cs @@ -61,14 +61,22 @@ public static UIGuidedAccessRestrictionState GetState (string restrictionIdentif #endif public delegate void UIGuidedAccessConfigureAccessibilityFeaturesCompletionHandler (bool success, NSError error); +#if !NET [UnmanagedFunctionPointer (CallingConvention.Cdecl)] internal delegate void DUIGuidedAccessConfigureAccessibilityFeaturesCompletionHandler (IntPtr block, byte success, IntPtr error); +#endif static internal class UIGuidedAccessConfigureAccessibilityFeaturesTrampoline { +#if !NET static internal readonly DUIGuidedAccessConfigureAccessibilityFeaturesCompletionHandler Handler = Invoke; +#endif +#if NET + [UnmanagedCallersOnlyAttribute] +#else [MonoPInvokeCallback (typeof (DUIGuidedAccessConfigureAccessibilityFeaturesCompletionHandler))] - static unsafe void Invoke (IntPtr block, byte success, IntPtr error) +#endif + internal static unsafe void Invoke (IntPtr block, byte success, IntPtr error) { var descriptor = (BlockLiteral*) block; var del = (UIGuidedAccessConfigureAccessibilityFeaturesCompletionHandler) (descriptor->Target); @@ -91,8 +99,13 @@ public static void ConfigureAccessibilityFeatures (UIGuidedAccessAccessibilityFe throw new ArgumentNullException (nameof (completionHandler)); unsafe { +#if NET + delegate* unmanaged trampoline = &UIGuidedAccessConfigureAccessibilityFeaturesTrampoline.Invoke; + using var block = new BlockLiteral (trampoline, completionHandler, typeof (UIGuidedAccessConfigureAccessibilityFeaturesTrampoline), nameof (UIGuidedAccessConfigureAccessibilityFeaturesTrampoline.Invoke)); +#else using var block = new BlockLiteral (); block.SetupBlockUnsafe (UIGuidedAccessConfigureAccessibilityFeaturesTrampoline.Handler, completionHandler); +#endif UIGuidedAccessConfigureAccessibilityFeatures ((nuint) (ulong) features, enabled, &block); } } diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs index 7fd35b206015..6a14ed5afe2f 100644 --- a/tools/common/Driver.cs +++ b/tools/common/Driver.cs @@ -198,7 +198,7 @@ static bool ParseOptions (Application app, Mono.Options.OptionSet options, strin " remove-dynamic-registrar: By default enabled when the static registrar is enabled and the interpreter is not used. Removes the dynamic registrar (makes the app smaller).\n" + " inline-runtime-arch: By default always enabled (requires the linker). Inlines calls to ObjCRuntime.Runtime.Arch to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" + #endif - " blockliteral-setupblock: By default enabled when using the static registrar. Optimizes calls to BlockLiteral.SetupBlock to avoid having to calculate the block signature at runtime.\n" + + " blockliteral-setupblock: By default enabled when using the static registrar. Optimizes calls to BlockLiteral.SetupBlock and certain BlockLiteral constructors to avoid having to calculate the block signature at runtime.\n" + " inline-intptr-size: By default enabled for builds that target a single architecture (requires the linker). Inlines calls to IntPtr.Size to load a constant value. Makes the app smaller, and slightly faster at runtime.\n" + " inline-dynamic-registration-supported: By default always enabled (requires the linker). Optimizes calls to Runtime.DynamicRegistrationSupported to be a constant value. Makes the app smaller, and slightly faster at runtime.\n" + #if !MONOTOUCH diff --git a/tools/common/Optimizations.cs b/tools/common/Optimizations.cs index 36115add3be6..5d194c226876 100644 --- a/tools/common/Optimizations.cs +++ b/tools/common/Optimizations.cs @@ -241,7 +241,7 @@ public void Initialize (Application app, out List messages) InlineRuntimeArch = true; } - // We try to optimize calls to BlockLiteral.SetupBlock if the static registrar is enabled + // We try to optimize calls to BlockLiteral.SetupBlock and certain BlockLiteral constructors if the static registrar is enabled if (!OptimizeBlockLiteralSetupBlock.HasValue) { OptimizeBlockLiteralSetupBlock = app.Registrar == RegistrarMode.Static; } diff --git a/tools/linker/CoreOptimizeGeneratedCode.cs b/tools/linker/CoreOptimizeGeneratedCode.cs index 7bbf077cddef..2ecc709e1b2c 100644 --- a/tools/linker/CoreOptimizeGeneratedCode.cs +++ b/tools/linker/CoreOptimizeGeneratedCode.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; +using System.Linq; + using ObjCRuntime; using Mono.Cecil; using Mono.Cecil.Cil; @@ -757,6 +759,7 @@ protected override void Process (MethodDefinition method) for (int i = 0; i < instructions.Count; i++) { var ins = instructions [i]; switch (ins.OpCode.Code) { + case Code.Newobj: case Code.Call: i += ProcessCalls (method, ins); break; @@ -769,7 +772,7 @@ protected override void Process (MethodDefinition method) EliminateDeadCode (method); } - // Returns the number of instructions add (or removed). + // Returns the number of instructions added (or removed). protected virtual int ProcessCalls (MethodDefinition caller, Instruction ins) { var mr = ins.Operand as MethodReference; @@ -793,6 +796,10 @@ protected virtual int ProcessCalls (MethodDefinition caller, Instruction ins) case "SetupBlock": case "SetupBlockUnsafe": return ProcessSetupBlock (caller, ins); + case ".ctor": + if (!mr.DeclaringType.Is (Namespaces.ObjCRuntime, "BlockLiteral")) + break; + return ProcessBlockLiteralConstructor (caller, ins); } return 0; @@ -1024,6 +1031,174 @@ int ProcessSetupBlock (MethodDefinition caller, Instruction ins) return 2; } + internal static bool IsBlockLiteralCtor_Type_String (MethodDefinition md) + { + if (!md.HasParameters) + return false; + + if (md.Parameters.Count != 4) + return false; + + if (!(md.Parameters [0].ParameterType is PointerType pt) || !pt.ElementType.Is ("System", "Void")) + return false; + + if (!md.Parameters [1].ParameterType.Is ("System", "Object")) + return false; + + if (!md.Parameters [2].ParameterType.Is ("System", "Type")) + return false; + + if (!md.Parameters [3].ParameterType.Is ("System", "String")) + return false; + + return true; + } + + int ProcessBlockLiteralConstructor (MethodDefinition caller, Instruction ins) + { + if (Optimizations.OptimizeBlockLiteralSetupBlock != true) + return 0; + + // This will optimize calls to this BlockLiteral constructor: + // (void* ptr, object context, Type trampolineType, string trampolineMethod) + // by calculating the signature for the block using the last two arguments, + // and then rewrite the code to call this constructor overload instead: + // (void* ptr, object context, string signature) + // This is required to remove the dynamic registrar, because calculating the block signature + // is done in the dynamic registrar. + // + // This code is a mirror of the code in BlockLiteral.SetupBlock (to calculate the block signature). + var mr = ins.Operand as MethodReference; + if (!mr.DeclaringType.Is (Namespaces.ObjCRuntime, "BlockLiteral")) + return 0; + + var md = mr.Resolve (); + if (!IsBlockLiteralCtor_Type_String (md)) + return 0; + + string signature = null; + Instruction sequenceStart; + try { + // We need to figure out the last argument to the call to the ctor + // + // Example sequence: + // + // ldarg.0 + // ldarg.1 + // ldtoken ... + // call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle) + // ldstr ... + // newobj BlockLiteral (void*, System.Object, System.Type, System.String) + // + + // Verify 'ldstr ...' + var loadString = GetPreviousSkippingNops (ins); + if (loadString.OpCode != OpCodes.Ldstr) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadString)); + return 0; + } + + // Verify 'call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)' + var callGetTypeFromHandle = GetPreviousSkippingNops (loadString); + if (callGetTypeFromHandle.OpCode != OpCodes.Call || !(callGetTypeFromHandle.Operand is MethodReference methodOperand) || methodOperand.Name != "GetTypeFromHandle" || !methodOperand.DeclaringType.Is ("System", "Type")) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, callGetTypeFromHandle)); + return 0; + } + + // Verify 'ldtoken ...' + var loadType = GetPreviousSkippingNops (callGetTypeFromHandle); + if (loadType.OpCode != OpCodes.Ldtoken) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType)); + return 0; + } + + // Then find the type of the previous instruction + var trampolineContainerTypeReference = loadType.Operand as TypeReference; + if (trampolineContainerTypeReference is null) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, loadType.Operand)); + return 0; + } + + var trampolineContainerType = trampolineContainerTypeReference.Resolve (); + if (trampolineContainerType is null) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MM2106 /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the previous instruction was unexpected ({3}) */, caller, ins.Offset, mr.Name, trampolineContainerTypeReference)); + return 0; + } + + // Find the trampoline method + var trampolineMethodName = (string) loadString.Operand; + var trampolineMethods = trampolineContainerType.Methods.Where (v => v.Name == trampolineMethodName).ToArray (); + if (trampolineMethods.Count () != 1) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MX2106_E /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the more than one method named '{3}' was found in the type '{4}. /* Errors.MM2106 */, caller, ins.Offset, mr.Name, trampolineMethodName, trampolineContainerType.FullName)); + return 0; + } + var trampolineMethod = trampolineMethods [0]; + if (!trampolineMethod.HasParameters || trampolineMethod.Parameters.Count < 1) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MX2106_F /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' must have at least one parameter. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); + return 0; + } + + // Check that the method's first parameter is either IntPtr, void* or BlockLiteral* + var firstParameterType = trampolineMethod.Parameters [0].ParameterType; + if (firstParameterType.Is ("System", "IntPtr")) { + // ok + } else if (firstParameterType is PointerType ptrType) { + var ptrTargetType = ptrType.ElementType; + if (!(ptrTargetType.Is ("System", "Void") || ptrTargetType.Is ("ObjCRuntime", "BlockLiteral"))) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); + return 0; + } + // ok + } else { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MX2106_G /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName, firstParameterType.FullName)); + return 0; + } + + // Check that the method has [UnmanagedCallersOnly] + if (!trampolineMethod.HasCustomAttributes || !trampolineMethod.CustomAttributes.Any (v => v.AttributeType.Is ("System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute"))) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, caller, ins, Errors.MX2106_H /* Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute. */, caller, ins.Offset, mr.Name, trampolineContainerType.FullName + "::" + trampolineMethodName)); + return 0; + } + + // Calculate the block signature. + var blockSignature = true; + var parameters = new TypeReference [trampolineMethod.Parameters.Count]; + for (int p = 0; p < parameters.Length; p++) + parameters [p] = trampolineMethod.Parameters [p].ParameterType; + signature = LinkContext.Target.StaticRegistrar.ComputeSignature (trampolineMethod.DeclaringType, false, trampolineMethod.ReturnType, parameters, trampolineMethod.Resolve (), isBlockSignature: blockSignature); + + sequenceStart = loadType; + } catch (Exception e) { + ErrorHelper.Show (ErrorHelper.CreateWarning (LinkContext.App, 2106, e, caller, ins, Errors.MM2106_D, caller, ins.Offset, e.Message)); + return 0; + } + + // We got the information we need: rewrite the IL. + var instructions = caller.Body.Instructions; + var index = instructions.IndexOf (sequenceStart); + int instructionDiff = 0; + while (instructions [index] != ins) { + instructions.RemoveAt (index); + instructionDiff--; + } + // Inject the extra arguments + instructions.Insert (index, Instruction.Create (OpCodes.Ldstr, signature)); + instructionDiff++; + // Change the call to call the ctor with the string signature parameter instead + ins.Operand = GetBlockLiteralConstructor (caller, ins); + + Driver.Log (4, "Optimized call to BlockLiteral..ctor in {0} at offset {1} with signature {2}", caller, ins.Offset, signature); + return instructionDiff; + } + + static Instruction GetPreviousSkippingNops (Instruction ins) + { + do { + ins = ins.Previous; + } while (ins.OpCode == OpCodes.Nop); + return ins; + } + int ProcessIsARM64CallingConvention (MethodDefinition caller, Instruction ins) { const string operation = "inline Runtime.IsARM64CallingConvention"; @@ -1175,6 +1350,33 @@ MethodReference GetBlockSetupImpl (MethodDefinition caller, Instruction ins) return caller.Module.ImportReference (setupblock_def); } + MethodDefinition block_ctor_def; + MethodReference GetBlockLiteralConstructor (MethodDefinition caller, Instruction ins) + { + if (block_ctor_def is null) { + var type = LinkContext.GetAssembly (Driver.GetProductAssembly (LinkContext.Target.App)).MainModule.GetType (Namespaces.ObjCRuntime, "BlockLiteral"); + foreach (var method in type.Methods) { + if (!method.IsConstructor) + continue; + if (method.IsStatic) + continue; + if (!method.HasParameters || method.Parameters.Count != 3) + continue; + if (!(method.Parameters [0].ParameterType is PointerType pt) || !pt.ElementType.Is ("System", "Void")) + continue; + if (!method.Parameters [1].ParameterType.Is ("System", "Object")) + continue; + if (!method.Parameters [2].ParameterType.Is ("System", "String")) + continue; + block_ctor_def = method; + break; + } + if (block_ctor_def is null) + throw ErrorHelper.CreateError (LinkContext.App, 99, caller, ins, Errors.MX0099, $"could not find the constructor ObjCRuntime.BlockLiteral (void*, object, string)"); + } + return caller.Module.ImportReference (block_ctor_def); + } + MethodReference InflateMethod (TypeReference inflatedDeclaringType, MethodDefinition openMethod) { var git = inflatedDeclaringType as GenericInstanceType; diff --git a/tools/linker/RegistrarRemovalTrackingStep.cs b/tools/linker/RegistrarRemovalTrackingStep.cs index d9ce8b4b34b0..a224fbc4a544 100644 --- a/tools/linker/RegistrarRemovalTrackingStep.cs +++ b/tools/linker/RegistrarRemovalTrackingStep.cs @@ -122,22 +122,38 @@ bool RequiresDynamicRegistrar (AssemblyDefinition assembly, bool warnIfRequired) } break; case "BlockLiteral": + // Req 2: + // * Nobody must call BlockLiteral.SetupBlock[Unsafe]. + // * Nobody must call BlockLiteral..ctor (void*, object, Type, string) + // + // Fortunately the linker is able to rewrite: + // + // * Calls to SetupBlock[Unsafe] to call SetupBlockImpl + // * Calls to .ctor(void*, object, Type, string) to call .ctor(void*, object, string) + // + // and these overloads don't need the dynamic registrar, which means we only have + // to look in assemblies that aren't linked. + if (Annotations.GetAction (assembly) == AssemblyAction.Link && Optimizations.OptimizeBlockLiteralSetupBlock == true) + break; + switch (mr.Name) { case "SetupBlock": case "SetupBlockUnsafe": - // Req 2: Nobody must call BlockLiteral.SetupBlock[Unsafe]. - // - // Fortunately the linker is able to rewrite calls to SetupBlock[Unsafe] to call - // SetupBlockImpl (which doesn't need the dynamic registrar), which means we only have - // to look in assemblies that aren't linked. - if (Annotations.GetAction (assembly) == AssemblyAction.Link && Optimizations.OptimizeBlockLiteralSetupBlock == true) - break; - if (warnIfRequired) Warn (assembly, mr); requires = true; break; + case ".ctor": + var md = mr.Resolve () as MethodDefinition; +#if NET + requires |= Xamarin.Linker.OptimizeGeneratedCodeHandler.IsBlockLiteralCtor_Type_String (md); +#else + requires |= Xamarin.Linker.OptimizeGeneratedCodeSubStep.IsBlockLiteralCtor_Type_String (md); +#endif + if (requires && warnIfRequired) + Warn (assembly, mr); + break; } break; case "TypeConverter": diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs index d7427077d261..a23b34a1af9a 100644 --- a/tools/mtouch/Errors.designer.cs +++ b/tools/mtouch/Errors.designer.cs @@ -3931,6 +3931,51 @@ public static string MX2103 { } } + /// + /// Looks up a localized string similar to Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the more than one method named '{3}' was found in the type '{4}.. + /// + public static string MX2106_E { + get { + return ResourceManager.GetString("MX2106_E", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' must have at least one parameter.. + /// + public static string MX2106_F { + get { + return ResourceManager.GetString("MX2106_F", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}'). + /// + public static string MX2106_G { + get { + return ResourceManager.GetString("MX2106_G", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute.. + /// + public static string MX2106_H { + get { + return ResourceManager.GetString("MX2106_H", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute.. + /// + public static string MX2106_I { + get { + return ResourceManager.GetString("MX2106_I", resourceCulture); + } + } + /// /// Looks up a localized string similar to Can not find the corlib assembly '{0}' in the list of loaded assemblies. /// . @@ -4149,5 +4194,68 @@ public static string MX8045 { return ResourceManager.GetString("MX8045", resourceCulture); } } + + /// + /// Looks up a localized string similar to Unable to find the method '{0}' in the type '{1}'. + /// + public static string MX8046 { + get { + return ResourceManager.GetString("MX8046", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The trampoline method {0} does not match the function pointer 0x{1} for the trampolineMethod argument (they're don't refer to the same method).. + /// + public static string MX8047 { + get { + return ResourceManager.GetString("MX8047", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The trampoline method {0} must have at least one parameter.. + /// + public static string MX8048 { + get { + return ResourceManager.GetString("MX8048", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The first parameter in the trampoline method {0} must be either 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*'.. + /// + public static string MX8049 { + get { + return ResourceManager.GetString("MX8049", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BlockLiteral.GetBlockSignature is not supported when the dynamic registrar has been linked away.. + /// + public static string MX8050 { + get { + return ResourceManager.GetString("MX8050", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The trampoline method {0} must have an [UnmanagedCallersOnly] attribute.. + /// + public static string MX8051 { + get { + return ResourceManager.GetString("MX8051", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The signature must be a non-empty string.. + /// + public static string MX8052 { + get { + return ResourceManager.GetString("MX8052", resourceCulture); + } + } } } diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx index 2dcc876e48a6..45687cea40f4 100644 --- a/tools/mtouch/Errors.resx +++ b/tools/mtouch/Errors.resx @@ -1298,7 +1298,27 @@ Could not optimize the call to BlockLiteral.SetupBlock in {0} at offset {1}: {2}. + + + Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the more than one method named '{3}' was found in the type '{4}. + + + Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' must have at least one parameter. + + + + Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the first parameter in the method '{3}' isn't 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*' (it's '{4}') + + + + Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute. + + + + Could not optimize the call to BlockLiteral.{2} in {0} at offset {1} because the method '{3}' does not have an [UnmanagedCallersOnly] attribute. + + It's not safe to remove the dynamic registrar, because {0} references '{1}.{2} ({3})'. @@ -2191,4 +2211,33 @@ Unable to call release on an instance of the type {0} + + + Unable to find the method '{0}' in the type '{1}' + + + + The trampoline method {0} does not match the function pointer 0x{1} for the trampolineMethod argument (they're don't refer to the same method). + + + + The trampoline method {0} must have at least one parameter. + + + + The first parameter in the trampoline method {0} must be either 'System.IntPtr', 'void*' or 'ObjCRuntime.BlockLiteral*'. + + + + BlockLiteral.GetBlockSignature is not supported when the dynamic registrar has been linked away. + + + + The trampoline method {0} must have an [UnmanagedCallersOnly] attribute. + + + + The signature must be a non-empty string. + +