Skip to content

Commit ab8e992

Browse files
committed
[mono] Disable partial generic sharing for gparams with non-enum constraints.
If a generic argument is a primitive type, and it has an interface constraint that enums don't implement, then partial sharing for that instance is not useful, since only the specific primitive type instance will be able to use the shared version. Fixes #54910.
1 parent 2099752 commit ab8e992

File tree

1 file changed

+65
-10
lines changed

1 file changed

+65
-10
lines changed

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

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,6 +3324,16 @@ mono_generic_context_is_sharable (MonoGenericContext *context, gboolean allow_ty
33243324
return mono_generic_context_is_sharable_full (context, allow_type_vars, partial_sharing_supported ());
33253325
}
33263326

3327+
static gboolean
3328+
is_primitive_inst (MonoGenericInst *inst)
3329+
{
3330+
for (int i = 0; i < inst->type_argc; ++i) {
3331+
if (!MONO_TYPE_IS_PRIMITIVE (inst->type_argv [i]))
3332+
return FALSE;
3333+
}
3334+
return TRUE;
3335+
}
3336+
33273337
/*
33283338
* mono_method_is_generic_impl:
33293339
* @method: a method
@@ -3350,18 +3360,45 @@ mono_method_is_generic_impl (MonoMethod *method)
33503360
static gboolean
33513361
has_constraints (MonoGenericContainer *container)
33523362
{
3353-
//int i;
3363+
int i;
33543364

3355-
return FALSE;
3356-
/*
33573365
g_assert (container->type_argc > 0);
33583366
g_assert (container->type_params);
33593367

33603368
for (i = 0; i < container->type_argc; ++i)
3361-
if (container->type_params [i].constraints)
3369+
if (container->type_params [i].info.constraints)
33623370
return TRUE;
33633371
return FALSE;
3364-
*/
3372+
}
3373+
3374+
/*
3375+
* Return whenever GPARAM can be instantiated with an enum.
3376+
*/
3377+
static gboolean
3378+
gparam_can_be_enum (MonoGenericParam *gparam)
3379+
{
3380+
if (!gparam->info.constraints)
3381+
return TRUE;
3382+
/*
3383+
* If a constraint is an interface which is not implemented by Enum, then the gparam can't be
3384+
* instantiated with an enum.
3385+
*/
3386+
for (int cindex = 0; gparam->info.constraints [cindex]; cindex ++) {
3387+
MonoClass *k = gparam->info.constraints [cindex];
3388+
if (MONO_CLASS_IS_INTERFACE_INTERNAL (k)) {
3389+
MonoClass **enum_ifaces = m_class_get_interfaces (mono_defaults.enum_class);
3390+
gboolean is_enum_iface = FALSE;
3391+
for (int i = 0; i < m_class_get_interface_count (mono_defaults.enum_class); i++) {
3392+
if (k == enum_ifaces [i]) {
3393+
is_enum_iface = TRUE;
3394+
break;
3395+
}
3396+
}
3397+
if (!is_enum_iface)
3398+
return FALSE;
3399+
}
3400+
}
3401+
return TRUE;
33653402
}
33663403

33673404
static gboolean
@@ -3488,21 +3525,39 @@ mono_method_is_generic_sharable_full (MonoMethod *method, gboolean allow_type_va
34883525

34893526
g_assert (inflated->declaring);
34903527

3528+
#if FALSE
34913529
if (inflated->declaring->is_generic) {
3492-
if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
3493-
return FALSE;
3530+
if (has_constraints (mono_method_get_generic_container (inflated->declaring))) {
3531+
}
34943532
}
3533+
#endif
34953534
}
34963535

34973536
if (mono_class_is_ginst (method->klass)) {
3498-
if (!mono_generic_context_is_sharable_full (&mono_class_get_generic_class (method->klass)->context, allow_type_vars, allow_partial))
3537+
MonoGenericContext *ctx = &mono_class_get_generic_class (method->klass)->context;
3538+
if (!mono_generic_context_is_sharable_full (ctx, allow_type_vars, allow_partial))
34993539
return FALSE;
35003540

35013541
g_assert (mono_class_get_generic_class (method->klass)->container_class &&
35023542
mono_class_is_gtd (mono_class_get_generic_class (method->klass)->container_class));
35033543

3504-
if (has_constraints (mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class)))
3505-
return FALSE;
3544+
/*
3545+
* If all the parameters are primitive types and constraints prevent
3546+
* them from being instantiated with enums, then only the primitive
3547+
* type instantiation is possible, thus sharing is not useful.
3548+
* Happens with generic math interfaces.
3549+
*/
3550+
if ((!ctx->class_inst || is_primitive_inst (ctx->class_inst)) &&
3551+
(!ctx->method_inst || is_primitive_inst (ctx->method_inst))) {
3552+
MonoGenericContainer *container = mono_class_get_generic_container (mono_class_get_generic_class (method->klass)->container_class);
3553+
if (has_constraints (container)) {
3554+
g_assert (ctx->class_inst->type_argc == container->type_argc);
3555+
for (int i = 0; i < container->type_argc; ++i) {
3556+
if (!gparam_can_be_enum (&container->type_params [i]))
3557+
return FALSE;
3558+
}
3559+
}
3560+
}
35063561
}
35073562

35083563
if (mono_class_is_gtd (method->klass) && !allow_type_vars)

0 commit comments

Comments
 (0)