Skip to content

Commit

Permalink
[mono][jit] Optimize constrained calls to object.GetHashCode () where…
Browse files Browse the repository at this point in the history
… the receiver is a gshared type constrained to a primitive type/enum. (#61513)
  • Loading branch information
vargaz authored Nov 12, 2021
1 parent e7600e0 commit 8574ce9
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -5680,12 +5680,17 @@ handle_constrained_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
gboolean constrained_is_generic_param =
m_class_get_byval_arg (constrained_class)->type == MONO_TYPE_VAR ||
m_class_get_byval_arg (constrained_class)->type == MONO_TYPE_MVAR;
MonoType *gshared_constraint = NULL;

if (constrained_is_generic_param && cfg->gshared) {
if (!mini_is_gsharedvt_klass (constrained_class)) {
g_assert (!m_class_is_valuetype (cmethod->klass));
if (!mini_type_is_reference (m_class_get_byval_arg (constrained_class)))
constrained_partial_call = TRUE;

MonoType *t = m_class_get_byval_arg (constrained_class);
MonoGenericParam *gparam = t->data.generic_param;
gshared_constraint = gparam->gshared_constraint;
}
}

Expand Down Expand Up @@ -5727,6 +5732,24 @@ handle_constrained_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
need_box = FALSE;
}

if (gshared_constraint && MONO_TYPE_IS_PRIMITIVE (gshared_constraint) && cmethod->klass == mono_defaults.object_class &&
!strcmp (cmethod->name, "GetHashCode")) {
/*
* The receiver is constrained to a primitive type or an enum with the same basetype.
* Enum.GetHashCode () returns the hash code of the underlying type (see comments in Enum.cs),
* so the constrained call can be replaced with a normal call to the basetype GetHashCode ()
* method.
*/
MonoClass *gshared_constraint_class = mono_class_from_mono_type_internal (gshared_constraint);
cmethod = get_method_nofail (gshared_constraint_class, cmethod->name, 0, 0);
g_assert (cmethod);
*ref_cmethod = cmethod;
*ref_virtual = FALSE;
if (cfg->verbose_level)
printf (" -> %s\n", mono_method_get_full_name (cmethod));
return NULL;
}

if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == m_class_get_parent (mono_defaults.enum_class) || cmethod->klass == mono_defaults.enum_class)) {
/* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, m_class_get_byval_arg (constrained_class), sp [0]->dreg, 0);
Expand Down

0 comments on commit 8574ce9

Please sign in to comment.