Patch by Joel Reed that implements a few network interface counters
[mono.git] / mono / metadata / generic-sharing.c
index ee0660f59be2e7adda2271c2684f884c096fd7bb..690c87ed70f6e644f20a4f6370b4647500c4078f 100644 (file)
@@ -4,11 +4,14 @@
  * Author:
  *   Mark Probst (mark.probst@gmail.com)
  *
- * (C) 2007-2008 Novell, Inc.
+ * Copyright 2007-2009 Novell, Inc (http://www.novell.com)
  */
 
 #include <config.h>
 #include <string.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 
 #ifdef _MSC_VER
 #include <glib.h>
@@ -115,39 +118,7 @@ mono_class_check_context_used (MonoClass *class)
 }
 
 /*
- * Guards the two global rgctx (template) hash tables and all rgctx
- * templates.
- *
- * Ordering: The loader lock can be taken while the templates lock is
- * held.
- */
-static CRITICAL_SECTION templates_mutex;
-
-static void
-templates_lock (void)
-{
-       static gboolean inited = FALSE;
-
-       if (!inited) {
-               mono_loader_lock ();
-               if (!inited) {
-                       InitializeCriticalSection (&templates_mutex);
-                       inited = TRUE;
-               }
-               mono_loader_unlock ();
-       }
-
-       EnterCriticalSection (&templates_mutex);
-}
-
-static void
-templates_unlock (void)
-{
-       LeaveCriticalSection (&templates_mutex);
-}
-
-/*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static MonoRuntimeGenericContextOtherInfoTemplate*
 get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
@@ -159,10 +130,10 @@ get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static void
-set_other_info_templates (MonoMemPool *mp, MonoRuntimeGenericContextTemplate *template, int type_argc,
+set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
        MonoRuntimeGenericContextOtherInfoTemplate *oti)
 {
        g_assert (type_argc >= 0);
@@ -174,7 +145,7 @@ set_other_info_templates (MonoMemPool *mp, MonoRuntimeGenericContextTemplate *te
 
                /* FIXME: quadratic! */
                while (length < type_argc) {
-                       template->method_templates = g_slist_append_mempool (mp, template->method_templates, NULL);
+                       template->method_templates = g_slist_append_image (image, template->method_templates, NULL);
                        length++;
                }
 
