Add gsharing support for cached casts.
authorRodrigo Kumpera <kumpera@gmail.com>
Thu, 7 Oct 2010 18:45:57 +0000 (15:45 -0300)
committerRodrigo Kumpera <kumpera@gmail.com>
Thu, 7 Oct 2010 20:38:57 +0000 (17:38 -0300)
* class-internals.h: Add new kind of rgctx slot.

* method-to-ir.c (handle_castclass): Emit gsharing code
for cast with caching.

* method-to-ir.c (handle_isinst):

* mini-generic-sharing.c: Implement MONO_RGCTX_INFO_CAST_CACHE
slot type. It's a 2 word domain allocated memory block with the
cache on the first word and the vtable on the second.

This design does a single rgctx fetch instead of two. It's
a bit faster and can potentialy save some slots.

mono/metadata/class-internals.h
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c

index c1652605d5b180787466a9561029f6f052d398ff..50b11ddb834fbca408c99882c904047071b51f6f 100644 (file)
@@ -226,7 +226,8 @@ enum {
        MONO_RGCTX_INFO_METHOD_RGCTX,
        MONO_RGCTX_INFO_METHOD_CONTEXT,
        MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK,
-       MONO_RGCTX_INFO_METHOD_DELEGATE_CODE
+       MONO_RGCTX_INFO_METHOD_DELEGATE_CODE,
+       MONO_RGCTX_INFO_CAST_CACHE
 };
 
 typedef struct _MonoRuntimeGenericContextOtherInfoTemplate {
index b8483c0161fa5bfb05d93a53f1a9e8dceb2168e8..4b02af1a4e1f62156918b67e115790cdabb3c300 100644 (file)
@@ -3335,10 +3335,26 @@ handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context
        MonoInst *klass_inst = NULL;
 
        if (context_used) {
-               MonoInst *args [2];
+               MonoInst *args [3];
+
+               if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                       MonoInst *cache_ins;
+
+                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       /* obj */
+                       args [0] = src;
 
-               klass_inst = emit_get_rgctx_klass (cfg, context_used,
-                                                                                  klass, MONO_RGCTX_INFO_KLASS);
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       /* cache */
+                       args [2] = cache_ins;
+
+                       return mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args);
+               }
+
+               klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
 
                if (is_complex_isinst (klass)) {
                        /* Complex case, handle by an icall */
@@ -3412,11 +3428,28 @@ handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_us
        MonoInst *klass_inst = NULL;
 
        if (context_used) {
+               MonoInst *args [3];
+
+               if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+                       MonoInst *cache_ins;
+
+                       cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+                       /* obj */
+                       args [0] = src;
+
+                       /* klass - it's the second element of the cache entry*/
+                       EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+                       /* cache */
+                       args [2] = cache_ins;
+
+                       return mono_emit_jit_icall (cfg, mono_object_isinst_with_cache, args);
+               }
+
                klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
 
                if (is_complex_isinst (klass)) {
-                       MonoInst *args [2];
-
                        /* Complex case, handle by an icall */
 
                        /* obj */
@@ -7892,7 +7925,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /*FIXME AOT support*/
                                EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
 
-
                                ins = mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args);
                                *sp ++ = ins;
                                ip += 5;
index 28a472bfc72d89302e1d58657088e176d6295143..018054018d8d7821eff5e82ec348bbe2d0f8cf44 100644 (file)
@@ -359,6 +359,17 @@ alloc_oti (MonoImage *image)
 
 #define MONO_RGCTX_SLOT_USED_MARKER    ((gpointer)&mono_defaults.object_class->byval_arg)
 
+/*
+ * Return true if this info type has the notion of identify.
+ *
+ * Some info types expect that each insert results in a new slot been assigned.
+ */
+static int
+other_info_has_identity (int info_type)
+{
+       return info_type != MONO_RGCTX_INFO_CAST_CACHE;
+}
+
 /*
  * LOCKING: loader lock
  */
@@ -494,7 +505,8 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M
        case MONO_RGCTX_INFO_KLASS:
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
-       case MONO_RGCTX_INFO_REFLECTION_TYPE: {
+       case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE: {
                gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
                        data, context, &error);
                g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
@@ -571,6 +583,7 @@ free_inflated_info (int info_type, gpointer info)
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                mono_metadata_free_type (info);
                break;
        default:
@@ -844,6 +857,12 @@ class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
                        mono_raise_exception (mono_class_get_exception_for_failure (class));
                return vtable;
        }
+       case MONO_RGCTX_INFO_CAST_CACHE: {
+               /*First slot is the cache itself, the second the vtable.*/
+               gpointer **cache_data = mono_domain_alloc0 (domain, sizeof (gpointer) * 2);
+               cache_data [1] = (gpointer)class;
+               return cache_data;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -865,6 +884,7 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        case MONO_RGCTX_INFO_STATIC_DATA:
        case MONO_RGCTX_INFO_KLASS:
        case MONO_RGCTX_INFO_VTABLE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                temporary = TRUE;
                break;
        default:
@@ -876,7 +896,8 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        switch (oti->info_type) {
        case MONO_RGCTX_INFO_STATIC_DATA:
        case MONO_RGCTX_INFO_KLASS:
-       case MONO_RGCTX_INFO_VTABLE: {
+       case MONO_RGCTX_INFO_VTABLE:
+       case MONO_RGCTX_INFO_CAST_CACHE: {
                MonoClass *arg_class = mono_class_from_mono_type (data);
 
                free_inflated_info (oti->info_type, data);
@@ -1023,6 +1044,7 @@ other_info_equal (gpointer data1, gpointer data2, int info_type)
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
+       case MONO_RGCTX_INFO_CAST_CACHE:
                return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
        case MONO_RGCTX_INFO_METHOD:
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
@@ -1053,22 +1075,24 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, i
 
        mono_loader_lock ();
 
-       oti_list = get_other_info_templates (rgctx_template, type_argc);
+       if (other_info_has_identity (info_type)) {
+               oti_list = get_other_info_templates (rgctx_template, type_argc);
 
-       for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
-               gpointer inflated_data;
+               for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
+                       gpointer inflated_data;
 
-               if (oti->info_type != info_type || !oti->data)
-                       continue;
+                       if (oti->info_type != info_type || !oti->data)
+                               continue;
 
-               inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
+                       inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
 
-               if (other_info_equal (data, inflated_data, info_type)) {
+                       if (other_info_equal (data, inflated_data, info_type)) {
+                               free_inflated_info (info_type, inflated_data);
+                               mono_loader_unlock ();
+                               return i;
+                       }
                        free_inflated_info (info_type, inflated_data);
-                       mono_loader_unlock ();
-                       return i;
                }
-               free_inflated_info (info_type, inflated_data);
        }
 
        /* We haven't found the info */