Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2ca5032
[dotnet-linker] Only override `NSObjectProxyAttribute.LookupUnmanaged…
rolfbjarne Aug 5, 2026
26355fb
Bump zizmorcore/zizmor-action from 0.6.0 to 0.6.1 (#26404)
dependabot[bot] Aug 5, 2026
0d9d023
[dotnet] Make trimmable-static the default registrar for CoreCLR too …
rolfbjarne Aug 5, 2026
3d00dc0
[docs] Improve XML docs for ten types (#26407)
rolfbjarne Aug 5, 2026
a26e2d4
[linker] Convert the EnsureUIThread optimization to a trimmer feature…
rolfbjarne Aug 5, 2026
c0f5924
[runtime] Fix the alloc/init handle-reuse race in object_map (issue #…
rolfbjarne Aug 6, 2026
5a3e485
[docs] Improve XML docs for ten types (#26415)
rolfbjarne Aug 6, 2026
111d59a
[tools] Report warnings as warnings in ErrorHelper.ShowInternal. (#26…
rolfbjarne Aug 6, 2026
0d1ec8c
[dotnet-linker] Relocate generic registrar trampolines into the compa…
rolfbjarne Aug 6, 2026
f7920a5
[CI] Retry simulator runtime downloads on transient network failures.…
rolfbjarne Aug 6, 2026
e4325ae
[mono-api-html] Fix placeholder leak and add a test project (#26405)
rolfbjarne Aug 6, 2026
ed5bb66
[registrar] Import the framework for NSObject types used in method si…
rolfbjarne Aug 6, 2026
4aa288a
[docs] Improve XML docs for ten types (#26419)
rolfbjarne Aug 6, 2026
ac39de2
[net11.0] Merge main into net11.0.
rolfbjarne Aug 7, 2026
0f3d9fe
[tests] Update expected sizes.
rolfbjarne Aug 7, 2026
ac20de8
[dotnet] Fix merge conflict resolution failure wrt UseMonoRuntime.
rolfbjarne Aug 7, 2026
00c155b
[dotnet-linker] Import the type into the current assembly for Dynamic…
rolfbjarne Aug 7, 2026
26ebd80
[assembly-preparer] Fix the assembly action computed for TrimMode=link.
rolfbjarne Aug 7, 2026
74a95d8
[assembly-preparer] Pass the computed DynamicRegistrationSupported va…
rolfbjarne Aug 7, 2026
df894ca
[assembly-preparer] Port RemoveAttributesStep to the assembly-preparer.
rolfbjarne Aug 7, 2026
ccf71f1
[assembly-preparer] Remove TypeMapAssemblyTarget attributes pointing …
rolfbjarne Aug 7, 2026
7cfa209
[tests] Define PREPARE_ASSEMBLIES whenever the assembly-preparer is u…
rolfbjarne Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ jobs:
echo "files=$files" >> "$GITHUB_OUTPUT"

- name: Run zizmor
uses: zizmorcore/zizmor-action@6599ee8b7a49aef6a770f63d261d214911a7ce02 # v0.6.0
uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1
with:
inputs: ${{ steps.find-files.outputs.files }}
21 changes: 21 additions & 0 deletions docs/building-apps/build-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,27 @@ The default value of this property `false` in .NET 9, and `true` in .NET 10+.
> [!NOTE]
> File an issue if you find that you need to disable this feature, as it's possible that the option to disable it will be removed in future.

## CheckForIllegalCrossThreadCalls

Controls whether the UI thread checks (the `[NS|UI]Application.EnsureUIThread`
calls the generated bindings emit for UI code) are performed.

When set to `true`, the checks are enabled: accessing UI API off the UI thread
throws an exception. When set to `false`, the checks are disabled.

This property is emitted as the `ObjCRuntime.Runtime.CheckForIllegalCrossThreadCalls`
runtime feature switch, so it takes effect even when trimming is disabled: the
`[NS|UI]Application.CheckForIllegalCrossThreadCalls` field reflects the property
value at runtime, and the checks are enabled or disabled accordingly.

When trimming is enabled and the checks are disabled, ILLink additionally stubs
the `[NS|UI]Application.EnsureUIThread` method body and trims away the
`CheckForIllegalCrossThreadCalls` field, making the app slightly smaller and
faster.

If this value is not specified, the checks are kept in debug builds and removed
in release builds.

## CodesignAllocate

The path to the `codesign_allocate` tool.
Expand Down
13 changes: 10 additions & 3 deletions docs/website/optimizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@ Xamarin.iOS and Xamarin.Mac apps.

## Remove UIApplication.EnsureUIThread / NSApplication.EnsureUIThread

Removes calls to [UIApplication.EnsureUIThread][1] (for Xamarin.iOS) or
`NSApplication.EnsureUIThread` (for Xamarin.Mac).
> [!NOTE]
> This optimization has been replaced by the `CheckForIllegalCrossThreadCalls`
> MSBuild property, which sets the
> `ObjCRuntime.Runtime.CheckForIllegalCrossThreadCalls` trimmer feature switch.
> The `--optimize=[+|-]remove-uithread-checks` flag is no longer applied and has
> no effect.

Removes calls to [UIApplication.EnsureUIThread][1] (for .NET for iOS) or
`NSApplication.EnsureUIThread` (for .NET for macOS).

This optimization will change the following type of code:

Expand All @@ -43,7 +50,7 @@ methods with the `[BindingImpl (BindingImplOptions.Optimizable)]` attribute.

By default it's enabled for release builds.

The default behavior can be overridden by passing `--optimize=[+|-]remove-uithread-checks` to mtouch/mmp.
Set the `CheckForIllegalCrossThreadCalls` MSBuild property to override the default behavior.

[1]: /dotnet/api/UIKit.UIApplication.EnsureUIThread

Expand Down
51 changes: 32 additions & 19 deletions dotnet/targets/Xamarin.Shared.Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,48 @@
<_UseNativeAot Condition="'$(PublishAot)' == 'true' And '$(_IsPublishing)' == 'true'">true</_UseNativeAot>

<!--
On .NET 11+, make the trimmable-static registrar the default for NativeAOT (it used to be
managed-static). This has to be set here, at evaluation time, and not only in the SelectRegistrar
target (which runs later), because the static _SkipILLink / _PostprocessAssembliesAfterIlc gates
check the registrar at evaluation time.

This is deliberately scoped to NativeAOT: the trimmable-static registrar only produces a *smaller*
app under NativeAOT (where the TypeMap feature and the post-ILC registrar reorder let us trim the
registered binding surface). On Mono/CoreCLR the trimmable-static registrar keeps the whole
registered NSObject surface and makes apps 2-3x *larger*, so those runtimes keep managed-static.
These have to be computed here, before the registrar defaults below, because those check
$(UseMonoRuntime) at evaluation time.
-->
<Registrar Condition="'$(Registrar)' == '' And '$(_UseNativeAot)' == 'true' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">trimmable-static</Registrar>
<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == ''">false</UseMonoRuntime>

<!--
Enable the PrepareAssemblies flow by default for NativeAOT on .NET 11+. This runs our custom linker
steps in the assembly-preparer, and for the (NativeAOT-default) trimmable-static registrar it also
generates the native static registrar code *after* the NativeAOT compiler (ILC) has run (see
_PostprocessAssembliesAfterIlc), so the registrar can drop the native code for UnmanagedCallersOnly
trampolines ILC trimmed away (an app-size optimization).
On .NET 11+, make the trimmable-static registrar the default for both CoreCLR and NativeAOT (it used
to be managed-static, and before that the trimmable-static registrar was only the default for
NativeAOT). This has to be set here, at evaluation time, and not only in the SelectRegistrar target
(which runs later), because the static _SkipILLink / _PostprocessAssembliesAfterIlc gates check the
registrar at evaluation time.

Mono keeps the managed-static registrar.
-->
<PrepareAssemblies Condition="'$(PrepareAssemblies)' == '' And '$(_UseNativeAot)' == 'true' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">true</PrepareAssemblies>
<Registrar Condition="'$(Registrar)' == '' And '$(UseMonoRuntime)' != 'true' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">trimmable-static</Registrar>

<!--
Enable the PrepareAssemblies flow by default for CoreCLR and NativeAOT on .NET 11+. This runs our
custom linker steps in the assembly-preparer. For NativeAOT it additionally generates the native
static registrar code *after* the NativeAOT compiler (ILC) has run (see
_PostprocessAssembliesAfterIlc, which is NativeAOT-only), so the registrar can drop the native code
for the UnmanagedCallersOnly trampolines ILC trimmed away (an app-size optimization).

This is *required* for the trimmable-static registrar to produce a small app: the assembly-preparer
writes the generated type map assemblies to disk (marked with [AssemblyMetadata ("IsTrimmable", "True")])
before the trimmer runs, so the trimmer treats them as ordinary trimmable input assemblies. Without it
the type map assemblies are created from inside the trimmer, where they end up with the 'copy' assembly
action - which means they're not trimmed, and since they reference every Objective-C type in the app,
nothing else can be trimmed either (that made apps ~3x larger).

The $(Registrar) check means a CoreCLR app that explicitly opts back in to the managed-static
registrar doesn't get PrepareAssemblies enabled - that combination makes apps *larger*. NativeAOT
always gets PrepareAssemblies regardless of the registrar, which is the pre-existing behavior.
-->
<PrepareAssemblies Condition="'$(PrepareAssemblies)' == '' And '$(UseMonoRuntime)' != 'true' And ('$(_UseNativeAot)' == 'true' Or '$(Registrar)' == 'trimmable-static') And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">true</PrepareAssemblies>

<!--
PostProcessAssemblies defaults to $(PrepareAssemblies) (see Xamarin.Shared.targets), but the static
_PostprocessAssembliesAfterIlc gate reads it at evaluation time - earlier than that default runs - so
apply the same $(PrepareAssemblies) default here too, otherwise the gate wouldn't see it.
-->
<PostProcessAssemblies Condition="'$(PostProcessAssemblies)' == '' And '$(_UseNativeAot)' == 'true' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">$(PrepareAssemblies)</PostProcessAssemblies>

<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == ''">false</UseMonoRuntime>
<PostProcessAssemblies Condition="'$(PostProcessAssemblies)' == '' And '$(UseMonoRuntime)' != 'true' And ('$(_UseNativeAot)' == 'true' Or '$(Registrar)' == 'trimmable-static') And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">$(PrepareAssemblies)</PostProcessAssemblies>

<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)Microsoft.$(_PlatformName).Sdk.targets</AfterMicrosoftNETSdkTargets>

Expand Down
16 changes: 13 additions & 3 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,8 @@
- NativeAOT supported platforms in all configurations
- ios/tvos device builds in all configurations
- macOS/MacCatalyst builds in release configuration
(On .NET 11+ NativeAOT defaults to 'trimmable-static' instead - that's set earlier, at
evaluation time, in Xamarin.Shared.Sdk.props. The trimmable-static registrar is only smaller
under NativeAOT, so the other runtimes keep managed-static.)
(On .NET 11+ CoreCLR and NativeAOT default to 'trimmable-static' instead - that's set earlier,
at evaluation time, in Xamarin.Shared.Sdk.props. Mono keeps managed-static.)
- Set 'partial-static' for:
- when no assemblies are trimmed and when MarshalManagedExceptionMode is default (or not set)
- Otherwise set 'dynamic'
Expand Down Expand Up @@ -795,6 +794,15 @@
<!-- Set default ValidateObjectPointers value -->
<_ValidateObjectPointers Condition="'$(_ValidateObjectPointers)' == ''">false</_ValidateObjectPointers>

<!--
Set the 'ObjCRuntime.Runtime.CheckForIllegalCrossThreadCalls' feature switch value. When false, ILLink stubs
the [NS|UI]Application.EnsureUIThread method body (so the UI thread checks are removed). A user-specified
$(CheckForIllegalCrossThreadCalls) always wins; otherwise we keep the checks in debug builds and remove them in
release builds (matching the old 'remove-uithread-checks' optimization default).
-->
<_CheckForIllegalCrossThreadCalls Condition="'$(CheckForIllegalCrossThreadCalls)' != ''">$(CheckForIllegalCrossThreadCalls)</_CheckForIllegalCrossThreadCalls>
<_CheckForIllegalCrossThreadCalls Condition="'$(_CheckForIllegalCrossThreadCalls)' == ''">$(_BundlerDebug)</_CheckForIllegalCrossThreadCalls>

<_CustomLinkerOptions>
AreAnyAssembliesTrimmed=$(_AreAnyAssembliesTrimmed)
AssemblyName=$(AssemblyName).dll
Expand Down Expand Up @@ -948,6 +956,7 @@
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsCoreCLR" Value="true" Trim="true" Condition="'$(UseMonoRuntime)' != 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsCoreCLR" Value="false" Trim="true" Condition="'$(UseMonoRuntime)' == 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Class.ValidateObjectPointers" Value="$(_ValidateObjectPointers)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.CheckForIllegalCrossThreadCalls" Value="$(_CheckForIllegalCrossThreadCalls)" Trim="true" />

<!-- Configure System.Net.Http Native Handlers -->
<RuntimeHostConfigurationOption Include="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" Value="$(_IsNSUrlSessionHandlerFeature)" Trim="true" />
Expand Down Expand Up @@ -1437,6 +1446,7 @@
>
<PrepareAssemblies
InputAssemblies="@(_AssembliesToPostProcess)"
DynamicRegistrationSupported="$(_DynamicRegistrationSupported)"
MakeReproPath="$(_PostprocessAssembliesMakeReproPath)"
NativeAOTObjectFile="$(NativeObject)"
OptionsFile="$(_CustomLinkerOptionsFile)"
Expand Down
12 changes: 12 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public class PrepareAssemblies : XamarinTask {

public string MakeReproPath { get; set; } = "";

// The value of the $(_DynamicRegistrationSupported) MSBuild property. During post-processing this is
// how the value RegistrarRemovalTrackingStep computed during the preparation pass is passed back to
// the assembly-preparer (the native main file is generated during post-processing, and it must agree
// with the managed side about whether the dynamic registrar is available).
public string DynamicRegistrationSupported { get; set; } = "";

public string OutputDirectory { get; set; } = "";

[Required]
Expand Down Expand Up @@ -77,6 +83,12 @@ public override bool Execute ()
using var preparer = new AssemblyPreparer (this, infos, OptionsFile?.ItemSpec ?? "");
preparer.MakeReproPath = MakeReproPath;
preparer.PreTrimAssemblies.AddRange (PreTrimAssemblies.Select (v => v.ItemSpec));

if (!string.IsNullOrEmpty (DynamicRegistrationSupported)) {
var dynamicRegistrationSupported = string.Equals (DynamicRegistrationSupported, "true", StringComparison.OrdinalIgnoreCase);
preparer.Configuration.DynamicRegistrationSupported = dynamicRegistrationSupported;
preparer.Configuration.Application.Optimizations.RemoveDynamicRegistrar = !dynamicRegistrationSupported;
}
bool rv;
List<ProductException> exceptions;

Expand Down
1 change: 1 addition & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3750,6 +3750,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
>
<PrepareAssemblies
InputAssemblies="@(_AssembliesToPostProcess)"
DynamicRegistrationSupported="$(_DynamicRegistrationSupported)"
MakeReproPath="$(_PostprocessAssembliesMakeReproPath)"
OptionsFile="$(_CustomLinkerOptionsFile)"
OutputDirectory="$(_PostprocessedAssembliesDirectory)"
Expand Down
9 changes: 4 additions & 5 deletions src/AVFoundation/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,12 @@ public enum AVAudioSessionInterruptionOptions : ulong {
}

/// <summary>An enumeration whose values define whether, after an audio session deactivates, previously interrupted audio sessions should or should not re-activate.</summary>
/// <remarks>To be added.</remarks>
[MacCatalyst (13, 1)]
[Flags]
[Native]
// NSUInteger - AVAudioSession.h
public enum AVAudioSessionSetActiveOptions : ulong {
/// <summary>To be added.</summary>
/// <summary>Notifies other audio sessions that they can resume when this session deactivates.</summary>
NotifyOthersOnDeactivation = 1,
}

Expand Down Expand Up @@ -1148,11 +1147,10 @@ public enum AVCaptureColorSpace : long {
}

/// <summary>Enumerates loop count limits.</summary>
/// <remarks>To be added.</remarks>
[MacCatalyst (13, 1)]
[Native]
public enum AVMusicTrackLoopCount : long {
/// <summary>To be added.</summary>
/// <summary>Loops the music track indefinitely.</summary>
Forever = -1,
}

Expand Down Expand Up @@ -1698,11 +1696,12 @@ public enum AVPlayerHdrMode : long {
DolbyVision = 0x4,
}

/// <summary>Specifies options for activating an audio session.</summary>
[MacCatalyst (13, 1)]
[Flags]
[Native]
public enum AVAudioSessionActivationOptions : ulong {
/// <summary>To be added.</summary>
/// <summary>No activation options are specified.</summary>
None = 0x0,
}

Expand Down
11 changes: 8 additions & 3 deletions src/AppKit/NSApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@

namespace AppKit {
public partial class NSApplication : NSResponder {
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
public static bool CheckForIllegalCrossThreadCalls = true;
/// <inheritdoc cref="Runtime.CheckForIllegalCrossThreadCalls" />
public static bool CheckForIllegalCrossThreadCalls;
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
public static bool CheckForEventAndDelegateMismatches = true;
Expand All @@ -53,6 +52,12 @@ public static void Init ()

internal static void InitializeApplication ()
{
// The linker replaces the 'Runtime.CheckForIllegalCrossThreadCalls' getter with a constant value, so when the UI
// thread checks are disabled the assignment below (and the 'CheckForIllegalCrossThreadCalls' field
// itself, unless something else references it) is trimmed away.
if (Runtime.CheckForIllegalCrossThreadCalls)
CheckForIllegalCrossThreadCalls = true;

SynchronizationContext.SetSynchronizationContext (new AppKitSynchronizationContext ());
}

Expand Down
1 change: 0 additions & 1 deletion src/CoreMotion/Defs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ public override string ToString ()

// untyped enum -> CMDeviceMotion.h
/// <summary>An enumeration whose values specify the quality of the magnetometer calibration.</summary>
/// <remarks>To be added.</remarks>
public enum CMMagneticFieldCalibrationAccuracy {
/// <summary>Magnetic calibration has not occurred.</summary>
Uncalibrated = -1,
Expand Down
20 changes: 11 additions & 9 deletions src/CoreTelephony/CTEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,37 @@ namespace CoreTelephony {
// in header file this is used inside a CTError structure where the domain is a SInt32
/// <summary>An enumeration whose values specify an error domain.</summary>
public enum CTErrorDomain {
/// <summary>To be added.</summary>
/// <summary>No error occurred.</summary>
NoError = 0,
/// <summary>To be added.</summary>
/// <summary>The error is in the POSIX error domain.</summary>
Posix = 1,
/// <summary>To be added.</summary>
/// <summary>The error is in the Mach error domain.</summary>
Mach = 2,
}

/// <summary>Enumerates data restrictions for <see cref="CoreTelephony.CTCellularData.RestrictedState" />.</summary>
[MacCatalyst (13, 1)]
[Native]
public enum CTCellularDataRestrictedState : ulong {
/// <summary>To be added.</summary>
/// <summary>The cellular data restriction state is unknown.</summary>
Unknown,
/// <summary>To be added.</summary>
/// <summary>Cellular data access is restricted.</summary>
Restricted,
/// <summary>To be added.</summary>
/// <summary>Cellular data access is not restricted.</summary>
NotRestricted,
}

/// <summary>Enumerates the results of adding a cellular plan.</summary>
[MacCatalyst (13, 1)]
[Native]
public enum CTCellularPlanProvisioningAddPlanResult : long {
/// <summary>To be added.</summary>
/// <summary>The result is unknown.</summary>
Unknown,
/// <summary>To be added.</summary>
/// <summary>The cellular plan could not be added.</summary>
Fail,
/// <summary>To be added.</summary>
/// <summary>The cellular plan was added successfully.</summary>
Success,
/// <summary>The operation was canceled.</summary>
[iOS (17, 0)]
Cancel,
}
Expand Down
6 changes: 3 additions & 3 deletions src/CoreVideo/CVEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ public enum CVReturn : int {
/// <summary>A flagging enumeration. Currently only contains a <c>None</c> value of 0.</summary>
[MacCatalyst (13, 1)]
public enum CVOptionFlags : long {
/// <summary>To be added.</summary>
/// <summary>No options are specified.</summary>
None = 0,
}

/// <summary>An enumeration that can flag whether a <see cref="CoreVideo.CVTime" /> is unknown.</summary>
[Flags]
[MacCatalyst (13, 1)]
public enum CVTimeFlags : int {
/// <summary>To be added.</summary>
/// <summary>The time value is indefinite.</summary>
IsIndefinite = 1 << 0,
}

Expand Down Expand Up @@ -173,7 +173,7 @@ public enum CVSMPTETimeType : uint {
/// <summary>Defines an option for <see cref="CoreVideo.CVPixelBufferPool.Flush(CoreVideo.CVPixelBufferPoolFlushFlags)" />.</summary>
[MacCatalyst (13, 1)]
public enum CVPixelBufferPoolFlushFlags : ulong {
/// <summary>To be added.</summary>
/// <summary>Releases all unused buffers from the pool.</summary>
FlushExcessBuffers = 1,
}

Expand Down
Loading
Loading