* Author:
* Mark Probst (mark.probst@gmail.com)
*
- * (C) 2007 Novell, Inc.
+ * Copyright 2007-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
#include <config.h>
//#define ALLOW_PARTIAL_SHARING TRUE
#define ALLOW_PARTIAL_SHARING FALSE
+
+#if 0
+#define DEBUG(...) __VA_ARGS__
+#else
+#define DEBUG(...)
+#endif
static void
mono_class_unregister_image_generic_subclasses (MonoImage *image, gpointer user_data);
+static MonoType*
+mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t);
+
static int
type_check_context_used (MonoType *type, gboolean recursive)
{
/*
* LOCKING: loader lock
*/
-static MonoRuntimeGenericContextOtherInfoTemplate*
-get_other_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
+static MonoRuntimeGenericContextInfoTemplate*
+get_info_templates (MonoRuntimeGenericContextTemplate *template, int type_argc)
{
g_assert (type_argc >= 0);
if (type_argc == 0)
- return template->other_infos;
+ return template->infos;
return g_slist_nth_data (template->method_templates, type_argc - 1);
}
* LOCKING: loader lock
*/
static void
-set_other_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
- MonoRuntimeGenericContextOtherInfoTemplate *oti)
+set_info_templates (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
+ MonoRuntimeGenericContextInfoTemplate *oti)
{
g_assert (type_argc >= 0);
if (type_argc == 0)
- template->other_infos = oti;
+ template->infos = oti;
else {
int length = g_slist_length (template->method_templates);
GSList *list;
/*
* LOCKING: loader lock
*/
-static MonoRuntimeGenericContextOtherInfoTemplate*
+static MonoRuntimeGenericContextInfoTemplate*
rgctx_template_get_other_slot (MonoRuntimeGenericContextTemplate *template, int type_argc, int slot)
{
int i;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti;
g_assert (slot >= 0);
- for (oti = get_other_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
+ for (oti = get_info_templates (template, type_argc), i = 0; i < slot; oti = oti->next, ++i) {
if (!oti)
return NULL;
}
* LOCKING: loader lock
*/
static int
-rgctx_template_num_other_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
+rgctx_template_num_infos (MonoRuntimeGenericContextTemplate *template, int type_argc)
{
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti;
int i;
- for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next)
+ for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next)
;
return i;
return mono_image_alloc0 (class->image, size);
}
-static MonoRuntimeGenericContextOtherInfoTemplate*
+static MonoRuntimeGenericContextInfoTemplate*
alloc_oti (MonoImage *image)
{
static gboolean inited = FALSE;
static int num_allocted = 0;
static int num_bytes = 0;
- int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
+ int size = sizeof (MonoRuntimeGenericContextInfoTemplate);
if (!inited) {
mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
* Some info types expect that each insert results in a new slot been assigned.
*/
static int
-other_info_has_identity (int info_type)
+info_has_identity (MonoRgctxInfoType info_type)
{
return info_type != MONO_RGCTX_INFO_CAST_CACHE;
}
* LOCKING: loader lock
*/
static void
-rgctx_template_set_other_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
- int slot, gpointer data, int info_type)
+rgctx_template_set_slot (MonoImage *image, MonoRuntimeGenericContextTemplate *template, int type_argc,
+ int slot, gpointer data, MonoRgctxInfoType info_type)
{
static gboolean inited = FALSE;
static int num_markers = 0;
static int num_data = 0;
int i;
- MonoRuntimeGenericContextOtherInfoTemplate *list = get_other_info_templates (template, type_argc);
- MonoRuntimeGenericContextOtherInfoTemplate **oti = &list;
+ MonoRuntimeGenericContextInfoTemplate *list = get_info_templates (template, type_argc);
+ MonoRuntimeGenericContextInfoTemplate **oti = &list;
if (!inited) {
mono_counters_register ("RGCTX oti num markers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_markers);
(*oti)->data = data;
(*oti)->info_type = info_type;
- set_other_info_templates (image, template, type_argc, list);
+ set_info_templates (image, template, type_argc, list);
if (data == MONO_RGCTX_SLOT_USED_MARKER)
++num_markers;
}
static gpointer
-inflate_other_data (gpointer data, int info_type, MonoGenericContext *context, MonoClass *class, gboolean temporary)
+inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *context, MonoClass *class, gboolean temporary)
{
+ gpointer data = oti->data;
+ MonoRgctxInfoType info_type = oti->info_type;
MonoError error;
g_assert (data);
case MONO_RGCTX_INFO_VTABLE:
case MONO_RGCTX_INFO_TYPE:
case MONO_RGCTX_INFO_REFLECTION_TYPE:
- case MONO_RGCTX_INFO_CAST_CACHE: {
+ case MONO_RGCTX_INFO_CAST_CACHE:
+ case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+ case MONO_RGCTX_INFO_VALUE_SIZE:
+ case MONO_RGCTX_INFO_CLASS_IS_REF: {
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*/
case MONO_RGCTX_INFO_METHOD_RGCTX:
case MONO_RGCTX_INFO_METHOD_CONTEXT:
case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
- case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: {
+ case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
MonoMethod *method = data;
MonoMethod *inflated_method;
MonoType *inflated_type = mono_class_inflate_generic_type (&method->klass->byval_arg, context);
return inflated_method;
}
- case MONO_RGCTX_INFO_CLASS_FIELD: {
+ case MONO_RGCTX_INFO_CLASS_FIELD:
+ case MONO_RGCTX_INFO_FIELD_OFFSET: {
MonoClassField *field = data;
MonoType *inflated_type = mono_class_inflate_generic_type (&field->parent->byval_arg, context);
MonoClass *inflated_class = mono_class_from_mono_type (inflated_type);
return NULL;
}
-static gpointer
-inflate_other_info (MonoRuntimeGenericContextOtherInfoTemplate *oti,
- MonoGenericContext *context, MonoClass *class, gboolean temporary)
-{
- return inflate_other_data (oti->data, oti->info_type, context, class, temporary);
-}
-
static void
-free_inflated_info (int info_type, gpointer info)
+free_inflated_info (MonoRgctxInfoType info_type, gpointer info)
{
if (!info)
return;
}
}
-static MonoRuntimeGenericContextOtherInfoTemplate
+static MonoRuntimeGenericContextInfoTemplate
class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free);
static MonoClass*
*/
//g_assert_not_reached ();
+ /* The gsharedvt changes break this */
+ if (ALLOW_PARTIAL_SHARING)
+ g_assert_not_reached ();
+
+#if 0
if (class->is_inflated) {
MonoGenericContext *context = &class->generic_class->context;
MonoGenericContext *container_context;
return class;
}
}
+#endif
return class_uninstantiated (class);
}
* mono_class_get_runtime_generic_context_template:
* @class: a class
*
- * Looks up or constructs, if necessary, the runtime generic context
- * for class.
+ * Looks up or constructs, if necessary, the runtime generic context template for class.
+ * The template is the same for all instantiations of a class.
*/
static MonoRuntimeGenericContextTemplate*
mono_class_get_runtime_generic_context_template (MonoClass *class)
MonoRuntimeGenericContextTemplate *parent_template, *template;
guint32 i;
+ class = get_shared_class (class);
+
mono_loader_lock ();
template = class_lookup_rgctx_template (class);
mono_loader_unlock ();
mono_loader_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);
+ guint32 num_entries;
+ int max_argc, type_argc;
- max_argc = template_get_max_argc (parent_template);
+ parent_template = mono_class_get_runtime_generic_context_template (class->parent);
+ max_argc = template_get_max_argc (parent_template);
- for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
- num_entries = rgctx_template_num_other_infos (parent_template, type_argc);
+ for (type_argc = 0; type_argc <= max_argc; ++type_argc) {
+ num_entries = rgctx_template_num_infos (parent_template, type_argc);
- /* FIXME: quadratic! */
- for (i = 0; i < num_entries; ++i) {
- MonoRuntimeGenericContextOtherInfoTemplate oti;
+ /* FIXME: quadratic! */
+ for (i = 0; i < num_entries; ++i) {
+ MonoRuntimeGenericContextInfoTemplate oti;
- oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
- 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);
-
- max_argc = template_get_max_argc (parent_template);
-
- 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);
- }
+ oti = class_get_rgctx_template_oti (class->parent, type_argc, i, FALSE, FALSE, NULL);
+ if (oti.data && oti.data != MONO_RGCTX_SLOT_USED_MARKER) {
+ rgctx_template_set_slot (class->image, template, type_argc, i,
+ oti.data, oti.info_type);
}
}
}
}
/*
+ * class_get_rgctx_template_oti:
+ *
+ * Return the info template of CLASS numbered TYPE_ARGC/SLOT.
* temporary signifies whether the inflated info (oti.data) will be
* used temporarily, in which case it might be heap-allocated, or
* permanently, in which case it will be mempool-allocated. If
*
* LOCKING: loader lock
*/
-static MonoRuntimeGenericContextOtherInfoTemplate
+static MonoRuntimeGenericContextInfoTemplate
class_get_rgctx_template_oti (MonoClass *class, int type_argc, guint32 slot, gboolean temporary, gboolean shared, gboolean *do_free)
{
g_assert ((temporary && do_free) || (!temporary && !do_free));
+ DEBUG (printf ("get slot: %s %d\n", mono_type_full_name (&class->byval_arg), slot));
+
if (class->generic_class && !shared) {
- MonoRuntimeGenericContextOtherInfoTemplate oti;
+ MonoRuntimeGenericContextInfoTemplate oti;
gboolean tmp_do_free;
oti = class_get_rgctx_template_oti (class->generic_class->container_class,
type_argc, slot, TRUE, FALSE, &tmp_do_free);
if (oti.data) {
gpointer info = oti.data;
- oti.data = inflate_other_info (&oti, &class->generic_class->context, class, temporary);
+ oti.data = inflate_info (&oti, &class->generic_class->context, class, temporary);
if (tmp_do_free)
free_inflated_info (oti.info_type, info);
}
return oti;
} else {
MonoRuntimeGenericContextTemplate *template;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti;
template = mono_class_get_runtime_generic_context_template (class);
oti = rgctx_template_get_other_slot (template, type_argc, slot);
}
static gpointer
-class_type_info (MonoDomain *domain, MonoClass *class, int info_type)
+class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_type)
{
switch (info_type) {
case MONO_RGCTX_INFO_STATIC_DATA: {
cache_data [1] = (gpointer)class;
return cache_data;
}
+ case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+ return GUINT_TO_POINTER (mono_class_array_element_size (class));
+ case MONO_RGCTX_INFO_VALUE_SIZE:
+ if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
+ return GUINT_TO_POINTER (sizeof (gpointer));
+ else
+ return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
+ case MONO_RGCTX_INFO_CLASS_IS_REF:
+ if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
+ return GUINT_TO_POINTER (1);
+ else
+ return GUINT_TO_POINTER (0);
default:
g_assert_not_reached ();
}
return NULL;
}
+static gboolean
+ji_is_gsharedvt (MonoJitInfo *ji)
+{
+ if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
+ mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
+ return TRUE;
+ else
+ return FALSE;
+}
+
static gpointer
-instantiate_other_info (MonoDomain *domain, MonoRuntimeGenericContextOtherInfoTemplate *oti,
- MonoGenericContext *context, MonoClass *class)
+instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
+ MonoGenericContext *context, MonoClass *class, guint8 *caller)
{
gpointer data;
gboolean temporary;
temporary = FALSE;
}
- data = inflate_other_info (oti, context, class, temporary);
+ data = inflate_info (oti, context, class, temporary);
switch (oti->info_type) {
case MONO_RGCTX_INFO_STATIC_DATA:
case MONO_RGCTX_INFO_KLASS:
case MONO_RGCTX_INFO_VTABLE:
- case MONO_RGCTX_INFO_CAST_CACHE: {
+ case MONO_RGCTX_INFO_CAST_CACHE:
+ case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+ case MONO_RGCTX_INFO_VALUE_SIZE:
+ case MONO_RGCTX_INFO_CLASS_IS_REF: {
MonoClass *arg_class = mono_class_from_mono_type (data);
free_inflated_info (oti->info_type, data);
return mono_domain_alloc0 (domain, sizeof (gpointer));
case MONO_RGCTX_INFO_CLASS_FIELD:
return data;
+ case MONO_RGCTX_INFO_FIELD_OFFSET: {
+ MonoClassField *field = data;
+
+ if (field->parent->valuetype && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ return GUINT_TO_POINTER (field->offset - sizeof (MonoObject));
+ else
+ return GUINT_TO_POINTER (field->offset);
+ }
case MONO_RGCTX_INFO_METHOD_RGCTX: {
MonoMethodInflated *method = data;
MonoVTable *vtable;
return method->context.method_inst;
}
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: {
+ MonoMethod *caller_method = oti->data;
+ MonoMethod *method = data;
+ gpointer addr;
+ MonoJitInfo *caller_ji, *ji;
+ gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+ gint32 vcall_offset;
+ MonoGenericJitInfo *gji;
+
+ g_assert (method->is_inflated);
+
+ if (!virtual)
+ addr = mono_compile_method (method);
+ else
+ addr = NULL;
+
+ if (virtual) {
+ /* Same as in mono_emit_method_call_full () */
+#ifndef MONO_ARCH_HAVE_IMT
+ NOT_IMPLEMENTED;
+#endif
+ if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ guint32 imt_slot = mono_method_get_imt_slot (method);
+ vcall_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
+ } else {
+ vcall_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
+ ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
+ }
+ } else {
+ vcall_offset = -1;
+ }
+
+ g_assert (caller);
+ caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
+ g_assert (caller_ji);
+ gji = mono_jit_info_get_generic_jit_info (caller_ji);
+ g_assert (gji);
+
+ /*
+ * For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
+ * non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
+ * call through the rgctx, in effect patching the rgctx entry instead of the call site.
+ * For virtual calls, the caller might be a normal or a gsharedvt method. Since there is only one vtable slot,
+ * this difference needs to be handed on the caller side. This is currently implemented by adding a gsharedvt-in
+ * trampoline to all gsharedvt methods and storing this trampoline into the vtable slot. Virtual calls made from
+ * gsharedvt methods always go through a gsharedvt-out trampoline, so the calling sequence is:
+ * caller -> out trampoline -> in trampoline -> callee
+ * This is not very efficient, but it is easy to implement.
+ */
+ // FIXME: This loads information from AOT
+ ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr), NULL);
+ if (virtual || !ji_is_gsharedvt (ji)) {
+ static gpointer tramp_addr;
+ gpointer info;
+ MonoMethod *wrapper;
+ MonoMethod *gm;
+
+ g_assert (method->is_inflated);
+
+ /* Have to pass TRUE for is_gshared since METHOD might not be gsharedvt but we need its shared version */
+ gm = mini_get_shared_method_full (method, FALSE, TRUE);
+ g_assert (gm != method);
+
+ gm = caller_method;
+
+ info = mono_arch_get_gsharedvt_call_info (addr, method, gm, gji->generic_sharing_context, FALSE, vcall_offset);
+
+ if (!tramp_addr) {
+ wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
+ addr = mono_compile_method (wrapper);
+ mono_memory_barrier ();
+ tramp_addr = addr;
+ }
+ addr = tramp_addr;
+
+ if (mono_aot_only)
+ addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
+ else
+ addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
+
+#if 0
+ if (virtual)
+ printf ("OUT-VCALL: %s\n", mono_method_full_name (method, TRUE));
+ else
+ printf ("OUT: %s\n", mono_method_full_name (method, TRUE));
+#endif
+ } else if (!mini_is_gsharedvt_variable_signature (mono_method_signature (caller_method)) && ji_is_gsharedvt (ji)) {
+ /* This is the IN case handled by mini_add_method_trampoline () */
+ static gpointer tramp_addr;
+ gpointer info;
+ MonoMethod *wrapper;
+
+ //
+ // FIXME:
+ // This is a combination of the normal in and out cases, since the caller is a gsharedvt method.
+ // A trampoline is not always needed, but its hard to determine when it can be omitted.
+ //
+
+ // FIXME: This is just a workaround
+ if (caller_method == method) {
+ } else {
+ info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, gji->generic_sharing_context, TRUE, -1);
+
+ if (!tramp_addr) {
+ wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
+ addr = mono_compile_method (wrapper);
+ mono_memory_barrier ();
+ tramp_addr = addr;
+ }
+ addr = tramp_addr;
+
+ if (mono_aot_only)
+ addr = mono_aot_get_gsharedvt_arg_trampoline (info, addr);
+ else
+ addr = mono_arch_get_gsharedvt_arg_trampoline (mono_domain_get (), info, addr);
+
+ //printf ("IN-RGCTX: %s\n", mono_method_full_name (method, TRUE));
+ }
+ }
+
+ return addr;
+ }
default:
g_assert_not_reached ();
}
* LOCKING: loader lock
*/
static void
-fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, int info_type)
+fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointer data, MonoRgctxInfoType info_type)
{
MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
MonoClass *subclass;
- rgctx_template_set_other_slot (class->image, template, type_argc, index, data, info_type);
+ rgctx_template_set_slot (class->image, template, type_argc, index, data, info_type);
/* Recurse for all subclasses */
if (generic_subclass_hash)
subclass = NULL;
while (subclass) {
- MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
+ MonoRuntimeGenericContextInfoTemplate subclass_oti;
MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
g_assert (subclass_template);
}
}
+const char*
+mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
+{
+ switch (type) {
+ case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
+ case MONO_RGCTX_INFO_KLASS: return "KLASS";
+ case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
+ case MONO_RGCTX_INFO_TYPE: return "TYPE";
+ case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
+ case MONO_RGCTX_INFO_METHOD: return "METHOD";
+ case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
+ case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
+ case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
+ case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
+ case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
+ case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
+ case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
+ 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_IS_REF: return "CLASS_IS_REF";
+ 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";
+ default:
+ return "<UNKNOWN RGCTX INFO TYPE>";
+ }
+}
+
+G_GNUC_UNUSED static char*
+rgctx_info_to_str (MonoRgctxInfoType info_type, gpointer data)
+{
+ switch (info_type) {
+ case MONO_RGCTX_INFO_VTABLE:
+ return mono_type_full_name ((MonoType*)data);
+ default:
+ return g_strdup_printf ("<%p>", data);
+ }
+}
+
/*
* LOCKING: loader lock
*/
static int
-register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type)
+register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type)
{
int i;
MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
MonoClass *parent;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti;
- for (i = 0, oti = get_other_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
+ for (i = 0, oti = get_info_templates (template, type_argc); oti; ++i, oti = oti->next) {
if (!oti->data)
break;
}
- //g_print ("template %s . other_infos [%d] = %s\n", mono_type_get_full_name (class), i, mono_type_get_full_name (other_class));
+ DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
/* Mark the slot as used in all parent classes (until we find
a parent class which already has it marked used). */
parent = class->parent;
while (parent != NULL) {
MonoRuntimeGenericContextTemplate *parent_template;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti;
if (parent->generic_class)
parent = parent->generic_class->container_class;
if (oti && oti->data)
break;
- rgctx_template_set_other_slot (parent->image, parent_template, type_argc, i,
- MONO_RGCTX_SLOT_USED_MARKER, 0);
+ rgctx_template_set_slot (parent->image, parent_template, type_argc, i,
+ MONO_RGCTX_SLOT_USED_MARKER, 0);
parent = parent->parent;
}
}
static gboolean
-other_info_equal (gpointer data1, gpointer data2, int info_type)
+info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
{
switch (info_type) {
case MONO_RGCTX_INFO_STATIC_DATA:
case MONO_RGCTX_INFO_TYPE:
case MONO_RGCTX_INFO_REFLECTION_TYPE:
case MONO_RGCTX_INFO_CAST_CACHE:
+ case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
+ case MONO_RGCTX_INFO_VALUE_SIZE:
+ case MONO_RGCTX_INFO_CLASS_IS_REF:
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:
case MONO_RGCTX_INFO_CLASS_FIELD:
+ case MONO_RGCTX_INFO_FIELD_OFFSET:
case MONO_RGCTX_INFO_METHOD_RGCTX:
case MONO_RGCTX_INFO_METHOD_CONTEXT:
case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK:
case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE:
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE:
+ case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT:
return data1 == data2;
default:
g_assert_not_reached ();
}
static int
-lookup_or_register_other_info (MonoClass *class, int type_argc, gpointer data, int info_type,
+lookup_or_register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType info_type,
MonoGenericContext *generic_context)
{
static gboolean inited = FALSE;
MonoRuntimeGenericContextTemplate *rgctx_template =
mono_class_get_runtime_generic_context_template (class);
- MonoRuntimeGenericContextOtherInfoTemplate *oti_list, *oti;
+ MonoRuntimeGenericContextInfoTemplate *oti_list, *oti;
int i;
+ class = get_shared_class (class);
+
mono_loader_lock ();
- if (other_info_has_identity (info_type)) {
- oti_list = get_other_info_templates (rgctx_template, type_argc);
+ if (info_has_identity (info_type)) {
+ oti_list = get_info_templates (rgctx_template, type_argc);
for (oti = oti_list, i = 0; oti; oti = oti->next, ++i) {
gpointer inflated_data;
if (oti->info_type != info_type || !oti->data)
continue;
- inflated_data = inflate_other_info (oti, generic_context, class, TRUE);
+ inflated_data = inflate_info (oti, generic_context, class, TRUE);
- if (other_info_equal (data, inflated_data, info_type)) {
+ if (info_equal (data, inflated_data, info_type)) {
free_inflated_info (info_type, inflated_data);
mono_loader_unlock ();
return i;
}
/* We haven't found the info */
- i = register_other_info (class, type_argc, data, info_type);
+ i = register_info (class, type_argc, data, info_type);
mono_loader_unlock ();
}
/*
- * mono_method_lookup_or_register_other_info:
+ * mono_method_lookup_or_register_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
+ * Looks up and, if necessary, adds information about data/info_type 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)
+mono_method_lookup_or_register_info (MonoMethod *method, gboolean in_mrgctx, gpointer data,
+ MonoRgctxInfoType info_type, MonoGenericContext *generic_context)
{
MonoClass *class = method->klass;
int type_argc, index;
type_argc = 0;
}
- index = lookup_or_register_other_info (class, type_argc, data, info_type, generic_context);
+ index = lookup_or_register_info (class, type_argc, data, info_type, generic_context);
//g_print ("rgctx item at index %d argc %d\n", index, type_argc);
}
static gpointer
-fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
+fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
MonoGenericInst *method_inst)
{
gpointer info;
MonoDomain *domain = class_vtable->domain;
MonoClass *class = class_vtable->klass;
MonoGenericContext *class_context = class->generic_class ? &class->generic_class->context : NULL;
- MonoRuntimeGenericContextOtherInfoTemplate oti;
+ MonoRuntimeGenericContextInfoTemplate oti;
MonoGenericContext context = { class_context ? class_context->class_inst : NULL, method_inst };
int rgctx_index;
gboolean do_free;
oti = class_get_rgctx_template_oti (get_shared_class (class),
method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
/* This might take the loader lock */
- info = instantiate_other_info (domain, &oti, &context, class);
+ info = instantiate_info (domain, &oti, &context, class, caller);
/*
if (method_inst)
/*
* mono_class_fill_runtime_generic_context:
* @class_vtable: a vtable
+ * @caller: caller method address
* @slot: a slot index to be instantiated
*
- * Instantiates a slot in the RGCTX.
+ * Instantiates a slot in the RGCTX, returning its value.
*/
gpointer
-mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
+mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint8 *caller, guint32 slot)
{
static gboolean inited = FALSE;
static int num_alloced = 0;
mono_domain_unlock (domain);
- info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
+ info = fill_runtime_generic_context (class_vtable, rgctx, caller, slot, 0);
+
+ DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));
return info;
}
/*
* mono_method_fill_runtime_generic_context:
* @mrgctx: an MRGCTX
+ * @caller: caller method address
* @slot: a slot index to be instantiated
*
* Instantiates a slot in the MRGCTX.
*/
gpointer
-mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
+mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
{
gpointer info;
- info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
+ info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
mrgctx->method_inst);
return info;
gboolean
mono_method_is_generic_impl (MonoMethod *method)
{
- if (method->is_inflated) {
- g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
+ if (method->is_inflated)
return TRUE;
- }
/* We don't treat wrappers as generic code, i.e., we never
apply generic sharing to them. This is especially
important for static rgctx invoke wrappers, which only work
* mono_method_is_generic_sharable_impl_full:
* @method: a method
* @allow_type_vars: whether to regard type variables as reference types
- * @alloc_partial: whether to allow partial sharing
+ * @allow_partial: whether to allow partial sharing
+ * @allow_gsharedvt: whenever to allow sharing over valuetypes
*
* Returns TRUE iff the method is inflated or part of an inflated
* class, its context is sharable and it has no constraints on its
*/
gboolean
mono_method_is_generic_sharable_impl_full (MonoMethod *method, gboolean allow_type_vars,
- gboolean allow_partial)
+ gboolean allow_partial, gboolean allow_gsharedvt)
{
if (!mono_method_is_generic_impl (method))
return FALSE;
+ if (allow_gsharedvt && mini_is_gsharedvt_sharable_method (method))
+ return TRUE;
+
if (method->is_inflated) {
MonoMethodInflated *inflated = (MonoMethodInflated*)method;
MonoGenericContext *context = &inflated->context;
gboolean
mono_method_is_generic_sharable_impl (MonoMethod *method, gboolean allow_type_vars)
{
- return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING);
+ return mono_method_is_generic_sharable_impl_full (method, allow_type_vars, ALLOW_PARTIAL_SHARING, TRUE);
}
gboolean
}
static gboolean gshared_supported;
+static gboolean gsharedvt_supported;
void
mono_set_generic_sharing_supported (gboolean supported)
gshared_supported = supported;
}
+void
+mono_set_generic_sharing_vt_supported (gboolean supported)
+{
+ gsharedvt_supported = supported;
+}
+
/*
* mono_class_generic_sharing_enabled:
* @class: a class
MonoType*
mini_get_basic_type_from_generic (MonoGenericSharingContext *gsctx, MonoType *type)
{
+ /* FIXME: Some callers don't pass in a gsctx, like mono_dyn_call_prepare () */
+ /*
if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
g_assert (gsctx);
-
- return mono_type_get_basic_type_from_generic (type);
+ */
+ if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && mini_is_gsharedvt_type_gsctx (gsctx, type))
+ return mini_get_gsharedvt_alloc_type_gsctx (gsctx, type);
+ else
+ return mono_type_get_basic_type_from_generic (type);
}
/*
{
if (type->byref)
return &mono_defaults.int_class->byval_arg;
- return mono_type_get_basic_type_from_generic (mono_type_get_underlying_type (type));
+ return mini_get_basic_type_from_generic (gsctx, mono_type_get_underlying_type (type));
}
/*
/*
* mini_type_stack_size_full:
*
- * Same as mini_type_stack_size, but handle pinvoke data types as well.
+ * Same as mini_type_stack_size, but handle gsharedvt and pinvoke data types as well.
*/
int
mini_type_stack_size_full (MonoGenericSharingContext *gsctx, MonoType *t, guint32 *align, gboolean pinvoke)
{
int size;
+ /*
+ if (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR)
+ g_assert (gsctx);
+ */
+
+ if (mini_is_gsharedvt_type_gsctx (gsctx, t))
+ t = mini_get_gsharedvt_alloc_type_gsctx (gsctx, t);
+
if (pinvoke) {
size = mono_type_native_stack_size (t, align);
} else {
g_hash_table_destroy (generic_subclass_hash);
}
+/*
+ * mini_type_var_is_vt:
+ *
+ * Return whenever T is a type variable instantiated with a vtype.
+ */
+gboolean
+mini_type_var_is_vt (MonoCompile *cfg, MonoType *type)
+{
+ if (type->type == MONO_TYPE_VAR) {
+ if (cfg->generic_sharing_context->var_is_vt && cfg->generic_sharing_context->var_is_vt [type->data.generic_param->num])
+ return TRUE;
+ else
+ return FALSE;
+ } else if (type->type == MONO_TYPE_MVAR) {
+ if (cfg->generic_sharing_context->mvar_is_vt && cfg->generic_sharing_context->mvar_is_vt [type->data.generic_param->num])
+ return TRUE;
+ else
+ return FALSE;
+ } else {
+ g_assert_not_reached ();
+ }
+ return FALSE;
+}
+
gboolean
mini_type_is_reference (MonoCompile *cfg, MonoType *type)
{
if (!cfg->generic_sharing_context)
return FALSE;
/*FIXME the probably needs better handle under partial sharing*/
- return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
+ return ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && !mini_type_var_is_vt (cfg, type));
+}
+
+/*
+ * mini_method_get_rgctx:
+ *
+ * Return the RGCTX which needs to be passed to M when it is called.
+ */
+gpointer
+mini_method_get_rgctx (MonoMethod *m)
+{
+ if (mini_method_get_context (m)->method_inst)
+ return mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
+ else
+ return mono_class_vtable (mono_domain_get (), m->klass);
+}
+
+/*
+ * mini_type_is_vtype:
+ *
+ * Return whenever T is a vtype, or a type param instantiated with a vtype.
+ * Should be used in place of MONO_TYPE_ISSTRUCT () which can't handle gsharedvt.
+ */
+gboolean
+mini_type_is_vtype (MonoCompile *cfg, MonoType *t)
+{
+ return MONO_TYPE_ISSTRUCT (t) || mini_is_gsharedvt_variable_type (cfg, t);
+}
+
+#if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
+
+#include "../../../mono-extensions/mono/mini/mini-generic-sharing-gsharedvt.c"
+
+#else
+
+gboolean
+mini_is_gsharedvt_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
+{
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_type (MonoCompile *cfg, MonoType *t)
+{
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_klass (MonoCompile *cfg, MonoClass *klass)
+{
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_signature (MonoCompile *cfg, MonoMethodSignature *sig)
+{
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_variable_type (MonoCompile *cfg, MonoType *t)
+{
+ return FALSE;
+}
+
+static MonoType*
+mini_get_gsharedvt_alloc_type_gsctx (MonoGenericSharingContext *gsctx, MonoType *t)
+{
+ return NULL;
+}
+
+MonoType*
+mini_get_gsharedvt_alloc_type_for_type (MonoCompile *cfg, MonoType *t)
+{
+ return NULL;
}
+
+gboolean
+mini_is_gsharedvt_sharable_method (MonoMethod *method)
+{
+ return FALSE;
+}
+
+gboolean
+mini_is_gsharedvt_variable_signature (MonoMethodSignature *sig)
+{
+ return FALSE;
+}
+
+#endif /* !MONOTOUCH */