Skip to content

Commit

Permalink
Merge branch 'main' into xcode15.3-bump
Browse files Browse the repository at this point in the history
  • Loading branch information
dalexsoto authored Jun 3, 2024
2 parents 48c1384 + 5557fa3 commit 4d89290
Show file tree
Hide file tree
Showing 78 changed files with 3,150 additions and 316 deletions.
79 changes: 76 additions & 3 deletions docs/objective-c-protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ breaking changes (which happens very rarely).
### Static members

Objective-C protocols can have static members. C# didn't allow for static
members in interfaces until C# 11, so until recently there hasn't been any
good way to bind static protocol members on a protocol.
members in interfaces until C# 11, so there wasn't any good way to bind static
protocol members on a protocol.

Our workaround is to manually inline every static member in all classes that
Our workaround was to manually inline every static member in all classes that
implemented a given protocol.

### Initializers
Expand All @@ -62,6 +62,79 @@ ignored them.

## Binding in C#

### Static members

Given the following API definition:

```cs
[Protocol]
public interface Protocol {
[Abstract]
[Static]
[Export ("requiredStaticMethod")]
void RequiredStaticMethod ();

[Static]
[Export ("optionalStaticMethod")]
void OptionalStaticMethod ();

[Abstract]
[Static]
[Export ("requiredStaticProperty")]
IntPtr RequiredStaticProperty { get; set; }

[Static]
[Export ("optionalStaticProperty")]
IntPtr OptionalStaticProperty { get; set; }
}
```

we're binding it like this:

```cs
[Protocol ("Protocol")]
public interface IProtocol : INativeObject {
[Export ("requiredStaticMethod")]
public static void RequiredStaticMethod<T> () where T: NSObject, IProtocol { /* implementation */ }

[Export ("optionalStaticMethod")]
public static void OptionalStaticMethod<T> () where T: NSObject, IProtocol { /* implementation */ }

[Property ("RequiredStaticProperty")]
[Export ("requiredStaticProperty")]
public static IntPtr GetRequiredStaticProperty<T> () where T: NSObject, IProtocol { /* implementation */ }

[Property ("RequiredStaticProperty")]
[Export ("setRequiredStaticProperty:")]
public static void SetRequiredStaticProperty<T> (IntPtr value) where T: NSObject, IProtocol { /* implementation */ }

[Property ("OptionalStaticProperty")]
[Export ("optionalStaticProperty")]
public static IntPtr GetOptionalStaticProperty<T> () where T: NSObject, IProtocol { /* implementation */ }

[Property ("OptionalStaticProperty")]
[Export ("setOptionalStaticProperty:")]
public static void SetOptionalStaticProperty<T> (IntPtr value) where T: NSObject, IProtocol { /* implementation */ }
}
```

There are three points of interest here:

1. Each method has a generic type argument that specifies which type's static
member should be called.
2. Properties have been turned into a pair of Get/Set methods - this is because
properties can't have type arguments the way methods can.
3. There's no difference between optional and required members.

Example consuming code:

```cs
public class MyClass : NSObject, IProtocol {}

// Call a required method:
IProtocol.RequiredStaticMethod<MyClass> ();
```

### Initializers

Given the following API definition:
Expand Down
10 changes: 8 additions & 2 deletions docs/preview-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ References:
* https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute?view=net-8.0
* https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/preview-apis#experimentalattribute

## Placeholder header for APL####
## CryptoTokenKit (APL0001)

Coming soon!
CryptoTokenKit requires special hardware to test, so it's not trivial for us to do so.
Thus we need customer input in order to validate the API, and as such we mark every
type in this framework as preview API for a while.

We've tentatively set .NET 10 as the release when we'll stop marking CryptoTokenKit as preview API.

The diagnostic id for CryptoTokenKit is APL0001.