@@ -185,7 +156,7 @@ set_other_info_templates (MonoMemPool *mp, MonoRuntimeGenericContextTemplate *te
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static int
 template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
@@ -194,7 +165,7 @@ template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static MonoRuntimeGenericContextOtherInfoTemplate*
 rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
@@ -213,7 +184,7 @@ rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static int
 rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
@@ -231,7 +202,7 @@ rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int
  * uninstantiated generic classes whose parent is the key class or an
  * instance of the key class.
  *
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static GHashTable *generic_subclass_hash;
 
@@ -248,7 +219,7 @@ class_set_rgctx_template (MonoClass *class, MonoRuntimeGenericContextTemplate *r
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static MonoRuntimeGenericContextTemplate*
 class_lookup_rgctx_template (MonoClass *class)
@@ -264,7 +235,7 @@ class_lookup_rgctx_template (MonoClass *class)
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static void
 register_generic_subclass (MonoClass *class)
@@ -339,21 +310,18 @@ mono_class_unregister_image_generic_subclasses (MonoImage *image)
        if (!generic_subclass_hash)
                return;
 
-       templates_lock ();
+       mono_loader_lock ();
 
        old_hash = generic_subclass_hash;
        generic_subclass_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        g_hash_table_foreach (old_hash, (GHFunc)move_subclasses_not_in_image_foreach_func, image);
 
-       templates_unlock ();
+       mono_loader_unlock ();
 
        g_hash_table_destroy (old_hash);
 }
 
-/*
- * LOCKING: loader lock
- */
 static MonoRuntimeGenericContextTemplate*
 alloc_template (MonoClass *class)
 {
@@ -375,9 +343,6 @@ alloc_template (MonoClass *class)
        return mono_image_alloc0 (class->image, size);
 }
 
-/*
- * LOCKING: loader lock
- */
 static MonoRuntimeGenericContextOtherInfoTemplate*
 alloc_oti (MonoImage *image)
 {
@@ -402,7 +367,7 @@ alloc_oti (MonoImage *image)
 #define MONO_RGCTX_SLOT_USED_MARKER    ((gpointer)&mono_defaults.object_class->byval_arg)
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static void
 rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
@@ -425,8 +390,6 @@ rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTempla
        g_assert (slot >= 0);
        g_assert (data);
 
-       mono_loader_lock ();
-
        i = 0;
        while (i <= slot) {
                if (i > 0)
@@ -436,13 +399,11 @@ rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTempla
                ++i;
        }
 
-       mono_loader_unlock ();
-
        g_assert (!(*oti)->data);
        (*oti)->data = data;
        (*oti)->info_type = info_type;
 
-       set_other_info_templates (image->mempool, template, type_argc, list);
+       set_other_info_templates (image, template, type_argc, list);
 
        if (data == MONO_RGCTX_SLOT_USED_MARKER)
                ++num_markers;
@@ -537,13 +498,14 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M
        case MONO_RGCTX_INFO_VTABLE:
        case MONO_RGCTX_INFO_TYPE:
        case MONO_RGCTX_INFO_REFLECTION_TYPE:
-               return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image->mempool,
+               return mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
                        data, context);
 
        case MONO_RGCTX_INFO_METHOD:
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
        case MONO_RGCTX_INFO_METHOD_RGCTX:
-       case MONO_RGCTX_INFO_METHOD_CONTEXT: {
+       case MONO_RGCTX_INFO_METHOD_CONTEXT:
+       case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: {
                MonoMethod *method = data;
                MonoMethod *inflated_method;
                MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
@@ -553,16 +515,15 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M
 
                mono_class_init (inflated_class);
 
-               if (method->wrapper_type != MONO_WRAPPER_NONE) {
-                       g_assert (info_type != MONO_RGCTX_INFO_METHOD_RGCTX);
-                       g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
+               g_assert (!method->wrapper_type);
 
-                       method = mono_marshal_method_from_wrapper (method);
-                       method = mono_class_inflate_generic_method (method, context);
-                       method = mono_marshal_get_static_rgctx_invoke (method);
+               if (inflated_class->byval_arg.type == MONO_TYPE_ARRAY ||
+                               inflated_class->byval_arg.type == MONO_TYPE_SZARRAY) {
+                       inflated_method = mono_method_search_in_array_class (inflated_class,
+                               method->name, method->signature);
+               } else {
+                       inflated_method = mono_class_inflate_generic_method (method, context);
                }
-
-               inflated_method = mono_class_inflate_generic_method (method, context);
                mono_class_init (inflated_method->klass);
                g_assert (inflated_method->klass == inflated_class);
                return inflated_method;
@@ -586,6 +547,8 @@ inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, M
        default:
                g_assert_not_reached ();
        }
+       /* Not reached, quiet compiler */
+       return NULL;
 }
 
 static gpointer
@@ -628,28 +591,20 @@ static MonoRuntimeGenericContextTemplate*
 mono_class_get_runtime_generic_context_template (MonoClass *class)
 {
        MonoRuntimeGenericContextTemplate *parent_template, *template;
-       MonoGenericInst *inst;
        guint32 i;
 
        g_assert (!class->generic_class);
 
-       templates_lock ();
+       mono_loader_lock ();
        template = class_lookup_rgctx_template (class);
-       templates_unlock ();
+       mono_loader_unlock ();
 
        if (template)
                return template;
 
-       if (class->generic_container)
-               inst = class->generic_container->context.class_inst;
-       else
-               inst = NULL;
-
-       mono_loader_lock ();
        template = alloc_template (class);
-       mono_loader_unlock ();
 
-       templates_lock ();
+       mono_loader_lock ();
 
        if (class->parent) {
                if (class->parent->generic_class) {
@@ -705,7 +660,7 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
                        register_generic_subclass (class);
        }
 
-       templates_unlock ();
+       mono_loader_unlock ();
 
        return template;
 }
@@ -716,6 +671,8 @@ mono_class_get_runtime_generic_context_template (MonoClass *class)
  * permanently, in which case it will be mempool-allocated.  If
  * temporary is set then *do_free will return whether the returned
  * data must be freed.
+ *
+ * LOCKING: loader lock
  */
 static MonoRuntimeGenericContextOtherInfoTemplate
 class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean *do_free)
@@ -765,15 +722,25 @@ static gpointer
 class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
 {
        switch (info_type) {
-       case MONO_RGCTX_INFO_STATIC_DATA:
-               return mono_class_vtable (domain, class)->data;
+       case MONO_RGCTX_INFO_STATIC_DATA: {
+               MonoVTable *vtable = mono_class_vtable (domain, class);
+               if (!vtable)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
+               return vtable->data;
+       }
        case MONO_RGCTX_INFO_KLASS:
                return class;
-       case MONO_RGCTX_INFO_VTABLE:
-               return mono_class_vtable (domain, class);
+       case MONO_RGCTX_INFO_VTABLE: {
+               MonoVTable *vtable = mono_class_vtable (domain, class);
+               if (!vtable)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
+               return vtable;
+       }
        default:
                g_assert_not_reached ();
        }
+       /* Not reached */
+       return NULL;
 }
 
 static gpointer
@@ -807,6 +774,12 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
                free_inflated_info (oti->info_type, data);
                g_assert (arg_class);
 
+               /* The class might be used as an argument to
+                  mono_value_copy(), which requires that its GC
+                  descriptor has been computed. */
+               if (oti->info_type == MONO_RGCTX_INFO_KLASS)
+                       mono_class_compute_gc_descriptor (arg_class);
+
                return class_type_info (domain, arg_class, oti->info_type);
        }
        case MONO_RGCTX_INFO_TYPE:
@@ -816,17 +789,26 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        case MONO_RGCTX_INFO_METHOD:
                return data;
        case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
-               return mono_compile_method (data);
+               return mono_create_ftnptr (mono_domain_get (),
+                               mono_runtime_create_jump_trampoline (mono_domain_get (), data, TRUE));
+       case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
+               return mono_create_ftnptr (mono_domain_get (),
+                               mono_runtime_create_jump_trampoline (mono_domain_get (),
+                                               mono_marshal_get_remoting_invoke_with_check (data), TRUE));
        case MONO_RGCTX_INFO_CLASS_FIELD:
                return data;
        case MONO_RGCTX_INFO_METHOD_RGCTX: {
                MonoMethodInflated *method = data;
+               MonoVTable *vtable;
 
                g_assert (method->method.method.is_inflated);
                g_assert (method->context.method_inst);
 
-               return mono_method_lookup_rgctx (mono_class_vtable (domain, method->method.method.klass),
-                       method->context.method_inst);
+               vtable = mono_class_vtable (domain, method->method.method.klass);
+               if (!vtable)
+                       mono_raise_exception (mono_class_get_exception_for_failure (method->method.method.klass));
+
+               return mono_method_lookup_rgctx (vtable, method->context.method_inst);
        }
        case MONO_RGCTX_INFO_METHOD_CONTEXT: {
                MonoMethodInflated *method = data;
@@ -839,10 +821,12 @@ instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTe
        default:
                g_assert_not_reached ();
        }
+       /* Not reached */
+       return NULL;
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static void
 fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
@@ -877,7 +861,7 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
 }
 
 /*
- * LOCKING: templates lock
+ * LOCKING: loader lock
  */
 static int
 register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
