@@ -5680,12 +5680,17 @@ handle_constrained_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
56805680 gboolean constrained_is_generic_param =
56815681 m_class_get_byval_arg (constrained_class )-> type == MONO_TYPE_VAR ||
56825682 m_class_get_byval_arg (constrained_class )-> type == MONO_TYPE_MVAR ;
5683+ MonoType * gshared_constraint = NULL ;
56835684
56845685 if (constrained_is_generic_param && cfg -> gshared ) {
56855686 if (!mini_is_gsharedvt_klass (constrained_class )) {
56865687 g_assert (!m_class_is_valuetype (cmethod -> klass ));
56875688 if (!mini_type_is_reference (m_class_get_byval_arg (constrained_class )))
56885689 constrained_partial_call = TRUE;
5690+
5691+ MonoType * t = m_class_get_byval_arg (constrained_class );
5692+ MonoGenericParam * gparam = t -> data .generic_param ;
5693+ gshared_constraint = gparam -> gshared_constraint ;
56895694 }
56905695 }
56915696
@@ -5727,6 +5732,24 @@ handle_constrained_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
57275732 need_box = FALSE;
57285733 }
57295734
5735+ if (gshared_constraint && MONO_TYPE_IS_PRIMITIVE (gshared_constraint ) && cmethod -> klass == mono_defaults .object_class &&
5736+ !strcmp (cmethod -> name , "GetHashCode" )) {
5737+ /*
5738+ * The receiver is constrained to a primitive type or an enum with the same basetype.
5739+ * Enum.GetHashCode () returns the hash code of the underlying type (see comments in Enum.cs),
5740+ * so the constrained call can be replaced with a normal call to the basetype GetHashCode ()
5741+ * method.
5742+ */
5743+ MonoClass * gshared_constraint_class = mono_class_from_mono_type_internal (gshared_constraint );
5744+ cmethod = get_method_nofail (gshared_constraint_class , cmethod -> name , 0 , 0 );
5745+ g_assert (cmethod );
5746+ * ref_cmethod = cmethod ;
5747+ * ref_virtual = FALSE;
5748+ if (cfg -> verbose_level )
5749+ printf (" -> %s\n" , mono_method_get_full_name (cmethod ));
5750+ return NULL ;
5751+ }
5752+
57305753 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 )) {
57315754 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
57325755 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg , ins , m_class_get_byval_arg (constrained_class ), sp [0 ]-> dreg , 0 );
0 commit comments