[1]: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute?view=net-8.0
4 changes: 2 additions & 2 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
<Uri>https://github.com/dotnet/templating</Uri>
<Sha />
</Dependency>
<Dependency Name="Microsoft.DotNet.XHarness.iOS.Shared" Version="9.0.0-prerelease.24256.1">
<Dependency Name="Microsoft.DotNet.XHarness.iOS.Shared" Version="9.0.0-prerelease.24270.4">
<Uri>https://github.com/dotnet/xharness</Uri>
<Sha>62a8662088425e03f7ba44a4ec817c198e38d0f9</Sha>
<Sha>8478d1a9a531e6b1cd26fb8c86400e2efbb8f2f3</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<MicrosoftNETRuntimeMonoTargetsSdkPackageVersion>8.0.0</MicrosoftNETRuntimeMonoTargetsSdkPackageVersion>
<MicrosoftTemplateEngineTasksVersion>7.0.100-alpha.1.21601.1</MicrosoftTemplateEngineTasksVersion>
<MicrosoftDotNetCecilPackageVersion>0.11.4-alpha.23509.2</MicrosoftDotNetCecilPackageVersion>
<MicrosoftDotNetXHarnessiOSSharedPackageVersion>9.0.0-prerelease.24256.1</MicrosoftDotNetXHarnessiOSSharedPackageVersion>
<MicrosoftDotNetXHarnessiOSSharedPackageVersion>9.0.0-prerelease.24270.4</MicrosoftDotNetXHarnessiOSSharedPackageVersion>
<!-- Manually updated versions -->
<Emscriptennet7WorkloadVersion>$(MicrosoftNETWorkloadEmscriptenCurrentManifest80100Version)</Emscriptennet7WorkloadVersion>
<EmscriptenWorkloadVersion>$(MicrosoftNETWorkloadEmscriptenCurrentManifest80100Version)</EmscriptenWorkloadVersion>
Expand Down
7 changes: 7 additions & 0 deletions runtime/coreclr-bridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -1174,4 +1174,11 @@
return rv;
}

void
xamarin_bridge_raise_unhandled_exception_event (GCHandle exception_gchandle)
{
// There's no way to raise the AppDomain.UnhandledException event.
// https://github.com/dotnet/runtime/issues/102730
}

#endif // CORECLR_RUNTIME
6 changes: 6 additions & 0 deletions runtime/exports.t4
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@
XamarinRuntime = RuntimeMode.MonoVM,
},

new Export ("void", "mono_unhandled_exception",
"MonoObject *", "ex"
) {
XamarinRuntime = RuntimeMode.MonoVM,
},

new Export ("char*", "mono_array_addr_with_size",
"MonoArray *", "array",
"int", "size",
Expand Down
7 changes: 7 additions & 0 deletions runtime/monovm-bridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -563,4 +563,11 @@
mono_profiler_install_gc (gc_event_callback, NULL);
}

void
xamarin_bridge_raise_unhandled_exception_event (GCHandle exception_gchandle)
{
MonoObject *exc = xamarin_gchandle_get_target (exception_gchandle);
mono_unhandled_exception (exc);
}

#endif // !CORECLR_RUNTIME
33 changes: 10 additions & 23 deletions runtime/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,16 @@ -(void) xamarinSetFlags: (enum XamarinGCHandleFlags) flags;
// COOP: We won't get here in coop-mode, because we don't set the uncaught objc exception handler in that case.
LOG (PRODUCT ": Received unhandled ObjectiveC exception: %@ %@", [exc name], [exc reason]);

XamarinGCHandle* exc_handle = [[exc userInfo] objectForKey: @"XamarinManagedExceptionHandle"];
if (exc_handle != NULL) {
GCHandle exception_gchandle = [exc_handle getHandle];
if (exception_gchandle != INVALID_GCHANDLE) {
xamarin_bridge_raise_unhandled_exception_event (exception_gchandle);
PRINT ("Received unhandled Objective-C exception that was marshalled from a managed exception: %@", exc);
abort ();
}
}

