[jit] Implement RuntimeHelpers.IsReferenceOrContainsReferences intrinsic. Fixes ...
authorZoltan Varga <vargaz@gmail.com>
Sun, 12 Mar 2017 04:43:37 +0000 (23:43 -0500)
committerGitHub <noreply@github.com>
Sun, 12 Mar 2017 04:43:37 +0000 (23:43 -0500)
mono/mini/generics.cs
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c
mono/mini/mini.h

index 929d4718bcd33cc24117560fd066ca0b3f87a10f..e9b41a64e08ab33fe63924edf89aeec83d2b0b52 100644 (file)
@@ -1308,6 +1308,68 @@ class Tests
                c.throw_catch_t ();
                return 0;
        }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static bool is_ref_or_contains_refs<T> () {
+               return RuntimeHelpers.IsReferenceOrContainsReferences<T> ();
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static bool is_ref_or_contains_refs_gen_ref<T> () {
+               return RuntimeHelpers.IsReferenceOrContainsReferences<GenStruct<T>> ();
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static bool is_ref_or_contains_refs_gen_noref<T> () {
+               return RuntimeHelpers.IsReferenceOrContainsReferences<NoRefGenStruct<T>> ();
+       }
+
+       struct GenStruct<T> {
+               T t;
+       }
+
+       struct NoRefGenStruct<T> {
+       }
+
+       struct RefStruct {
+               string s;
+       }
+
+       struct NestedRefStruct {
+               RefStruct r;
+       }
+
+       struct NoRefStruct {
+               int i;
+       }
+
+       public static int test_0_isreference_intrins () {
+               if (RuntimeHelpers.IsReferenceOrContainsReferences<int> ())
+                       return 1;
+               if (!RuntimeHelpers.IsReferenceOrContainsReferences<string> ())
+                       return 2;
+               if (!RuntimeHelpers.IsReferenceOrContainsReferences<RefStruct> ())
+                       return 3;
+               if (!RuntimeHelpers.IsReferenceOrContainsReferences<NestedRefStruct> ())
+                       return 4;
+               if (RuntimeHelpers.IsReferenceOrContainsReferences<NoRefStruct> ())
+                       return 5;
+               // Generic code
+               if (is_ref_or_contains_refs<int> ())
+                       return 6;
+               // Shared code
+               if (!is_ref_or_contains_refs<string> ())
+                       return 7;
+               // Complex type from shared code
+               if (!is_ref_or_contains_refs_gen_ref<string> ())
+                       return 8;
+               if (is_ref_or_contains_refs_gen_ref<int> ())
+                       return 9;
+               if (is_ref_or_contains_refs_gen_noref<string> ())
+                       return 10;
+
+               return 0;
+       }
 }
 
 #if !__MOBILE__
index 78d0c219216cd033ca369312d2963955f063beb1..6e28f2a0e60938c7a9cedd1f3827de7fec3a0617 100644 (file)
@@ -5242,8 +5242,7 @@ static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
        MonoInst *ins = NULL;
-
-        MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
+       MonoClass *runtime_helpers_class = mono_class_get_runtime_helpers_class ();
 
        if (cmethod->klass == mono_defaults.string_class) {
                if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
@@ -5389,6 +5388,37 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        } else if (cmethod->klass == runtime_helpers_class) {
                if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
                        EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
+                       return ins;
+               } else if (strcmp (cmethod->name, "IsReferenceOrContainsReferences") == 0 && fsig->param_count == 0) {
+                       MonoGenericContext *ctx = mono_method_get_context (cmethod);
+                       g_assert (ctx);
+                       g_assert (ctx->method_inst);
+                       g_assert (ctx->method_inst->type_argc == 1);
+                       MonoType *t = mini_get_underlying_type (ctx->method_inst->type_argv [0]);
+                       MonoClass *klass = mono_class_from_mono_type (t);
+
+                       ins = NULL;
+
+                       mono_class_init (klass);
+                       if (MONO_TYPE_IS_REFERENCE (t))
+                               EMIT_NEW_ICONST (cfg, ins, 1);
+                       else if (MONO_TYPE_IS_PRIMITIVE (t))
+                               EMIT_NEW_ICONST (cfg, ins, 0);
+                       else if (cfg->gshared && (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (t))
+                               EMIT_NEW_ICONST (cfg, ins, 1);
+                       else if (!cfg->gshared || !mini_class_check_context_used (cfg, klass))
+                               EMIT_NEW_ICONST (cfg, ins, klass->has_references ? 1 : 0);
+                       else {
+                               g_assert (cfg->gshared);
+
+                               int context_used = mini_class_check_context_used (cfg, klass);
+
+                               /* This returns 1 or 2 */
+                               MonoInst *info = mini_emit_get_rgctx_klass (cfg, context_used, klass,   MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS);
+                               int dreg = alloc_ireg (cfg);
+                               EMIT_NEW_BIALU_IMM (cfg, ins, OP_ISUB_IMM, dreg, info->dreg, 1);
+                       }
+
                        return ins;
                } else
                        return NULL;
index 65ce24f3afc7bfbbf421b5676ae57c35cb9b48f4..58fcaac9c82d59ae4b4317013f16d5531c6c2202 100644 (file)
@@ -532,6 +532,7 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_LOCAL_OFFSET:
@@ -913,6 +914,13 @@ class_type_info (MonoDomain *domain, MonoClass *klass, MonoRgctxInfoType info_ty
                        return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
                else
                        return GUINT_TO_POINTER (MONO_GSHAREDVT_BOX_TYPE_VTYPE);
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
+               mono_class_init (klass);
+               /* Can't return 0 */
+               if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg) || klass->has_references)
+                       return GUINT_TO_POINTER (2);
+               else
+                       return GUINT_TO_POINTER (1);
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO: {
                static MonoMethod *memcpy_method [17];
@@ -1566,6 +1574,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
@@ -2007,6 +2016,7 @@ mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
        case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE: return "CLASS_BOX_TYPE";
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS: return "CLASS_IS_REF_OR_CONTAINS_REFS";
        case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
        case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
@@ -2095,6 +2105,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
@@ -2148,6 +2159,7 @@ mini_rgctx_info_type_to_patch_info_type (MonoRgctxInfoType info_type)
        case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
        case MONO_RGCTX_INFO_VALUE_SIZE:
        case MONO_RGCTX_INFO_CLASS_BOX_TYPE:
+       case MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS:
        case MONO_RGCTX_INFO_MEMCPY:
        case MONO_RGCTX_INFO_BZERO:
        case MONO_RGCTX_INFO_NULLABLE_CLASS_BOX:
index a9c6f3209b467576ddbf6540a121086a603b4030..e7fc859c250c3b22c299c1d6b94ace2ec2e3bb92 100644 (file)
@@ -1277,6 +1277,8 @@ typedef enum {
         * which implements the method.
         */
        MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE,
+       /* Resolve to 2 (TRUE) or 1 (FALSE) */
+       MONO_RGCTX_INFO_CLASS_IS_REF_OR_CONTAINS_REFS
 } MonoRgctxInfoType;
 
 typedef struct _MonoRuntimeGenericContextInfoTemplate {