Skip to content

Commit 6550ee3

Browse files
committed
WIP
1 parent be42e62 commit 6550ee3

File tree

1 file changed

+49
-9
lines changed

1 file changed

+49
-9
lines changed

README.md

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ Fundamentally, this work is benefiting not just NativeAOT but also the MonoVM AO
3434

3535
### WinForms
3636

37-
WinForms and NativeAOT are not an officially supported scenario yet. There is an ongoing effort to remove the blockers. The scope of the work is rather wide though and it's been spaning multiple releases.
37+
WinForms and NativeAOT are not an officially supported scenario yet. There is an [ongoing effort to remove the blockers](https://github.com/dotnet/winforms/issues/4649). The scope of the work is rather wide though and it's been spaning multiple releases.
3838

39-
One of the issues is that the framework relies on non-string resources. These are either deserialized using the binary formatter or the `TypeConverter`s (part of System.ComponentModel). Both approaches are problematic for different reasons. Binary formatter is going through deprecation cycle over last few .NET releases. In .NET 9 it's finally removed from the core class libraries. A work has been done to replace it with a [NrbfDecoder](https://github.com/dotnet/runtime/pull/103232) to handle reading of pre-existing data. As part of the prototyping for the `NrbfDecoder` API shape the usage has been validated on WinForms use cases. `TypeConverter`s depend on reflection and the NativeAOT compiler doesn't have intrinsic understanding of the WinForms framework necessary to figure out which types are going to be accessed by the reflection-based logic. The solution to this problem is described in detail in the [TypeDescriptor-related trimming support issue](https://github.com/dotnet/runtime/issues/101202).
39+
[One of the issues](https://github.com/dotnet/winforms/issues/10813) is that the framework relies on non-string resources. These are either deserialized using the binary formatter or the `TypeConverter`s (part of System.ComponentModel). Both approaches are problematic for different reasons. Binary formatter is going through deprecation cycle over last few .NET releases. In .NET 9 it's finally removed from the core class libraries. A work has been done to replace it with a [NrbfDecoder](https://github.com/dotnet/runtime/pull/103232) to handle reading of pre-existing data. As part of the prototyping for the `NrbfDecoder` API shape the usage has been validated on WinForms use cases. `TypeConverter`s depend on reflection and the NativeAOT compiler doesn't have intrinsic understanding of the WinForms framework necessary to figure out which types are going to be accessed by the reflection-based logic. The solution to this problem is described in detail in the [TypeDescriptor-related trimming support issue](https://github.com/dotnet/runtime/issues/101202).
4040

4141
Second issue is the dependency on COM interop for features like accessibility or open/save dialogs. NativeAOT doesn't support the traditional COM interop with class attributes that was present in .NET since the inception. Instead, it depends on a more modern [ComWrappers API](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/tutorial-comwrappers) introduced in .NET 5. Early pioneering work on the new WinForms COM interop was done by [Andrii Kurdiumov](https://github.com/kant2002) and he has written [informative blog posts](https://codevision.medium.com/using-com-in-nativeaot-131dbc0d559e) about it. This is currently an area of focus in .NET 9.
4242

@@ -52,16 +52,56 @@ experimental NativeAOT/iOS support.
5252

5353
## Platform support
5454

55-
TODO
55+
For the desktop part of the application, we publish for the osx-arm64, osx-x64, and win-x86 runtime identifiers. The macOS support was added in .NET 8, while the Windows x86 support only landed in usable form in .NET 9 Preview 4.
5656

57-
OS:
58-
- macOS (.NET 8), MSR, ILLink behavior differences (TypeForwardedTo)
59-
- win-x86 (.NET 9 Preview 5)
57+
### macOS
6058

61-
Processors
59+
Early in the .NET 8 product cycle we resurrected the existing bits of the macOS support in NativeAOT. This work was soon followed by [Austin Wise](https://github.com/AustinWise) adding support for Objective-C interop API. This was soon picked up by the .NET and Xamarin.iOS teams and extended to support the platform including the full iOS/macOS API bindings which were previously only available in CoreCLR and MonoVM.
6260

63-
ARM[64], branch limits, linker
64-
X86 is odd, exception handling
61+
As part of the NativeAOT/iOS bring-up few important technologies like [Managed Static Registrar](https://github.com/xamarin/xamarin-macios/blob/main/docs/managed-static-registrar.md) were developed that were crucial to get an application of this size running. Notably, these improvements also significantly helped performance of interop scenarios on other runtimes.
62+
63+
One peculiar thing about the macOS support in NativeAOT is that if you target the `net8.0-macos` framework the build process includes an extra ILLink step. The responsibilities of ILLink and NativeAOT overlap in many ways. They both do trimming but they slight behavioral differences that may be observable in some scenarios. We hit one such difference on our macOS version of the System.Drawing library. The library itself is an automatically generated type forwarder. All the implementations of the drawing primitives live in System.Drawing.Common or System.Drawing.Primitives libraries. Why is the System.Drawing library necessary at all then? To answer that we need to go back to the WinForms section above. The resource files reference .NET types by name. For example, you may encounter something like this in the .resx file:
64+
65+
```xml
66+
<data name="user_gray" type="System.Resources.ResXFileRef, System.Windows.Forms">
67+
<value>../Resources/user_gray.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
68+
</data>
69+
```
70+
71+
The referenced type is in the System.Drawing assembly. The assembly is auto-generated and it contains a code similar to:
72+
73+
```csharp
74+
[assembly: TypeForwardedTo(typeof(System.Drawing.Bitmap))]
75+
```
76+
77+
That in turns forwards to the actual implementation in System.Drawing.Common:
78+
79+
```csharp
80+
[System.Runtime.CompilerServices.TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
81+
public sealed class Bitmap : Image { ... }
82+
83+
[TypeConverter(typeof(ImageConverter))]
84+
[System.Runtime.CompilerServices.TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
85+
public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISerializable { ... }
86+
```
87+
88+
If you didn't skip the WinForms section, you likely see what is going on. At runtime, the resource deserialization needs to resolve the type name into a type. It then examines the attributes on the type, and finds the `TypeConverter` attribute. This tells it to instantiate the `ImageConverter` class and finally use that to interpret the data in the resources.
89+
90+
Now, let's get back to the ILLink and NativeAOT little difference. ILLink strips the `TypeForwardedTo` annotations from the trimmed assemblies. The intention is good. As far as ILLink is concerned, all the references to `Bitmap` in the code are rewritten to the real implementation assembly, and so the attribute is no longer needed. It doesn't have the intrinsic knowledge of the resource resolution logic, and hence doesn't see that it will still be required at runtime. NativeAOT seems to keep the information about forwarded types though.
91+
92+
The build process for `net8.0-macos` runs the ILLink first and then pipes the output into NativeAOT compiler. This has the unfortunate side effect of losing the the `TypeForwardedTo` attributes. The fix is adding a simple `<TrimmerRootAssembly Include="System.Drawing" />` item into the main project and we can move on.
93+
94+
### Windows
95+
96+
TODO: .NET 9 Preview 5
97+
98+
### ARM processors
99+
100+
TODO: ARM[64], branch limits, linker
101+
102+
### X86 oddities
103+
104+
TODO: X86 is odd, exception handling
65105

66106
## Main project
67107

0 commit comments

Comments
 (0)