@@ -938,10 +922,13 @@ other_info_equal (gpointer data1, gpointer data2, int info_type)
        case MONO_RGCTX_INFO_CLASS_FIELD:
        case MONO_RGCTX_INFO_METHOD_RGCTX:
        case MONO_RGCTX_INFO_METHOD_CONTEXT:
+       case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
                return data1 == data2;
        default:
                g_assert_not_reached ();
        }
+       /* never reached */
+       return FALSE;
 }
 
 static int
@@ -953,33 +940,36 @@ lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, i
 
        MonoRuntimeGenericContextTemplate *rgctx_template =
                mono_class_get_runtime_generic_context_template (class);
-       MonoRuntimeGenericContextOtherInfoTemplate *oti;
+       MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
        int i;
 
        g_assert (!class->generic_class);
        g_assert (class->generic_container || type_argc);
 
-       templates_lock ();
+       mono_loader_lock ();
+
+       oti_list = get_other_info_templates (rgctx_template, type_argc);
 
-       for (oti = get_other_info_templates (rgctx_template, type_argc), i = 0; oti; oti = oti->next, ++i) {
+       for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
                gpointer inflated_data;
 
-               if (!oti || oti->info_type != info_type || !oti->data)
+               if (oti->info_type != info_type || !oti->data)
                        continue;
 
                inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
 
                if (other_info_equal (data, inflated_data, info_type)) {
-                       templates_unlock ();
-                       free_inflated_info (oti->info_type, inflated_data);
+                       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 */
        i = register_other_info (class, type_argc, data, info_type);
 
-       templates_unlock ();
+       mono_loader_unlock ();
 
        if (!inited) {
                mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
@@ -1084,9 +1074,6 @@ alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
        return array;
 }
 
-/*
- * LOCKING: domain lock
- */
 static gpointer
 fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
                MonoGenericInst *method_inst)
@@ -1103,26 +1090,30 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
 
        g_assert (rgctx);
 
+       mono_domain_lock (domain);
+
        /* First check whether that slot isn't already instantiated.
           This might happen because lookup doesn't lock.  Allocate
           arrays on the way. */
        first_slot = 0;
        size = mono_class_rgctx_get_array_size (0, method_inst != NULL);
        if (method_inst)
-               size -= sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
+               size -= MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
        for (i = 0; ; ++i) {
                int offset;
 
                if (method_inst && i == 0)
-                       offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
+                       offset = MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
                else
                        offset = 0;
 
                if (slot < first_slot + size - 1) {
                        rgctx_index = slot - first_slot + 1 + offset;
                        info = rgctx [rgctx_index];
-                       if (info)
+                       if (info) {
+                               mono_domain_unlock (domain);
                                return info;
+                       }
                        break;
                }
                if (!rgctx [offset + 0])
@@ -1134,15 +1125,29 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
 
        g_assert (!rgctx [rgctx_index]);
 
+       mono_domain_unlock (domain);
+
        oti = class_get_rgctx_template_oti (class_uninstantiated (class),
                        method_inst ? method_inst->type_argc : 0, slot, TRUE, &do_free);
+       /* This might take the loader lock */
+       info = instantiate_other_info (domain, &oti, &context, class);
 
        /*
        if (method_inst)
                g_print ("filling mrgctx slot %d table %d index %d\n", slot, i, rgctx_index);
        */
 
-       info = rgctx [rgctx_index] = instantiate_other_info (domain, &oti, &context, class);
+       /*FIXME We should use CAS here, no need to take a lock.*/
+       mono_domain_lock (domain);
+
+       /* Check whether the slot hasn't been instantiated in the
+          meantime. */
+       if (rgctx [rgctx_index])
+               info = rgctx [rgctx_index];
+       else
+               rgctx [rgctx_index] = info;
+
+       mono_domain_unlock (domain);
 
        if (do_free)
                free_inflated_info (oti.info_type, oti.data);
@@ -1181,10 +1186,10 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
                num_alloced++;
        }
 
-       info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
-
        mono_domain_unlock (domain);
 
+       info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
+
        return info;
 }
 
