#include "class.h"
#include "class-internals.h"
#include "marshal.h"
+#include "debug-helpers.h"
static int
type_check_context_used (MonoType *type, gboolean recursive)
/*
* 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;
* LOCKING: templates lock
*/
static MonoRuntimeGenericContextOtherInfoTemplate*
-rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int slot)
+get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
+{
+ g_assert (type_argc >= 0);
+ if (type_argc == 0)
+ return template->other_infos;
+ return g_slist_nth_data (template->method_templates, type_argc - 1);
+}
+
+/*
+ * LOCKING: templates lock
+ */
+static void
+set_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc,
+ MonoRuntimeGenericContextOtherInfoTemplate *oti)
+{
+ g_assert (type_argc >= 0);
+ if (type_argc == 0)
+ template->other_infos = oti;
+ else {
+ int length = g_slist_length (template->method_templates);
+ GSList *list;
+
+ /* FIXME: quadratic! */
+ while (length < type_argc) {
+ template->method_templates = g_slist_append (template->method_templates, NULL);
+ length++;
+ }
+
+ list = g_slist_nth (template->method_templates, type_argc - 1);
+ g_assert (list);
+ list->data = oti;
+ }
+}
+
+/*
+ * LOCKING: templates lock
+ */
+static int
+template_get_max_argc (MonoRuntimeGenericContextTemplate *template)
+{
+ return g_slist_length (template->method_templates);
+}
+
+/*
+ * LOCKING: templates lock
+ */
+static MonoRuntimeGenericContextOtherInfoTemplate*
+rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
{
int i;
MonoRuntimeGenericContextOtherInfoTemplate *oti;
g_assert (slot >= 0);
- for (oti = template->other_infos, i = 0; i < slot; oti = oti->next, ++i) {
+ for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
if (!oti)
return NULL;
}
* LOCKING: templates lock
*/
static int
-rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template)
+rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
{
MonoRuntimeGenericContextOtherInfoTemplate *oti;
int i;
- for (i = 0, oti = template->other_infos; oti; ++i, oti = oti->next)
+ for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
;
return i;
return mono_mempool_alloc0 (image->mempool, size);
}
+#define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
+
/*
* LOCKING: templates lock
*/
static void
-rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int slot,
- gpointer data, int info_type)
+rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
+ int slot, gpointer data, int info_type)
{
+ static gboolean inited = FALSE;
+ static int num_markers = 0;
+ static int num_data = 0;
+
int i;
- MonoRuntimeGenericContextOtherInfoTemplate **oti;
+ MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
+ MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
+
+ if (!inited) {
+ mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
+ mono_counters_register ("RGCTX oti num data", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_data);
+ inited = TRUE;
+ }
g_assert (slot >= 0);
g_assert (data);
mono_loader_lock ();
- oti = &template->other_infos;
i = 0;
while (i <= slot) {
if (i > 0)
++i;
}
+ mono_loader_unlock ();
+
g_assert (!(*oti)->data);
(*oti)->data = data;
(*oti)->info_type = info_type;
- mono_loader_unlock ();
+ set_other_info_templates (template, type_argc, list);
+
+ if (data == MONO_RGCTX_SLOT_USED_MARKER)
+ ++num_markers;
+ else
+ ++num_data;
}
-#define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
+/*
+ * mono_method_get_declaring_generic_method:
+ * @method: an inflated method
+ *
+ * Returns an inflated method's declaring method.
+ */
+MonoMethod*
+mono_method_get_declaring_generic_method (MonoMethod *method)
+{
+ MonoMethodInflated *inflated;
+
+ g_assert (method->is_inflated);
+
+ inflated = (MonoMethodInflated*)method;
+
+ return inflated->declaring;
+}
static gpointer
inflate_other_data (gpointer data, int info_type, MonoGenericContext *context)
return mono_class_inflate_generic_type (data, context);
case MONO_RGCTX_INFO_METHOD:
- case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
+ case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
+ case MONO_RGCTX_INFO_METHOD_RGCTX: {
MonoMethod *method = data;
MonoMethod *inflated_method;
+ MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
+ MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
+
+ 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);
method = mono_marshal_method_from_wrapper (method);
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;
}
}
static MonoRuntimeGenericContextOtherInfoTemplate
-class_get_rgctx_template_oti (MonoClass *class, guint32 slot);
+class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot);
/*
* mono_class_get_runtime_generic_context_template:
template = alloc_template (class);
mono_loader_unlock ();
+ templates_lock ();
+
if (class->parent) {
if (class->parent->generic_class) {
guint32 num_entries;
+ int max_argc, type_argc;
parent_template = mono_class_get_runtime_generic_context_template
(class->parent->generic_class->container_class);
- num_entries = rgctx_template_num_other_infos (parent_template);
- mono_loader_lock ();
+ max_argc = template_get_max_argc (parent_template);
- /* FIXME: quadratic! */
- for (i = 0; i < num_entries; ++i) {
- MonoRuntimeGenericContextOtherInfoTemplate oti;
+ for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
+ num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
- oti = class_get_rgctx_template_oti (class->parent, i);
- if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER)
- rgctx_template_set_other_slot (class->image, template, i, oti.data, oti.info_type);
- }
+ /* FIXME: quadratic! */
+ for (i = 0; i < num_entries; ++i) {
+ MonoRuntimeGenericContextOtherInfoTemplate oti;
- mono_loader_unlock ();
+ oti = class_get_rgctx_template_oti (class->parent, type_argc, i);
+ if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
+ rgctx_template_set_other_slot (class->image, template, type_argc, i,
+ oti.data, oti.info_type);
+ }
+ }
+ }
} else {
MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ int max_argc, type_argc;
parent_template = mono_class_get_runtime_generic_context_template (class->parent);
- mono_loader_lock ();
+ max_argc = template_get_max_argc (parent_template);
- /* FIXME: quadratic! */
- for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
- if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER)
- rgctx_template_set_other_slot (class->image, template, i, oti->data, oti->info_type);
+ for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
+ /* FIXME: quadratic! */
+ for (i = 0, oti = parent_template->other_infos; oti; ++i, oti = oti->next) {
+ if (oti->data && oti->data != MONO_RGCTX_SLOT_USED_MARKER) {
+ rgctx_template_set_other_slot (class->image, template, type_argc, i,
+ oti->data, oti->info_type);
+ }
+ }
}
-
- mono_loader_unlock ();
}
}
- templates_lock ();
-
if (class_lookup_rgctx_template (class)) {
/* some other thread already set the template */
template = class_lookup_rgctx_template (class);
}
static MonoRuntimeGenericContextOtherInfoTemplate
-class_get_rgctx_template_oti (MonoClass *class, guint32 slot)
+class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot)
{
if (class->generic_class) {
MonoRuntimeGenericContextOtherInfoTemplate oti;
- oti = class_get_rgctx_template_oti (class->generic_class->container_class, slot);
+ oti = class_get_rgctx_template_oti (class->generic_class->container_class, type_argc, slot);
if (oti.data)
oti.data = inflate_other_info (&oti, &class->generic_class->context);
} else {
MonoRuntimeGenericContextTemplate *template;
MonoRuntimeGenericContextOtherInfoTemplate *oti;
- guint32 i;
template = mono_class_get_runtime_generic_context_template (class);
-
- for (i = 0, oti = template->other_infos; oti; ++i, oti = oti->next) {
- if (i == slot)
- break;
- }
- g_assert (i == slot && oti);
+ oti = rgctx_template_get_other_slot (template, type_argc, slot);
+ g_assert (oti);
return *oti;
}
return mono_compile_method (data);
case MONO_RGCTX_INFO_CLASS_FIELD:
return data;
+ case MONO_RGCTX_INFO_METHOD_RGCTX: {
+ MonoMethodInflated *method = data;
+
+ 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);
+ }
default:
g_assert_not_reached ();
}
* LOCKING: templates lock
*/
static void
-fill_in_rgctx_template_slot (MonoClass *class, int index, gpointer data, int info_type)
+fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
{
MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
MonoClass *subclass;
g_assert (!class->generic_class);
- old_length = rgctx_template_num_other_infos (template);
- rgctx_template_set_other_slot (class->image, template, index, data, info_type);
- new_length = rgctx_template_num_other_infos (template);
+ old_length = rgctx_template_num_other_infos (template, type_argc);
+ rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
+ new_length = rgctx_template_num_other_infos (template, type_argc);
if (old_instances_length < 0)
old_instances_length = old_length;
g_assert (!subclass->generic_class);
g_assert (subclass_template);
- subclass_oti = class_get_rgctx_template_oti (subclass->parent, index);
+ subclass_oti = class_get_rgctx_template_oti (subclass->parent, type_argc, index);
g_assert (subclass_oti.data);
- fill_in_rgctx_template_slot (subclass, index, subclass_oti.data, info_type);
+ fill_in_rgctx_template_slot (subclass, type_argc, index, subclass_oti.data, info_type);
subclass = subclass_template->next_subclass;
}
* LOCKING: templates lock
*/
static int
-register_other_info (MonoClass *class, gpointer data, int info_type)
+register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
{
int i;
MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
MonoClass *parent;
MonoRuntimeGenericContextOtherInfoTemplate *oti;
- g_assert (!class->generic_class && class->generic_container);
-
- for (i = 0, oti = template->other_infos; oti; ++i, oti = oti->next) {
+ for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
if (!oti->data)
break;
}
parent = parent->generic_class->container_class;
parent_template = mono_class_get_runtime_generic_context_template (parent);
- oti = rgctx_template_get_other_slot (parent_template, i);
+ oti = rgctx_template_get_other_slot (parent_template, type_argc, i);
if (oti && oti->data)
break;
- rgctx_template_set_other_slot (parent->image, parent_template, i, MONO_RGCTX_SLOT_USED_MARKER, 0);
+ rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
+ MONO_RGCTX_SLOT_USED_MARKER, 0);
parent = parent->parent;
}
/* Fill in the slot in this class and in all subclasses
recursively. */
- fill_in_rgctx_template_slot (class, i, data, info_type);
+ fill_in_rgctx_template_slot (class, type_argc, i, data, info_type);
return i;
}
case MONO_RGCTX_INFO_METHOD:
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
case MONO_RGCTX_INFO_CLASS_FIELD:
+ case MONO_RGCTX_INFO_METHOD_RGCTX:
return data1 == data2;
default:
g_assert_not_reached ();
}
}
-/*
- * mono_class_lookup_or_register_other_info:
- * @class: a class
- * @data: the info data
- * @info_type: the type of info to register about data
- * @generic_context: a generic context
- *
- * Looks up and, if necessary, adds information about other_class in
- * class's runtime generic context. Returns the index of the
- * corresponding other-infos slot.
- */
-int
-mono_class_lookup_or_register_other_info (MonoClass *class, gpointer data, int info_type,
+static int
+lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
MonoGenericContext *generic_context)
{
static gboolean inited = FALSE;
MonoRuntimeGenericContextOtherInfoTemplate *oti;
int i;
- g_assert (!class->generic_class && class->generic_container);
+ g_assert (!class->generic_class);
+ g_assert (class->generic_container || type_argc);
templates_lock ();
- for (oti = rgctx_template->other_infos, i = 0; oti; oti = oti->next, ++i) {
+ for (oti = get_other_info_templates (rgctx_template, type_argc), i = 0; oti; oti = oti->next, ++i) {
gpointer inflated_data;
if (!oti || oti->info_type != info_type || !oti->data)
}
}
- i = register_other_info (class, data, info_type);
+ i = register_other_info (class, type_argc, data, info_type);
templates_unlock ();
if (i > max_slot)
max_slot = i;
-
return i;
}
+/*
+ * mono_method_lookup_or_register_other_info:
+ * @method: a method
+ * @in_mrgctx: whether to put the data into the MRGCTX
+ * @data: the info data
+ * @info_type: the type of info to register about data
+ * @generic_context: a generic context
+ *
+ * Looks up and, if necessary, adds information about other_class in
+ * method's or method's class runtime generic context. Returns the
+ * encoded slot number.
+ */
+guint32
+mono_method_lookup_or_register_other_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
+ int info_type, MonoGenericContext *generic_context)
+{
+ MonoClass *class = method->klass;
+ int type_argc, index;
+
+ if (in_mrgctx) {
+ MonoGenericInst *method_inst = mono_method_get_context (method)->method_inst;
+
+ g_assert (method->is_inflated && method_inst);
+ type_argc = method_inst->type_argc;
+ g_assert (type_argc > 0);
+ } else {
+ type_argc = 0;
+ }
+
+ index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
+
+ //g_print ("rgctx item at index %d argc %d\n", index, type_argc);
+
+ if (in_mrgctx)
+ return MONO_RGCTX_SLOT_MAKE_MRGCTX (index);
+ else
+ return MONO_RGCTX_SLOT_MAKE_RGCTX (index);
+}
+
int
-mono_class_rgctx_get_array_size (int n)
+mono_class_rgctx_get_array_size (int n, gboolean mrgctx)
{
g_assert (n >= 0 && n < 30);
- return 4 << n;
+ if (mrgctx)
+ return 6 << n;
+ else
+ return 4 << n;
}
/*
* LOCKING: domain lock
*/
static gpointer*
-alloc_rgctx_array (MonoDomain *domain, int n)
+alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
{
static gboolean inited = FALSE;
- static int num_alloced = 0;
- static int bytes_alloced = 0;
+ static int rgctx_num_alloced = 0;
+ static int rgctx_bytes_alloced = 0;
+ static int mrgctx_num_alloced = 0;
+ static int mrgctx_bytes_alloced = 0;
- int size = mono_class_rgctx_get_array_size (n) * sizeof (gpointer);
+ int size = mono_class_rgctx_get_array_size (n, is_mrgctx) * sizeof (gpointer);
gpointer array = mono_mempool_alloc0 (domain->mp, size);
if (!inited) {
- mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
- mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &bytes_alloced);
+ mono_counters_register ("RGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_num_alloced);
+ mono_counters_register ("RGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &rgctx_bytes_alloced);
+ mono_counters_register ("MRGCTX num arrays alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_num_alloced);
+ mono_counters_register ("MRGCTX bytes alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mrgctx_bytes_alloced);
inited = TRUE;
}
- num_alloced++;
- bytes_alloced += size;
+ if (is_mrgctx) {
+ mrgctx_num_alloced++;
+ mrgctx_bytes_alloced += size;
+ } else {
+ rgctx_num_alloced++;
+ rgctx_bytes_alloced += size;
+ }
return array;
}
+/*
+ * LOCKING: domain lock
+ */
+static gpointer
+fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
+ MonoGenericInst *method_inst)
+{
+ gpointer info;
+ int i, first_slot, size;
+ MonoDomain *domain = class_vtable->domain;
+ MonoClass *class = class_vtable->klass;
+ MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
+ MonoRuntimeGenericContextOtherInfoTemplate oti;
+ MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
+ int rgctx_index;
+
+ g_assert (rgctx);
+
+ /* 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);
+ for (i = 0; ; ++i) {
+ int offset;
+
+ if (method_inst && i == 0)
+ offset = sizeof (MonoMethodRuntimeGenericContext) / sizeof (gpointer);
+ else
+ offset = 0;
+
+ if (slot < first_slot + size - 1) {
+ rgctx_index = slot - first_slot + 1 + offset;
+ info = rgctx [rgctx_index];
+ if (info)
+ return info;
+ break;
+ }
+ if (!rgctx [offset + 0])
+ rgctx [offset + 0] = alloc_rgctx_array (domain, i + 1, method_inst != NULL);
+ rgctx = rgctx [offset + 0];
+ first_slot += size - 1;
+ size = mono_class_rgctx_get_array_size (i + 1, method_inst != NULL);
+ }
+
+ g_assert (!rgctx [rgctx_index]);
+
+ oti = class_get_rgctx_template_oti (class_uninstantiated (class),
+ method_inst ? method_inst->type_argc : 0, slot);
+
+ /*
+ 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);
+
+ return info;
+}
+
/*
* mono_class_fill_runtime_generic_context:
* @class_vtable: a vtable
static gboolean inited = FALSE;
static int num_alloced = 0;
- MonoRuntimeGenericContext *rgctx;
MonoDomain *domain = class_vtable->domain;
- MonoClass *class = class_vtable->klass;
- MonoGenericContext *context = &class->generic_class->context;
- MonoRuntimeGenericContextOtherInfoTemplate oti;
- int i, first_slot, size;
+ MonoRuntimeGenericContext *rgctx;
gpointer info;
mono_domain_lock (domain);
rgctx = class_vtable->runtime_generic_context;
if (!rgctx) {
- rgctx = alloc_rgctx_array (domain, 0);
+ rgctx = alloc_rgctx_array (domain, 0, FALSE);
class_vtable->runtime_generic_context = rgctx;
num_alloced++;
}
- /* 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);
- for (i = 0; ; ++i) {
- if (slot < first_slot + size - 1) {
- info = rgctx [slot - first_slot + 1];
- if (info) {
- mono_domain_unlock (domain);
- return info;
- }
- break;
- }
- if (!rgctx [0])
- rgctx [0] = alloc_rgctx_array (domain, i + 1);
- rgctx = rgctx [0];
- first_slot += size - 1;
- size = mono_class_rgctx_get_array_size (i + 1);
- }
+ info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
- g_assert (!rgctx [slot - first_slot + 1]);
+ mono_domain_unlock (domain);
- oti = class_get_rgctx_template_oti (class_uninstantiated (class), slot);
+ return info;
+}
+
+gpointer
+mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
+{
+ MonoDomain *domain = mrgctx->class_vtable->domain;
+ gpointer info;
- info = rgctx [slot - first_slot + 1] = instantiate_other_info (domain, &oti, context);
+ mono_domain_lock (domain);
+
+ info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
+ mrgctx->method_inst);
mono_domain_unlock (domain);
return info;
}
+
+static guint
+mrgctx_hash_func (gconstpointer key)
+{
+ const MonoMethodRuntimeGenericContext *mrgctx = key;
+
+ return mono_aligned_addr_hash (mrgctx->class_vtable) ^ mono_metadata_generic_inst_hash (mrgctx->method_inst);
+}
+
+static gboolean
+mrgctx_equal_func (gconstpointer a, gconstpointer b)
+{
+ const MonoMethodRuntimeGenericContext *mrgctx1 = a;
+ const MonoMethodRuntimeGenericContext *mrgctx2 = b;
+
+ return mrgctx1->class_vtable == mrgctx2->class_vtable &&
+ mono_metadata_generic_inst_equal (mrgctx1->method_inst, mrgctx2->method_inst);
+}
+
+MonoMethodRuntimeGenericContext*
+mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst)
+{
+ MonoDomain *domain = class_vtable->domain;
+ MonoMethodRuntimeGenericContext *mrgctx;
+ MonoMethodRuntimeGenericContext key;
+
+ g_assert (!class_vtable->klass->generic_container);
+ g_assert (!method_inst->is_open);
+
+ mono_domain_lock (domain);
+ if (!domain->method_rgctx_hash)
+ domain->method_rgctx_hash = g_hash_table_new (mrgctx_hash_func, mrgctx_equal_func);
+
+ key.class_vtable = class_vtable;
+ key.method_inst = method_inst;
+
+ mrgctx = g_hash_table_lookup (domain->method_rgctx_hash, &key);
+
+ if (!mrgctx) {
+ int i;
+
+ mrgctx = (MonoMethodRuntimeGenericContext*)alloc_rgctx_array (domain, 0, TRUE);
+ mrgctx->class_vtable = class_vtable;
+ mrgctx->method_inst = method_inst;
+
+ g_hash_table_insert (domain->method_rgctx_hash, mrgctx, mrgctx);
+
+ /*
+ g_print ("mrgctx alloced for %s <", mono_type_get_full_name (class_vtable->klass));
+ for (i = 0; i < method_inst->type_argc; ++i)
+ g_print ("%s, ", mono_type_full_name (method_inst->type_argv [i]));
+ g_print (">\n");
+ */
+ }
+
+ mono_domain_unlock (domain);
+
+ g_assert (mrgctx);
+
+ return mrgctx;
+}
#include "mini.h"
-static int generic_class_lookups = 0;
-static int generic_class_lookup_failures = 0;
-
/*
* mini_method_get_context:
* @method: a method
return mono_type_stack_size_internal (t, align, gsctx != NULL);
}
-/*
- * mono_method_get_declaring_generic_method:
- * @method: an inflated method
- *
- * Returns an inflated method's declaring method.
- */
-MonoMethod*
-mono_method_get_declaring_generic_method (MonoMethod *method)
-{
- MonoMethodInflated *inflated;
-
- g_assert (method->is_inflated);
-
- inflated = (MonoMethodInflated*)method;
-
- return inflated->declaring;
-}
-
-/*
- * mono_class_generic_class_relation:
- * @klass: the class to be investigated
- * @method_klass: the reference class
- * @generic_context: the generic context of method_klass
- * @arg_num: where a value will be returned
- *
- * Discovers and returns the relation of klass with reference to
- * method_klass. This can either be MINI_GENERIC_CLASS_RELATION_SELF,
- * meaning that klass is the same as method_klass,
- * MINI_GENERIC_CLASS_RELATION_ARGUMENT, meaning that klass is one of
- * the type arguments of method_klass, or otherwise
- * MINI_GENERIC_CLASS_RELATION_OTHER. In the case of
- * MINI_GENERIC_CLASS_RELATION_ARGUMENT the number of the argument is
- * returned in *arg_num.
- */
-int
-mono_class_generic_class_relation (MonoClass *klass, int info_type, MonoClass *method_klass,
- MonoGenericContext *generic_context, int *arg_num)
-{
- int i = mono_class_lookup_or_register_other_info (method_klass, &klass->byval_arg, info_type, generic_context);
-
- if (arg_num)
- *arg_num = i;
-
- return MINI_GENERIC_CLASS_RELATION_OTHER_TABLE;
-}
-
-typedef struct
-{
- guint32 token;
- MonoGenericContext *context;
-} MonoTokenAndContext;
-
-static guint
-token_context_hash (MonoTokenAndContext *tc)
-{
- return (guint)((gulong)tc->token | (gulong)tc->context->class_inst | (gulong)tc->context->method_inst);
-}
-
-static gboolean
-token_context_equal (MonoTokenAndContext *tc1, MonoTokenAndContext *tc2)
-{
- if (tc1->token != tc2->token)
- return FALSE;
-
- return tc1->context->class_inst == tc2->context->class_inst &&
- tc1->context->method_inst == tc2->context->method_inst;
-}
-
-/*
- * mono_helper_get_rgctx_other_ptr:
- * @caller_class: the klass of the calling method
- * @vtable: the vtable with the runtime generic context
- * @token: the token which to look up
- * @token_source: what kind of item the token is for
- * @rgctx_type: the kind of value requested
- *
- * Is called from method to look up a token for a given runtime
- * generic sharing context and return some particular information
- * about the looked up class (the class itself, the vtable or the
- * static_data pointer).
- */
-gpointer
-mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoVTable *vtable,
- guint32 token, guint32 token_source, guint32 rgctx_type, gint32 rgctx_index)
-{
- MonoImage *image = caller_class->image;
- MonoClass *klass = vtable->klass;
- MonoClass *result = NULL;
- MonoTokenAndContext tc = { token, &klass->generic_class->context };
- gpointer result_ptr;
-
- mono_loader_lock ();
-
- generic_class_lookups++;
-
- if (!image->generic_class_cache) {
- image->generic_class_cache = g_hash_table_new ((GHashFunc)token_context_hash,
- (GCompareFunc)token_context_equal);
- }
-
- result = g_hash_table_lookup (image->generic_class_cache, &tc);
-
- mono_loader_unlock ();
-
- if (!result) {
- generic_class_lookup_failures++;
-
- switch (token_source) {
- case MINI_TOKEN_SOURCE_FIELD: {
- MonoClassField *field = mono_field_from_token (image, token, &result, &klass->generic_class->context);
-
- g_assert (field);
- break;
- }
- case MINI_TOKEN_SOURCE_CLASS:
- result = mono_class_get_full (image, token, &klass->generic_class->context);
- break;
- case MINI_TOKEN_SOURCE_METHOD: {
- MonoMethod *cmethod = mono_get_method_full (image, token, NULL,
- &klass->generic_class->context);
- result = cmethod->klass;
- break;
- }
- default :
- g_assert_not_reached ();
- }
-
- g_assert (result);
-
- mono_class_init (result);
-
- mono_loader_lock ();
-
- /*
- * In the meantime another thread might have put this class in
- * the cache, so check again.
- */
- if (!g_hash_table_lookup (image->generic_class_cache, &tc)) {
- MonoTokenAndContext *tcp = (MonoTokenAndContext*) mono_mempool_alloc0 (image->mempool,
- sizeof (MonoTokenAndContext));
-
- *tcp = tc;
-
- g_hash_table_insert (image->generic_class_cache, tcp, result);
- }
-
- mono_loader_unlock ();
- }
-
- g_assert (result);
-
- switch (rgctx_type) {
- case MONO_RGCTX_INFO_KLASS:
- result_ptr = result;
- break;
- case MONO_RGCTX_INFO_STATIC_DATA: {
- MonoVTable *result_vtable = mono_class_vtable (vtable->domain, result);
- result_ptr = result_vtable->data;
- break;
- }
- case MONO_RGCTX_INFO_VTABLE:
- result_ptr = mono_class_vtable (vtable->domain, result);
- break;
- default:
- g_assert_not_reached ();
- }
-
- return result_ptr;
-}
-
/*
* mono_generic_sharing_init:
*
void
mono_generic_sharing_init (void)
{
- mono_counters_register ("Generic class lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT,
- &generic_class_lookups);
- mono_counters_register ("Generic class lookup failures", MONO_COUNTER_GENERICS | MONO_COUNTER_INT,
- &generic_class_lookup_failures);
}
return field;
}
-static MonoInst*
-get_runtime_generic_context_other_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, guint32 token, int token_source, int rgctx_type, unsigned char *ip, int index)
-{
- MonoInst *args [6];
- int temp;
- MonoInst *result;
-
- g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
-
- NEW_CLASSCONST (cfg, args [0], method->klass);
- args [1] = rgc_ptr;
- NEW_ICONST (cfg, args [2], token);
- NEW_ICONST (cfg, args [3], token_source);
- NEW_ICONST (cfg, args [4], rgctx_type);
- NEW_ICONST (cfg, args [5], index);
-
- temp = mono_emit_jit_icall (cfg, bblock, mono_helper_get_rgctx_other_ptr, args, ip);
- NEW_TEMPLOAD (cfg, result, temp);
-
- return result;
-}
-
static MonoInst*
get_runtime_generic_context_ptr (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
MonoClass *klass, guint32 type_token, int token_source, MonoGenericContext *generic_context, MonoInst *rgctx,
int rgctx_type, unsigned char *ip)
{
- int arg_num = -1;
- int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
+ guint32 slot = mono_method_lookup_or_register_other_info (method,
+ FALSE, &klass->byval_arg, rgctx_type, generic_context);
- switch (relation) {
- case MINI_GENERIC_CLASS_RELATION_OTHER_TABLE:
- return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
- case MINI_GENERIC_CLASS_RELATION_OTHER:
- return get_runtime_generic_context_other_ptr (cfg, method, bblock, rgctx,
- type_token, token_source, rgctx_type, ip, arg_num);
- default:
- g_assert_not_reached ();
- return NULL;
- }
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
}
static MonoInst*
get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, const unsigned char *ip)
{
- int arg_num = mono_class_lookup_or_register_other_info (method->klass, cmethod, rgctx_type, generic_context);
+ guint32 slot = mono_method_lookup_or_register_other_info (method, FALSE, cmethod, rgctx_type, generic_context);
- return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
}
static MonoInst*
MonoClassField *field, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type,
const unsigned char *ip)
{
- int arg_num = mono_class_lookup_or_register_other_info (method->klass, field, rgctx_type, generic_context);
+ guint32 slot = mono_method_lookup_or_register_other_info (method, FALSE, field, rgctx_type, generic_context);
- return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, arg_num, ip);
+ return get_runtime_generic_context_other_table_ptr (cfg, bblock, rgctx, slot, ip);
}
static gboolean
MonoClassField *field;
gpointer addr = NULL;
gboolean shared_access = FALSE;
- int relation = 0;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass->valuetype)
GENERIC_SHARING_FAILURE (*ip);
- if (context_used) {
- relation = mono_class_generic_class_relation (klass, MONO_RGCTX_INFO_VTABLE,
- method->klass, generic_context, NULL);
+ if (context_used)
shared_access = TRUE;
- }
}
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
- register_icall (mono_helper_get_rgctx_other_ptr, "get_rgctx_other_ptr", "ptr ptr ptr int32 int32 int32 int32", FALSE);
register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE);
register_icall (mono_break, "mono_break", NULL, TRUE);
register_icall (mono_create_corlib_exception_0, "mono_create_corlib_exception_0", "object int", TRUE);