This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add doc on p/invoke marshalling pregeneration in ReadyToRun (#27413)
- Loading branch information
1 parent
7233801
commit 7bc2158
Showing
1 changed file
with
38 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# P/invoke marshalling pregeneration in ReadyToRun | ||
|
||
One of the themes for .NET 5 is improvement of startup times for apps running on top of the CoreCLR runtime. One of the costs that apps must pay at startup is the generation of p/invoke interop marshalling stubs. | ||
|
||
P/invoke marshalling is the process of converting managed types declared in the signature of a p/invoke into native types expected by the foreign native function targeted by the p/invoke. Marshalling helps with e.g. bridging the gap between managed methods that model text strings as `System.String` instances and native methods that expect text strings to be a zero-terminated buffer of Utf-8 characters. | ||
|
||
P/invoke marshalling is performed by methods called "marshalling stubs" that the runtime generates based on the signature of the p/invoke, `MarshalAs` attributes applied to the method parameters, and other attributes that control p/invoke marshalling. | ||
|
||
These stubs can be generated ahead of time, as part of ReadyToRun compilation. | ||
|
||
## P/invoke marshalling pregeneration | ||
|
||
The marshalling code generator that the runtime currently uses is written in C++ and is tightly coupled with the CoreCLR type system. As such, it would require a non-trivial effort to re-use the existing marshallers in the ReadyToRun compiler that is written in C#. | ||
|
||
Marshalling code generators will therefore have to be duplicated in C#. To limit the amount of duplication, we’ll be scoping down the number of supported marshallers to the most common ones. Uncommon marshallers (`StringBuilder`, `UnmanagedType.AsAny`, `HandleRef`, `Decimal`, `DateTime`, interface, etc.) will stay JITted at runtime. | ||
|
||
We’ll be reusing a subset of the marshalling code generator written for the CoreRT AOT compiler by making it work on CoreCLR and bringing it to production quality. | ||
|
||
Following marshallers will be supported: | ||
|
||
* Primitive types, enums, blittable structs | ||
* Pointers and references to primitive types, enums, and blittable structs | ||
* Arrays of primitive types and arrays of blittable structs | ||
* String (Ansi, Unicode, Utf8) | ||
* SafeHandle | ||
* Delegate | ||
|
||
All the other marshallers will be generated and JITted at runtime. | ||
|
||
The IL stubs generated by the runtime are currently shared by all p/invokes that have the same signature/marshalling. As part of this work, we’re going to make p/invoke stubs like any other methods. This will enable their inlining. | ||
|
||
## Expected limitations | ||
|
||
In the first phase, p/invoke pregeneration will be limited to CoreLib and large version bubble modes that include CoreLib. There are several reasons for this limitation – all of these limitations need to be lifted to enable p/invoke pregeneration outside large version bubble that includes CoreLib: | ||
|
||
1. The marshallers often need to call helpers defined in CoreLib. Outside large version bubble mode, the ReadyToRun compiler can currently only reference members defined in other assemblies if there’s an existing MemberRef record in the IL metadata stream. It’s not possible to generate fixups referencing methods the module didn’t already reference. | ||
2. The helpers defined in CoreLib do not represent public APIs. Their shape and existence is not guaranteed in future versions of the runtime. We need to make these helpers public APIs. | ||
3. Versioning of the generated marshallers: the generation of marshalling code is tied to the version of the runtime. ReadyToRun code can possibly be used on multiple different versions of the runtime. We need to make sure the code that the runtime generates if e.g. ReadyToRun is turned off is the same as the code we generated ahead of time. |