Skip to content

Commit 4cf19ee

Browse files
authored
[mono] Add basic ref struct support for generic parameter (#99081)
* Add basic ref struct support for generic parameter * Try to fix format * Address review feedback and enable more tests * Fix format * Commenting out methods with array of T to workaround AOT failure * Split up the testcases * Throw type loading exception when trying to create type arrays with ByRefLike types * Fix box and stsfld/ldsfld/ldsflda * Disable a test cause it is failing with interpreter * For load/store static field, only error out when it is a generic class with byreflike type parameter * Fix interpreter box byreflike exception ID * Relax type check * Enable more tests * Revert the change for relaxing type check * Remove unreached check * remove unused variable
1 parent 07b705b commit 4cf19ee

14 files changed

+35
-41
lines changed

src/mono/mono/metadata/class-init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2953,7 +2953,7 @@ mono_class_init_internal (MonoClass *klass)
29532953
if (klass->inited || mono_class_has_failure (klass))
29542954
return !mono_class_has_failure (klass);
29552955

2956-
/*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
2956+
// g_print ("Init class %s\n", mono_type_get_full_name (klass));
29572957

29582958
/*
29592959
* This function can recursively call itself.

src/mono/mono/metadata/class.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -640,10 +640,7 @@ mono_type_is_valid_generic_argument (MonoType *type)
640640
{
641641
switch (type->type) {
642642
case MONO_TYPE_VOID:
643-
case MONO_TYPE_TYPEDBYREF:
644643
return FALSE;
645-
case MONO_TYPE_VALUETYPE:
646-
return !m_class_is_byreflike (type->data.klass);
647644
default:
648645
return TRUE;
649646
}

src/mono/mono/metadata/loader.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,6 @@ mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMetho
823823
int i;
824824

825825
mono_class_setup_methods (klass);
826-
g_assert (!mono_class_has_failure (klass)); /*FIXME this should not fail, right?*/
827826
int mcount = mono_class_get_method_count (klass);
828827
MonoMethod **klass_methods = m_class_get_methods (klass);
829828
for (i = 0; i < mcount; ++i) {

src/mono/mono/metadata/metadata.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3942,7 +3942,7 @@ compare_type_literals (MonoImage *image, int class_type, int type_type, MonoErro
39423942
if (class_type == MONO_TYPE_STRING || class_type == MONO_TYPE_OBJECT)
39433943
return TRUE;
39443944
//XXX stringify this argument
3945-
mono_error_set_bad_image (error, image, "Expected reference type but got type kind %d", class_type);
3945+
mono_error_set_type_load_name (error, NULL, NULL, "Expected reference type but got type kind %d", class_type);
39463946
return FALSE;
39473947
}
39483948

@@ -3966,7 +3966,7 @@ compare_type_literals (MonoImage *image, int class_type, int type_type, MonoErro
39663966
return TRUE;
39673967
default:
39683968
//XXX stringify this argument
3969-
mono_error_set_bad_image (error, image, "Expected value type but got type kind %d", class_type);
3969+
mono_error_set_type_load_name (error, NULL, NULL, "Expected value type but got type kind %d", class_type);
39703970
return FALSE;
39713971
}
39723972
}

src/mono/mono/metadata/object-internals.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,16 +1439,17 @@ typedef struct {
14391439

14401440
/* Keep in sync with System.GenericParameterAttributes */
14411441
typedef enum {
1442-
GENERIC_PARAMETER_ATTRIBUTE_NON_VARIANT = 0,
1443-
GENERIC_PARAMETER_ATTRIBUTE_COVARIANT = 1,
1444-
GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT = 2,
1445-
GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK = 3,
1446-
1447-
GENERIC_PARAMETER_ATTRIBUTE_NO_SPECIAL_CONSTRAINT = 0,
1448-
GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT = 4,
1449-
GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT = 8,
1450-
GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT = 16,
1451-
GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK = 28
1442+
GENERIC_PARAMETER_ATTRIBUTE_NON_VARIANT = 0x0000,
1443+
GENERIC_PARAMETER_ATTRIBUTE_COVARIANT = 0x0001,
1444+
GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT = 0x0002,
1445+
GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK = 0x0003,
1446+
1447+
GENERIC_PARAMETER_ATTRIBUTE_NO_SPECIAL_CONSTRAINT = 0x0000,
1448+
GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT = 0x0004,
1449+
GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT = 0x0008,
1450+
GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT = 0x0010,
1451+
GENERIC_PARAMETER_ATTRIBUTE_ACCEPT_BYREFLIKE_CONSTRAINTS = 0x0020, // type argument can be ByRefLike
1452+
GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK = 0x003c
14521453
} GenericParameterAttributes;
14531454

14541455
typedef struct {

src/mono/mono/metadata/verify.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co
8787
return FALSE;
8888
}
8989

90+
if (m_class_is_byreflike (paramClass) && (param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_ACCEPT_BYREFLIKE_CONSTRAINTS) == 0)
91+
return FALSE;
92+
9093
if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
9194
continue;
9295

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6905,7 +6905,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
69056905
td->ip += 5;
69066906
} else {
69076907
if (G_UNLIKELY (m_class_is_byreflike (klass))) {
6908-
mono_error_set_bad_image (error, image, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
6908+
mono_error_set_invalid_program (error, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
69096909
goto exit;
69106910
}
69116911

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

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,16 +2320,13 @@ emit_type_load_failure (MonoCompile* cfg, MonoClass* klass)
23202320
}
23212321

23222322
static void
2323-
emit_invalid_program_with_msg (MonoCompile *cfg, MonoError *error_msg, MonoMethod *caller, MonoMethod *callee)
2323+
emit_invalid_program_with_msg (MonoCompile *cfg, char *error_msg)
23242324
{
2325-
g_assert (!is_ok (error_msg));
2326-
2327-
char *str = mono_mem_manager_strdup (cfg->mem_manager, mono_error_get_message (error_msg));
23282325
MonoInst *iargs[1];
23292326
if (cfg->compile_aot)
2330-
EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
2327+
EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], error_msg);
23312328
else
2332-
EMIT_NEW_PCONST (cfg, iargs [0], str);
2329+
EMIT_NEW_PCONST (cfg, iargs [0], error_msg);
23332330
mono_emit_jit_icall (cfg, mono_throw_invalid_program, iargs);
23342331
}
23352332

@@ -3416,8 +3413,8 @@ mini_emit_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_us
34163413
MonoInst *alloc, *ins;
34173414

34183415
if (G_UNLIKELY (m_class_is_byreflike (klass))) {
3419-
mono_error_set_bad_image (cfg->error, m_class_get_image (cfg->method->klass), "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
3420-
mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
3416+
mono_error_set_invalid_program (cfg->error, "Cannot box IsByRefLike type '%s.%s'", m_class_get_name_space (klass), m_class_get_name (klass));
3417+
mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
34213418
return NULL;
34223419
}
34233420

@@ -9282,7 +9279,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
92829279

92839280
mono_save_token_info (cfg, image, token, cmethod);
92849281

9285-
if (!mono_class_init_internal (cmethod->klass))
9282+
if (mono_class_has_failure (cmethod->klass) || !mono_class_init_internal (cmethod->klass))
92869283
TYPE_LOAD_ERROR (cmethod->klass);
92879284

92889285
context_used = mini_method_check_context_used (cfg, cmethod);
@@ -9995,8 +9992,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
99959992
case MONO_CEE_STSFLD: {
99969993
MonoClassField *field;
99979994
guint foffset;
9998-
gboolean is_instance;
99999995
gpointer addr = NULL;
9996+
gboolean is_instance;
100009997
gboolean is_special_static;
100019998
MonoType *ftype;
100029999
MonoInst *store_val = NULL;
@@ -10081,6 +10078,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1008110078
is_instance = FALSE;
1008210079
}
1008310080

10081+
1008410082
context_used = mini_class_check_context_used (cfg, klass);
1008510083

1008610084
if (il_op == MONO_CEE_LDSFLD) {
@@ -11845,7 +11843,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1184511843
/* if we couldn't create a wrapper because cmethod isn't supposed to have an
1184611844
UnmanagedCallersOnly attribute, follow CoreCLR behavior and throw when the
1184711845
method with the ldftn is executing, not when it is being compiled. */
11848-
emit_invalid_program_with_msg (cfg, wrapper_error, method, cmethod);
11846+
char *err_msg = mono_mem_manager_strdup (cfg->mem_manager, mono_error_get_message (wrapper_error));
11847+
emit_invalid_program_with_msg (cfg, err_msg);
1184911848
mono_error_cleanup (wrapper_error);
1185011849
EMIT_NEW_PCONST (cfg, ins, NULL);
1185111850
*sp++ = ins;

src/mono/mono/mini/mini-generic-sharing.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,12 +584,14 @@ inflate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoTempl
584584

585585
if (m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_ARRAY ||
586586
m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_SZARRAY) {
587+
g_assert (!mono_class_has_failure (inflated_class));
587588
inflated_method = mono_method_search_in_array_class (inflated_class,
588589
method->name, method->signature);
589590
} else {
590591
inflated_method = mono_class_inflate_generic_method_checked (method, context, error);
591592
g_assert (is_ok (error)); /* FIXME don't swallow the error */
592593
}
594+
g_assert (inflated_method);
593595
mono_class_init_internal (inflated_method->klass);
594596
g_assert (inflated_method->klass == inflated_class);
595597
return inflated_method;
@@ -648,12 +650,14 @@ inflate_info (MonoMemoryManager *mem_manager, MonoRuntimeGenericContextInfoTempl
648650

649651
if (m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_ARRAY ||
650652
m_class_get_byval_arg (inflated_class)->type == MONO_TYPE_SZARRAY) {
653+
g_assert (!mono_class_has_failure (inflated_class));
651654
inflated_method = mono_method_search_in_array_class (inflated_class,
652655
method->name, method->signature);
653656
} else {
654657
inflated_method = mono_class_inflate_generic_method_checked (method, context, error);
655658
g_assert (is_ok (error)); /* FIXME don't swallow the error */
656659
}
660+
g_assert (inflated_method);
657661
mono_class_init_internal (inflated_method->klass);
658662
g_assert (inflated_method->klass == inflated_class);
659663

src/tests/Loader/classloader/generics/ByRefLike/GenericTypeSubstitution.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
public class GenericTypeSubstitution
1313
{
1414
[Fact]
15-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
1615
public static void AllowByRefLike_Substituted_For_AllowByRefLike()
1716
{
1817
Console.WriteLine($"{nameof(AllowByRefLike_Substituted_For_AllowByRefLike)}...");
@@ -23,7 +22,6 @@ public static void AllowByRefLike_Substituted_For_AllowByRefLike()
2322
}
2423

2524
[Fact]
26-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
2725
public static void NonByRefLike_Substituted_For_AllowByRefLike()
2826
{
2927
Console.WriteLine($"{nameof(NonByRefLike_Substituted_For_AllowByRefLike)}...");
@@ -34,7 +32,6 @@ public static void NonByRefLike_Substituted_For_AllowByRefLike()
3432
}
3533

3634
[Fact]
37-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
3835
public static void AllowByRefLike_Substituted_For_NonByRefLike()
3936
{
4037
Console.WriteLine($"{nameof(AllowByRefLike_Substituted_For_NonByRefLike)}...");

src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@
344344
ret
345345
}
346346

347+
.field public static class InvalidCSharp.GenericClass_Over`1<!T> StaticField1
347348
.field public static !T StaticField
348349
}
349350

@@ -551,7 +552,7 @@
551552
.method public hidebysig static
552553
class [System.Runtime]System.Type GenericByRefLike_ConstraintsAreIndependent_Interface_ByRefLike_Invalid() cil managed
553554
{
554-
newobj instance void class InvalidCSharp.GenericClass_IndependentConstraints`2<class InvalidCSharp.ByRefLikeTypeWithInterface, valuetype InvalidCSharp.ByRefLikeTypeWithInterface>::.ctor()
555+
newobj instance void class InvalidCSharp.GenericClass_IndependentConstraints`2<class InvalidCSharp.EmptyInterface, valuetype InvalidCSharp.ByRefLikeTypeWithInterface>::.ctor()
555556
callvirt instance class [System.Runtime]System.Type [System.Runtime]System.Object::GetType()
556557
ret
557558
}

src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.ilproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
<PropertyGroup>
33
<OutputType>library</OutputType>
44
<MonoAotIncompatible>true</MonoAotIncompatible>
5-
<DisableProjectBuild Condition="'$(RuntimeFlavor)' == 'Mono'">true</DisableProjectBuild>
65
</PropertyGroup>
76
<ItemGroup>
87
<Compile Include="InvalidCSharp.il" />

src/tests/Loader/classloader/generics/ByRefLike/Validate.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
public class Validate
1313
{
1414
[Fact]
15-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
1615
public static void Validate_TypeLoad()
1716
{
1817
Console.WriteLine($"{nameof(Validate_TypeLoad)}...");
@@ -32,7 +31,6 @@ public static void Validate_TypeLoad()
3231
}
3332

3433
[Fact]
35-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
3634
public static void Validate_Casting_Scenarios()
3735
{
3836
Console.WriteLine($"{nameof(Validate_Casting_Scenarios)}...");
@@ -47,7 +45,7 @@ public static void Validate_Casting_Scenarios()
4745
}
4846

4947
[Fact]
50-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
48+
[SkipOnMono("https://github.com/dotnet/runtime/issues/99379")]
5149
public static void Validate_RecognizedOpCodeSequences_Scenarios()
5250
{
5351
Console.WriteLine($"{nameof(Validate_RecognizedOpCodeSequences_Scenarios)}...");
@@ -59,7 +57,6 @@ public static void Validate_RecognizedOpCodeSequences_Scenarios()
5957
}
6058

6159
[Fact]
62-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
6360
public static void Validate_InvalidOpCode_Scenarios()
6461
{
6562
Console.WriteLine($"{nameof(Validate_InvalidOpCode_Scenarios)}...");
@@ -76,7 +73,6 @@ public static void Validate_InvalidOpCode_Scenarios()
7673
}
7774

7875
[Fact]
79-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
8076
public static void Validate_Inlining_Behavior()
8177
{
8278
Console.WriteLine($"{nameof(Validate_Inlining_Behavior)}...");
@@ -88,7 +84,6 @@ public static void Validate_Inlining_Behavior()
8884
}
8985

9086
// [Fact]
91-
[SkipOnMono("Mono does not support ByRefLike generics yet")]
9287
public static void Validate_MemberDiscoveryViaReflection_ForSpanReadOnlySpan()
9388
{
9489
Console.WriteLine($"{nameof(Validate_MemberDiscoveryViaReflection_ForSpanReadOnlySpan)}...");

src/tests/Loader/classloader/generics/ByRefLike/Validate.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
<PropertyGroup>
33
<!-- Needed for mechanical merging of all remaining tests, this particular project may not actually need process isolation -->
44
<RequiresProcessIsolation>true</RequiresProcessIsolation>
5-
<DisableProjectBuild Condition="'$(RuntimeFlavor)' == 'Mono'">true</DisableProjectBuild>
65
</PropertyGroup>
76
<ItemGroup>
87
<Compile Include="Validate.cs" />

0 commit comments

Comments
 (0)