From 51604aa3953731a7be592a4e034e45353abedbd1 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 14 May 2021 22:33:02 +0200 Subject: [PATCH] [mono] Fix Type equality comparisons The Mono CoreLib currently implements the equality operator for Type using an intrinsic that effectively does ReferenceEquals. However, the CLR CoreLib only does that if both sides are RuntimeType; if not, it uses the Equals predicate. This difference causes System.Text.Json.SourceGeneration to fail when built with the Mono runtime, because it uses a subtype of Type (TypeWrapper) that implements a non-default Equals predicate. The Mono logic will simply ignore that, causing various errors. Fixed by removing the Mono intrinsic and implementing Type equality in managed code in a way that should be equivalent to CoreCLR (as implemented there in RuntimeTypeHandle::TypeEQ). --- .../System.Private.CoreLib/src/System/Type.cs | 23 +++++++++++++++++++ .../src/System/Type.Mono.cs | 8 ------- src/mono/mono/mini/interp/transform.c | 2 -- src/mono/mono/mini/intrinsics.c | 7 ------ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index ca57ed53988aa..6754a69e86ab1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -428,6 +428,29 @@ protected virtual TypeCode GetTypeCodeImpl() return TypeCode.Object; } +#if !CORECLR + [Intrinsic] + public static bool operator ==(Type? left, Type? right) + { + if (object.ReferenceEquals(left, right)) + return true; + + if (left is null || right is null) + return false; + + // CLR-compat: runtime types are never equal to non-runtime types + // If `left` is a non-runtime type with a weird Equals implementation + // this is where operator `==` would differ from `Equals` call. + if (left.IsRuntimeImplemented() || right.IsRuntimeImplemented()) + return false; + + return left.Equals(right); + } + + [Intrinsic] + public static bool operator !=(Type? left, Type? right) => !(left == right); +#endif + public abstract Guid GUID { get; } [SupportedOSPlatform("windows")] diff --git a/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs index 7fa48ecb8eaf3..1981f6b1b7ef4 100644 --- a/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Type.Mono.cs @@ -133,13 +133,5 @@ internal virtual FieldInfo GetField(FieldInfo fromNoninstanciated) [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern Type internal_from_handle(IntPtr handle); - - [Intrinsic] - public static bool operator ==(Type? left, Type? right) => left == right; - - public static bool operator !=(Type? left, Type? right) - { - return !(left == right); - } } } diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index f6a710f34a49b..270b9010e57e3 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2417,8 +2417,6 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "RuntimeMethodHandle") && !strcmp (tm, "GetFunctionPointer") && csignature->param_count == 1) { // We must intrinsify this method on interp so we don't return a pointer to native code entering interpreter *op = MINT_LDFTN_DYNAMIC; - } else if (in_corlib && target_method->klass == mono_defaults.systemtype_class && !strcmp (target_method->name, "op_Equality")) { - *op = MINT_CEQ_P; } else if (in_corlib && target_method->klass == mono_defaults.object_class) { if (!strcmp (tm, "InternalGetHashCode")) *op = MINT_INTRINS_GET_HASHCODE; diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index d194525124dbd..8d1de71428122 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -1798,13 +1798,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign return ins; } } - } else if (cmethod->klass == mono_defaults.systemtype_class && !strcmp (cmethod->name, "op_Equality")) { - EMIT_NEW_BIALU (cfg, ins, OP_COMPARE, -1, args [0]->dreg, args [1]->dreg); - MONO_INST_NEW (cfg, ins, OP_PCEQ); - ins->dreg = alloc_preg (cfg); - ins->type = STACK_I4; - MONO_ADD_INS (cfg->cbb, ins); - return ins; } else if (((!strcmp (cmethod_klass_image->assembly->aname.name, "MonoMac") || !strcmp (cmethod_klass_image->assembly->aname.name, "monotouch")) && !strcmp (cmethod_klass_name_space, "XamCore.ObjCRuntime") &&