if (xamarin_handling_unhandled_exceptions == 1) {
PRINT ("Detected recursion when handling uncaught Objective-C exception: %@", exc);
abort ();
Expand Down Expand Up @@ -1753,29 +1763,6 @@ -(void) xamarinSetFlags: (enum XamarinGCHandleFlags) flags;
*
*/
//#define DEBUG_REF_COUNTING
void
xamarin_create_gchandle (id self, void *managed_object, enum XamarinGCHandleFlags flags, bool force_weak)
{
// COOP: reads managed memory: unsafe mode
MONO_ASSERT_GC_UNSAFE;

// force_weak is to avoid calling retainCount unless needed, since some classes (UIWebView in iOS 5)
// will crash if retainCount is called before init. See bug #9261.
bool weak = force_weak || ([self retainCount] == 1);
GCHandle gchandle;

if (weak) {
gchandle = xamarin_gchandle_new_weakref ((MonoObject *) managed_object, TRUE);
flags = (enum XamarinGCHandleFlags) (flags | XamarinGCHandleFlags_WeakGCHandle);
} else {
gchandle = xamarin_gchandle_new ((MonoObject *) managed_object, FALSE);
flags = (enum XamarinGCHandleFlags) (flags & ~XamarinGCHandleFlags_WeakGCHandle);
}
set_gchandle (self, gchandle, flags);
#if defined(DEBUG_REF_COUNTING)
PRINT ("\tGCHandle created for %p: %d (flags: %p) = %s managed object: %p\n", self, gchandle, GINT_TO_POINTER (flags), weak ? "weak" : "strong", managed_object);
#endif
}

void
xamarin_switch_gchandle (id self, bool to_weak)
Expand Down
2 changes: 1 addition & 1 deletion runtime/xamarin/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ void xamarin_bridge_call_runtime_initialize (struct InitializationOptions* opt
void xamarin_bridge_register_product_assembly (GCHandle* exception_gchandle);
MonoMethod * xamarin_bridge_get_mono_method (MonoReflectionMethod *method);
void xamarin_bridge_free_mono_signature (MonoMethodSignature **signature);
void xamarin_bridge_raise_unhandled_exception_event (GCHandle exception_gchandle); // the GCHandle is *not* freed. This method will return after raising the event.
bool xamarin_register_monoassembly (MonoAssembly *assembly, GCHandle *exception_gchandle);
void xamarin_install_nsautoreleasepool_hooks ();
void xamarin_enable_new_refcount ();
Expand All @@ -239,7 +240,6 @@ void xamarin_clear_gchandle (id self);
GCHandle xamarin_get_gchandle_with_flags (id self, enum XamarinGCHandleFlags *flags);
bool xamarin_set_gchandle_with_flags (id self, GCHandle gchandle, enum XamarinGCHandleFlags flags);
bool xamarin_set_gchandle_with_flags_safe (id self, GCHandle gchandle, enum XamarinGCHandleFlags flags);
void xamarin_create_gchandle (id self, void *managed_object, enum XamarinGCHandleFlags flags, bool force_weak);
void xamarin_release_managed_ref (id self, bool user_type);
void xamarin_notify_dealloc (id self, GCHandle gchandle);
void xamarin_release_static_dictionaries ();
Expand Down
21 changes: 21 additions & 0 deletions src/AppKit/NSPasteboardReading.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#if !__MACCATALYST__

using System;

using Foundation;
using ObjCRuntime;

#nullable enable

#if NET
namespace AppKit {
public partial interface INSPasteboardReading {
[BindingImpl (BindingImplOptions.Optimizable)]
public unsafe static T? CreateInstance<T> (NSObject propertyList, NSPasteboardType type) where T: NSObject, INSPasteboardReading
{
return CreateInstance<T> (propertyList, type.GetConstant ()!);
}
}
}
#endif // NET
#endif // !__MACCATALYST__
1 change: 1 addition & 0 deletions src/Foundation/NSObject.mac.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public partial class NSObject {
static IntPtr ni = Dlfcn.dlopen (Constants.NearbyInteractionLibrary, 1);
static IntPtr sm = Dlfcn.dlopen (Constants.ServiceManagementLibrary, 1);
static IntPtr sa = Dlfcn.dlopen (Constants.SafetyKitLibrary, 1);
static IntPtr cr = Dlfcn.dlopen (Constants.CryptoTokenKitLibrary, 1);

#if !NET
[Obsolete ("Use PlatformAssembly for easier code sharing across platforms.")]
Expand Down
4 changes: 2 additions & 2 deletions src/Network/NWConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ static void TrampolineSendCompletion (IntPtr block, IntPtr error)
static extern unsafe void nw_connection_send (IntPtr handle,
IntPtr dispatchData,
IntPtr contentContext,
[MarshalAs (UnmanagedType.U1)] bool isComplete,
byte isComplete,
BlockLiteral* callback);

//
Expand All @@ -511,7 +511,7 @@ unsafe void LowLevelSend (IntPtr handle, DispatchData? buffer, IntPtr contentCon
nw_connection_send (handle: GetCheckedHandle (),
dispatchData: buffer.GetHandle (),
contentContext: contentContext,
isComplete: isComplete,
isComplete: isComplete.AsByte (),
callback: callback);
}

Expand Down
11 changes: 5 additions & 6 deletions src/Network/NWConnectionGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ 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);
unsafe static extern void nw_connection_group_set_receive_handler (OS_nw_connection_group group, uint maximum_message_size, byte reject_oversized_messages, BlockLiteral* handler);

#if !NET
delegate void nw_connection_group_receive_handler_t (IntPtr block, IntPtr content, IntPtr context, byte isCompleted);
Expand All @@ -259,7 +259,7 @@ public void SetReceiveHandler (uint maximumMessageSize, bool rejectOversizedMess
{
unsafe {
if (handler is null) {
nw_connection_group_set_receive_handler (GetCheckedHandle (), maximumMessageSize, rejectOversizedMessages, null);
nw_connection_group_set_receive_handler (GetCheckedHandle (), maximumMessageSize, rejectOversizedMessages.AsByte (), null);
return;
}

Expand All @@ -270,7 +270,7 @@ public void SetReceiveHandler (uint maximumMessageSize, bool rejectOversizedMess
using var block = new BlockLiteral ();
block.SetupBlockUnsafe (static_ReceiveHandler, handler);
#endif
nw_connection_group_set_receive_handler (GetCheckedHandle (), maximumMessageSize, rejectOversizedMessages, &block);
nw_connection_group_set_receive_handler (GetCheckedHandle (), maximumMessageSize, rejectOversizedMessages.AsByte (), &block);
}
}

Expand Down Expand Up @@ -432,8 +432,7 @@ public void SetStateChangedHandler (NWConnectionGroupStateChangedDelegate handle
[MacCatalyst (15, 0)]
#endif
[DllImport (Constants.NetworkLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
static extern bool nw_connection_group_reinsert_extracted_connection (OS_nw_connection_group group, OS_nw_connection connection);
static extern byte nw_connection_group_reinsert_extracted_connection (OS_nw_connection_group group, OS_nw_connection connection);

#if NET
[SupportedOSPlatform ("tvos15.0")]
Expand All @@ -451,7 +450,7 @@ public bool TryReinsertExtractedConnection (NWConnection connection)
{
if (connection is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (connection));
return nw_connection_group_reinsert_extracted_connection (GetCheckedHandle (), connection.Handle);
return nw_connection_group_reinsert_extracted_connection (GetCheckedHandle (), connection.Handle) != 0;
}

#if NET
Expand Down
9 changes: 4 additions & 5 deletions src/Network/NWContentContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,14 @@ public NWContentContext (string contextIdentifier)
public string? Identifier => Marshal.PtrToStringAnsi (nw_content_context_get_identifier (GetCheckedHandle ()));

[DllImport (Constants.NetworkLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
extern static bool nw_content_context_get_is_final (IntPtr handle);
extern static byte nw_content_context_get_is_final (IntPtr handle);

[DllImport (Constants.NetworkLibrary)]
extern static void nw_content_context_set_is_final (IntPtr handle, [MarshalAs (UnmanagedType.I1)] bool is_final);
extern static void nw_content_context_set_is_final (IntPtr handle, byte is_final);

public bool IsFinal {
get => nw_content_context_get_is_final (GetCheckedHandle ());
set => nw_content_context_set_is_final (GetCheckedHandle (), value);
get => nw_content_context_get_is_final (GetCheckedHandle ()) != 0;
set => nw_content_context_set_is_final (GetCheckedHandle (), value.AsByte ());
}

[DllImport (Constants.NetworkLibrary)]
Expand Down
5 changes: 3 additions & 2 deletions src/Network/NWEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static string nw_endpoint_copy_address_string (OS_nw_endpoint endpoint)
[Watch (9, 0)]
#endif
[DllImport (Constants.NetworkLibrary)]
static extern unsafe byte* nw_endpoint_get_signature (OS_nw_endpoint endpoint, out nuint out_signature_length);
static extern unsafe byte* nw_endpoint_get_signature (OS_nw_endpoint endpoint, nuint* out_signature_length);

#if NET
[SupportedOSPlatform ("tvos16.0")]
Expand All @@ -227,7 +227,8 @@ static string nw_endpoint_copy_address_string (OS_nw_endpoint endpoint)
public ReadOnlySpan<byte> Signature {
get {
unsafe {
var data = nw_endpoint_get_signature (GetCheckedHandle (), out var length);
nuint length;
var data = nw_endpoint_get_signature (GetCheckedHandle (), &length);
var mValue = new ReadOnlySpan<byte> (data, (int) length);
// we do not know who manages the byte array, so we return a copy, is more expensive but
// safer until we know what is the mem management.
Expand Down
10 changes: 4 additions & 6 deletions src/Network/NWEstablishmentReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,14 @@ public class NWEstablishmentReport : NativeObject {
internal NWEstablishmentReport (NativeHandle handle, bool owns) : base (handle, owns) { }

[DllImport (Constants.NetworkLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
static extern bool nw_establishment_report_get_used_proxy (OS_nw_establishment_report report);
static extern byte nw_establishment_report_get_used_proxy (OS_nw_establishment_report report);

public bool UsedProxy => nw_establishment_report_get_used_proxy (GetCheckedHandle ());
public bool UsedProxy => nw_establishment_report_get_used_proxy (GetCheckedHandle ()) != 0;

[DllImport (Constants.NetworkLibrary)]
[return: MarshalAs (UnmanagedType.I1)]
static extern bool nw_establishment_report_get_proxy_configured (OS_nw_establishment_report report);
static extern byte nw_establishment_report_get_proxy_configured (OS_nw_establishment_report report);

public bool ProxyConfigured => nw_establishment_report_get_proxy_configured (GetCheckedHandle ());
public bool ProxyConfigured => nw_establishment_report_get_proxy_configured (GetCheckedHandle ()) != 0;

[DllImport (Constants.NetworkLibrary)]
static extern uint nw_establishment_report_get_previous_attempt_count (OS_nw_establishment_report report);
Expand Down
Loading

0 comments on commit 4d89290

Please sign in to comment.