Skip to content

Commit 3648b56

Browse files
authored
Add support for SwiftSelf<T> in Mono JIT and Interpreter (#104171)
This PR adds Mono support for SwiftSelf<T> in the Swift calling convention. This type enables the correct passing of frozen value types in instance methods in Swift.
1 parent a3fd095 commit 3648b56

File tree

7 files changed

+38
-12
lines changed

7 files changed

+38
-12
lines changed

src/mono/mono/metadata/marshal.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "Sys
130130
static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute")
131131
static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callconv_attribute, "System.Runtime.InteropServices", "UnmanagedCallConvAttribute")
132132

133-
GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError")
134133
GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self, "System.Runtime.InteropServices.Swift", "SwiftSelf")
134+
GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_self_t, "System.Runtime.InteropServices.Swift", "SwiftSelf`1");
135+
GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_error, "System.Runtime.InteropServices.Swift", "SwiftError")
135136
GENERATE_TRY_GET_CLASS_WITH_CACHE (swift_indirect_result, "System.Runtime.InteropServices.Swift", "SwiftIndirectResult")
136137

137138
static gboolean type_is_blittable (MonoType *type);
@@ -3698,20 +3699,30 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
36983699

36993700
if (mono_method_signature_has_ext_callconv (csig, MONO_EXT_CALLCONV_SWIFTCALL)) {
37003701
MonoClass *swift_self = mono_class_try_get_swift_self_class ();
3702+
MonoClass *swift_self_t = mono_class_try_get_swift_self_t_class ();
37013703
MonoClass *swift_error = mono_class_try_get_swift_error_class ();
37023704
MonoClass *swift_indirect_result = mono_class_try_get_swift_indirect_result_class ();
37033705
MonoClass *swift_error_ptr = mono_class_create_ptr (m_class_get_this_arg (swift_error));
37043706
int swift_error_args = 0, swift_self_args = 0, swift_indirect_result_args = 0;
37053707
for (int i = 0; i < method->signature->param_count; ++i) {
37063708
MonoClass *param_klass = mono_class_from_mono_type_internal (method->signature->params [i]);
3709+
MonoGenericClass *param_gklass = mono_class_try_get_generic_class (param_klass);
37073710
if (param_klass) {
37083711
if (param_klass == swift_error && !m_type_is_byref (method->signature->params [i])) {
37093712
swift_error_args = swift_self_args = 0;
37103713
mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftError argument must be passed by reference.");
37113714
break;
37123715
} else if (param_klass == swift_error || param_klass == swift_error_ptr) {
37133716
swift_error_args++;
3714-
} else if (param_klass == swift_self) {
3717+
} else if (param_gklass && (param_gklass->container_class == swift_self_t) && i > 0) {
3718+
swift_error_args = swift_self_args = 0;
3719+
mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "SwiftSelf<T> must be the first argument in the signature.");
3720+
break;
3721+
} else if (param_gklass && (param_gklass->container_class == swift_self_t) && m_type_is_byref (method->signature->params [i])) {
3722+
swift_error_args = swift_self_args = 0;
3723+
mono_error_set_generic_error (emitted_error, "System", "InvalidProgramException", "Expected SwiftSelf<T> struct, got pointer/reference.");
3724+
break;
3725+
} else if (param_klass == swift_self || (param_gklass && (param_gklass->container_class == swift_self_t))) {
37153726
swift_self_args++;
37163727
} else if (param_klass == swift_indirect_result) {
37173728
swift_indirect_result_args++;

src/mono/mono/metadata/marshal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ IlgenCallbacksToMono*
753753
mono_marshal_get_mono_callbacks_for_ilgen (void);
754754

755755
GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_self)
756+
GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_self_t);
756757
GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_error)
757758
GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL (swift_indirect_result)
758759

