Add support for SwiftIndirectResult in Mono JIT and Interpreter#104111
Add support for SwiftIndirectResult in Mono JIT and Interpreter#104111matouskozak merged 7 commits intodotnet:mainfrom
SwiftIndirectResult in Mono JIT and Interpreter#104111Conversation
|
/azp run runtime-extra-platforms |
|
Tagging subscribers to this area: @steveisok, @lambdageek |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
I think I don't understand private struct NonFrozenStruct
{
public int A;
public int B;
public int C;
}
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
[DllImport(SwiftLib, EntryPoint = "$s19SwiftIndirectResult21ReturnNonFrozenStruct1a1b1cAA0efG0Vs5Int32V_A2ItF")]
public static extern void ReturnNonFrozenStruct(SwiftIndirectResult result, int a, int b, int c);
[Fact]
public static void TestReturnNonFrozenStruct()
{
// In normal circumstances this instance would have unknown/dynamically determined size.
NonFrozenStruct instance;
ReturnNonFrozenStruct(new SwiftIndirectResult(&instance), 10, 20, 30);
Assert.Equal(10, instance.A);
Assert.Equal(20, instance.B);
Assert.Equal(30, instance.C);
}How does Swift know that the caller allocated a large enough buffer so the callee can rely on being able to write into it? My understanding of non-frozen Swift types is that they allow you to link two different versions of |
There is metadata created and exported by the callee module that, among other things, includes the size of the non-frozen struct. The caller is supposed to allocate a buffer of that size. I didn't do that in the test. @kotlarmilos's original issue has some (pseudo-)code that is more faithful to what the interop generator would end up with: #102082 |
Description
This PR adds Mono support for
SwiftIndirectResultin Swift calling convention. This type provides direct access to the return result buffer needed for returning non-frozen types in Swift.Changes
This PR includes both Mono JIT and Interpreter changes. On arm64, the indirect return buffer
x8is assigned whenSwiftIndirectResultis passed as an argument, requiring no additional handling. On amd64,raxis the indirect return buffer, but it is heavily used across the runtime as a scratch register. To handle this, thex10register is assigned as a proxy, and at the P/Invoke boundary, it is copied to/fromrax.Verification
The runtime tests in
Interop/Swift/SwiftIndirectResultshould verify the functionality.Additional notes
Additional testing coverage will be added as we progress with projection tooling changes.
Contributes to #102082