@@ -1198,16 +1203,11 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
 gpointer
 mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
 {
-       MonoDomain *domain = mrgctx->class_vtable->domain;
        gpointer info;
 
-       mono_domain_lock (domain);
-
        info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
                mrgctx->method_inst);
 
-       mono_domain_unlock (domain);
-
        return info;
 }
 
@@ -1236,6 +1236,8 @@ mrgctx_equal_func (gconstpointer a, gconstpointer b)
  *
  * Returns the MRGCTX for the generic method(s) with the given
  * method_inst of the given class_vtable.
+ *
+ * LOCKING: Take the domain lock.
  */
 MonoMethodRuntimeGenericContext*
 mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
@@ -1348,6 +1350,23 @@ mono_method_is_generic_impl (MonoMethod *method)
        return FALSE;
 }
 
+static gboolean
+has_constraints (MonoGenericContainer *container)
+{
+       //int i;
+
+       return FALSE;
+       /*
+       g_assert (container->type_argc > 0);
+       g_assert (container->type_params);
+
+       for (i = 0; i < container->type_argc; ++i)
+               if (container->type_params [i].constraints)
+                       return TRUE;
+       return FALSE;
+       */
+}
+
 /*
  * mono_method_is_generic_sharable_impl:
  * @method: a method
@@ -1373,9 +1392,7 @@ mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_va
                g_assert (inflated->declaring);
 
                if (inflated->declaring->is_generic) {
-                       g_assert (mono_method_get_generic_container (inflated->declaring)->type_params);
-
-                       if (mono_method_get_generic_container (inflated->declaring)->type_params->constraints)
+                       if (has_constraints (mono_method_get_generic_container (inflated->declaring)))
                                return FALSE;
                }
        }
@@ -1385,10 +1402,9 @@ mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_va
                        return FALSE;
 
                g_assert (method->klass->generic_class->container_class &&
-                               method->klass->generic_class->container_class->generic_container &&
-                               method->klass->generic_class->container_class->generic_container->type_params);
+                               method->klass->generic_class->container_class->generic_container);
 
-               if (method->klass->generic_class->container_class->generic_container->type_params->constraints)
+               if (has_constraints (method->klass->generic_class->container_class->generic_container))
                        return FALSE;
        }
 
@@ -1414,3 +1430,91 @@ mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_v
                        method->klass->valuetype) &&
                (method->klass->generic_class || method->klass->generic_container);
 }
+
+static MonoGenericInst*
+get_object_generic_inst (int type_argc)
+{
+       MonoType **type_argv;
+       int i;
+
+       type_argv = alloca (sizeof (MonoType*) * type_argc);
+
+       for (i = 0; i < type_argc; ++i)
+               type_argv [i] = &mono_defaults.object_class->byval_arg;
+
+       return mono_metadata_get_generic_inst (type_argc, type_argv);
+}
+
+/*
+ * mono_method_construct_object_context:
+ * @method: a method
+ *
+ * Returns a generic context for method with all type variables for
+ * class and method instantiated with Object.
+ */
+MonoGenericContext
+mono_method_construct_object_context (MonoMethod *method)
+{
+       MonoGenericContext object_context;
+
+       g_assert (!method->klass->generic_class);
+       if (method->klass->generic_container) {
+               int type_argc = method->klass->generic_container->type_argc;
+
+               object_context.class_inst = get_object_generic_inst (type_argc);
+       } else {
+               object_context.class_inst = NULL;
+       }
+
+       if (mono_method_get_context_general (method, TRUE)->method_inst) {
+               int type_argc = mono_method_get_context_general (method, TRUE)->method_inst->type_argc;
+
+               object_context.method_inst = get_object_generic_inst (type_argc);
+       } else {
+               object_context.method_inst = NULL;
+       }
+
+       g_assert (object_context.class_inst || object_context.method_inst);
+
+       return object_context;
+}
+
+/*
+ * mono_domain_lookup_shared_generic:
+ * @domain: a domain
+ * @open_method: an open generic method
+ *
+ * Looks up the jit info for method via the domain's jit code hash.
+ */
+MonoJitInfo*
+mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *open_method)
+{
+       static gboolean inited = FALSE;
+       static int lookups = 0;
+       static int failed_lookups = 0;
+
+       MonoGenericContext object_context;
+       MonoMethod *object_method;
+       MonoJitInfo *ji;
+
+       object_context = mono_method_construct_object_context (open_method);
+       object_method = mono_class_inflate_generic_method (open_method, &object_context);
+
+       mono_domain_jit_code_hash_lock (domain);
+       ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
+       if (ji && !ji->has_generic_jit_info)
+               ji = NULL;
+       mono_domain_jit_code_hash_unlock (domain);
+
+       if (!inited) {
+               mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
+               mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
+               inited = TRUE;
+       }
+
+       ++lookups;
+       if (!ji)
+               ++failed_lookups;
+
+       return ji;
+}