src/mono/mono/mini/interp/transform.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,7 @@ interp_emit_swiftcall_struct_lowering (TransformData *td, MonoMethodSignature *c
33563356
uint32_t new_param_count = 0;
33573357
int align;
33583358
MonoClass *swift_self = mono_class_try_get_swift_self_class ();
3359+
MonoClass *swift_self_t = mono_class_try_get_swift_self_t_class ();
33593360
MonoClass *swift_error = mono_class_try_get_swift_error_class ();
33603361
MonoClass *swift_indirect_result = mono_class_try_get_swift_indirect_result_class ();
33613362
/*
@@ -3366,6 +3367,8 @@ interp_emit_swiftcall_struct_lowering (TransformData *td, MonoMethodSignature *c
33663367
for (int idx_param = 0; idx_param < csignature->param_count; ++idx_param) {
33673368
MonoType *ptype = csignature->params [idx_param];
33683369
MonoClass *klass = mono_class_from_mono_type_internal (ptype);
3370+
MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
3371+
33693372
// SwiftSelf, SwiftError, and SwiftIndirectResult are special cases where we need to preserve the class information for the codegen to handle them correctly.
33703373
if (mono_type_is_struct (ptype) && !(klass == swift_self || klass == swift_error || klass == swift_indirect_result)) {
33713374
SwiftPhysicalLowering lowered_swift_struct = mono_marshal_get_swift_physical_lowering (ptype, FALSE);
@@ -3386,8 +3389,13 @@ interp_emit_swiftcall_struct_lowering (TransformData *td, MonoMethodSignature *c
33863389
g_array_append_val (new_params, lowered_swift_struct.lowered_elements [idx_lowered]);
33873390
}
33883391
} else {
3389-
// For structs that cannot be lowered, we change the argument to byref type
3390-
ptype = mono_class_get_byref_type (mono_defaults.typed_reference_class);
3392+
// For structs that cannot be lowered, we change the argument to a pointer-like argument type.
3393+
// If SwiftSelf<T> can't be lowered, it should be passed in the same manner as SwiftSelf, via the context register.
3394+
if (gklass && (gklass->container_class == swift_self_t))
3395+
ptype = mono_class_get_byref_type (swift_self);
3396+
else
3397+
ptype = mono_class_get_byref_type (klass);
3398+
33913399
// Load the address of the struct
33923400
interp_add_ins (td, MINT_LDLOCA_S);
33933401
interp_ins_set_sreg (td->last_ins, sp_old_params [idx_param].var);

src/mono/mono/mini/method-to-ir.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,6 +7533,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
75337533
GArray *new_params = g_array_sized_new (FALSE, FALSE, sizeof (MonoType*), n);
75347534
uint32_t new_param_count = 0;
75357535
MonoClass *swift_self = mono_class_try_get_swift_self_class ();
7536+
MonoClass *swift_self_t = mono_class_try_get_swift_self_t_class ();
75367537
MonoClass *swift_error = mono_class_try_get_swift_error_class ();
75377538
MonoClass *swift_indirect_result = mono_class_try_get_swift_indirect_result_class ();
75387539
/*
@@ -7543,6 +7544,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
75437544
for (int idx_param = 0; idx_param < n; ++idx_param) {
75447545
MonoType *ptype = fsig->params [idx_param];
75457546
MonoClass *klass = mono_class_from_mono_type_internal (ptype);
7547+
MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
75467548

75477549
// SwiftSelf, SwiftError, and SwiftIndirectResult are special cases where we need to preserve the class information for the codegen to handle them correctly.
75487550
if (mono_type_is_struct (ptype) && !(klass == swift_self || klass == swift_error || klass == swift_indirect_result)) {
@@ -7562,9 +7564,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
75627564
++new_param_count;
75637565
}
75647566
} else {
7565-
// For structs that cannot be lowered, we change the argument to byref type
7567+
// For structs that cannot be lowered, we change the argument to a pointer-like argument type.
7568+
// If SwiftSelf<T> can't be lowered, it should be passed in the same manner as SwiftSelf, via the context register.
7569+
if (gklass && (gklass->container_class == swift_self_t)) {
7570+
ptype = mono_class_get_byref_type (swift_self);
7571+
// The ARGLOADA should be a pointer-like type.
7572+
struct_base_address->klass = mono_defaults.int_class;
7573+
} else {
7574+
ptype = mono_class_get_byref_type (klass);
7575+
}
7576+
75667577
*sp++ = struct_base_address;
7567-
ptype = mono_class_get_byref_type (klass);
75687578

75697579
g_array_append_val (new_params, ptype);
75707580
++new_param_count;

src/mono/mono/mini/mini-amd64.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,8 +1096,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
10961096

10971097
if ((klass == swift_self || klass == swift_indirect_result) && sig->pinvoke) {
10981098
guint32 size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke && !sig->marshalling_disabled);
1099-
g_assert (size == 8);
1100-
1099+
g_assert (size == TARGET_SIZEOF_VOID_P);
11011100
ainfo->storage = ArgValuetypeInReg;
11021101
ainfo->pair_storage [0] = ArgInIReg;
11031102
ainfo->pair_storage [1] = ArgNone;

src/mono/mono/mini/mini-arm64.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,8 +1922,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
19221922
guint32 align;
19231923
MonoType *ptype = mini_get_underlying_type (sig->params [pindex]);
19241924
int size = mini_type_stack_size_full (ptype, &align, cinfo->pinvoke);
1925-
g_assert (size == 8);
1926-
1925+
g_assert (size == TARGET_SIZEOF_VOID_P);
19271926
ainfo->storage = ArgVtypeInIRegs;
19281927
ainfo->reg = (klass == swift_self) ? ARMREG_R20 : ARMREG_R8;
19291928
ainfo->nregs = 1;

src/tests/Interop/Swift/SwiftSelfContext/SwiftSelfContext.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,13 @@ public struct FrozenNonEnregisteredStruct
6969
public static extern long SumFrozenNonEnregisteredStruct(SwiftSelf<FrozenNonEnregisteredStruct> self);
7070

7171
[Fact]
72-
[SkipOnMono("SwiftSelf<T> is not supported on Mono")]
7372
public unsafe static void TestSelfIsFrozenEnregisteredStruct()
7473
{
7574
long sum = SumFrozenEnregisteredStruct(new SwiftSelf<FrozenEnregisteredStruct>(new FrozenEnregisteredStruct { A = 10, B = 20 }));
7675
Assert.Equal(30, sum);
7776
}
7877

7978
[Fact]
80-
[SkipOnMono("SwiftSelf<T> is not supported on Mono")]
8179
public unsafe static void TestSelfIsFrozenNonEnregisteredStruct()
8280
{
8381
long sum = SumFrozenNonEnregisteredStruct(new SwiftSelf<FrozenNonEnregisteredStruct>(new FrozenNonEnregisteredStruct { A = 10, B = 20, C = 30, D = 40, E = 50 }));

0 commit comments

Comments
 (0)