-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
The source generated interop for string marshaling have unnecessary stack copies of the marshaller.
Proposal
Introduce FromManagedValue method on the string marshallers and use it to initialize the marshaller instead of the constructor.
Details
[LibraryImport("...", StringMarshalling = StringMarshalling.Utf8)]
public static partial void TestTest(string s);The source generated interop for this simple method that takes utf8 string looks like this:
public static partial void TestTest(string s)
{
byte* __s_gen_native = default;
//
// Setup
//
global::System.Runtime.InteropServices.Marshalling.Utf8StringMarshaller __s_gen_native__marshaller = default;
try
{
//
// Marshal
//
byte* __s_gen_native__marshaller__stackptr = stackalloc byte[256];
__s_gen_native__marshaller = new(s, new System.Span<byte>(__s_gen_native__marshaller__stackptr, 256));
__s_gen_native = __s_gen_native__marshaller.ToNativeValue();
__PInvoke__(__s_gen_native);
}
finally
{
//
// Cleanup
//
__s_gen_native__marshaller.FreeNative();
}
...__s_gen_native__marshaller = new(s, new System.Span<byte>(__s_gen_native__marshaller__stackptr, 256)); is the problematic line. The JIT has to create a temporary stack copy of the marshaller, invoke the constructor on this temporary copy, and then copy this temporary on-stack over the local variable.
My proposal is to change this line to __s_gen_native__marshaller.FromManagedValue(s, new System.Span<byte>(__s_gen_native__marshaller__stackptr, 256)); that will avoid the unnecessary on-stack copies.