* class-internals.h, generic-sharing.c: New, small runtime generic context.
* metadata-internals.h, domain.c, image.c: Less bookkeeping is required for the new RGCTX.
* object.c: Don't setup the RGCTX when the vtable is created,
because we're setting it up lazily now.
2008-04-28 Mark Probst <mark.probst@gmail.com>
* mini.h, mini.c: Lots of code for accessing the old RGCTX
deleted. The only way to access the new RGCTX is via the
trampline.
* mini.c, mini-amd64, mini-x86.c, mini-exceptions.c: Pass the
vtable instead of the RGCTX to static methods.
* mini-tramplines.c, tramp-amd64.c, tramp-x86.c: Trampoline for
accessing the new RGCTX.
* generic-sharing.c: There is no separation between self, type
arguments and other types in the RGCTX anymore.
svn path=/trunk/mono/; revision=102043
+2008-04-28 Mark Probst <mark.probst@gmail.com>
+
+ * class-internals.h, generic-sharing.c: New, small runtime generic context.
+
+ * metadata-internals.h, domain.c, image.c: Less bookkeeping is required for the new RGCTX.
+
+ * object.c: Don't setup the RGCTX when the vtable is created,
+ because we're setting it up lazily now.
+
2008-04-26 Zoltan Varga <vargaz@gmail.com>
* sgen-gc.c: Make the 'desc' variables an mword instead of a guint32 to fix
MonoVTable *domain_vtables [MONO_ZERO_LEN_ARRAY];
} MonoClassRuntimeInfo;
-#define MONO_RGCTX_MAX_OTHER_INFOS 2
-
enum {
MONO_RGCTX_INFO_STATIC_DATA,
MONO_RGCTX_INFO_KLASS,
MONO_RGCTX_INFO_VTABLE,
+ MONO_RGCTX_INFO_TYPE,
MONO_RGCTX_INFO_REFLECTION_TYPE,
MONO_RGCTX_INFO_METHOD,
- MONO_RGCTX_INFO_GENERIC_METHOD_CODE
+ MONO_RGCTX_INFO_GENERIC_METHOD_CODE,
+ MONO_RGCTX_INFO_CLASS_FIELD
};
typedef struct _MonoRuntimeGenericContextOtherInfoTemplate {
} MonoRuntimeGenericContextOtherInfoTemplate;
typedef struct {
- int num_arg_infos;
MonoClass *next_subclass;
MonoRuntimeGenericContextOtherInfoTemplate *other_infos;
- MonoType *arg_infos [MONO_ZERO_LEN_ARRAY];
} MonoRuntimeGenericContextTemplate;
struct _MonoClass {
#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= (k)->max_interface_id) && ((k)->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
int mono_class_interface_offset (MonoClass *klass, MonoClass *itf);
-typedef struct {
- gpointer static_data;
- MonoClass *klass;
- MonoVTable *vtable;
-} MonoRuntimeGenericSuperInfo;
-
-typedef struct {
- gpointer static_data;
- MonoClass *klass;
- MonoVTable *vtable;
-} MonoRuntimeGenericArgInfo;
-
-typedef struct {
- MonoDomain *domain;
- MonoVTable *vtable;
- gpointer other_infos [MONO_RGCTX_MAX_OTHER_INFOS];
- gpointer *extra_other_infos;
- MonoRuntimeGenericArgInfo arg_infos [MONO_ZERO_LEN_ARRAY];
-} MonoRuntimeGenericContext;
-
-#define MONO_RGCTX_ENCODE_DIRECT_OFFSET(o) ((guint32)(o) & 0x00ffffff)
-#define MONO_RGCTX_ENCODE_INDIRECT_OFFSET(o) (((guint32)(o) & 0x00ffffff) | 0x01000000)
-
-#define MONO_RGCTX_OFFSET_INDIRECT_SLOT(s) ((gint32)(((guint32)(s))>>24) - 1)
-#define MONO_RGCTX_OFFSET_IS_INDIRECT(s) (MONO_RGCTX_OFFSET_INDIRECT_SLOT((s)) >= 0)
-
-#define MONO_RGCTX_OFFSET_OFFSET_PART(s) ((guint32)(s) & 0x00ffffff)
-#define MONO_RGCTX_OFFSET_DIRECT_OFFSET(s) ((MONO_RGCTX_OFFSET_OFFSET_PART((s)) & 0x00800000) ? \
- (gint32)(MONO_RGCTX_OFFSET_OFFSET_PART((s)) | 0xff000000) : \
- (gint32)MONO_RGCTX_OFFSET_OFFSET_PART((s)))
-#define MONO_RGCTX_OFFSET_INDIRECT_OFFSET(s) MONO_RGCTX_OFFSET_DIRECT_OFFSET((s))
+typedef gpointer MonoRuntimeGenericContext;
/* the interface_offsets array is stored in memory before this struct */
struct MonoVTable {
gboolean
mono_class_generic_sharing_enabled (MonoClass *class) MONO_INTERNAL;
-MonoRuntimeGenericContextTemplate*
-mono_class_get_runtime_generic_context_template (MonoClass *class) MONO_INTERNAL;
-
-void
-mono_class_setup_runtime_generic_context (MonoClass *class, MonoDomain *domain) MONO_INTERNAL;
+gpointer
+mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot) MONO_INTERNAL;
-void
-mono_class_fill_runtime_generic_context (MonoRuntimeGenericContext *rgctx) MONO_INTERNAL;
+int
+mono_class_rgctx_get_array_size (int n) MONO_INTERNAL;
gboolean
mono_class_lookup_or_register_other_info (MonoClass *class, gpointer data, int info_type, MonoGenericContext *generic_context) MONO_INTERNAL;
void
mono_class_unregister_image_generic_subclasses (MonoImage *image) MONO_INTERNAL;
-void
-mono_class_unregister_domain_generic_vtables (MonoDomain *domain) MONO_INTERNAL;
-
gboolean
mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass) MONO_INTERNAL;
max_domain_code_alloc = MAX (max_domain_code_alloc, code_alloc);
max_domain_code_size = MAX (max_domain_code_size, code_size);
- mono_class_unregister_domain_generic_vtables (domain);
-
#ifdef DEBUG_DOMAIN_UNLOAD
mono_mempool_invalidate (domain->mp);
mono_code_manager_invalidate (domain->code_mp);
#include <glib.h>
#endif
#include <mono/utils/mono-membar.h>
+#include <mono/utils/mono-counters.h>
#include "metadata-internals.h"
#include "class.h"
#include "class-internals.h"
+#include "marshal.h"
static int
type_check_context_used (MonoType *type, gboolean recursive)
return i;
}
-/* Maps from uninstantiated generic classes to GSLists's of
- * MonoVTable's of classes that are instantiations of the key class.
- *
- * LOCKING: templates lock
- */
-static GHashTable *generic_class_rgctx_hash;
-
/* Maps from uninstantiated generic classes to GList's of
* uninstantiated generic classes whose parent is the key class or an
* instance of the key class.
*/
static GHashTable *generic_subclass_hash;
-static void
-list_hash_table_insert (GHashTable **hash, gpointer key, gpointer value)
-{
- GSList *list;
-
- if (!*hash)
- *hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-
- list = g_hash_table_lookup (*hash, key);
- g_hash_table_insert (*hash, key, g_slist_prepend (list, value));
-}
-
/*
* LOCKING: templates lock
*/
return template;
}
-/*
- * LOCKING: templates lock
- */
-static void
-register_open_instance (MonoClass *class)
-{
- g_assert (class->generic_class && class->generic_class->container_class);
- g_assert (class_lookup_rgctx_template (class));
-
- list_hash_table_insert (&class->image->generic_class_open_instances_hash, class->generic_class->container_class, class);
-}
-
-/*
- * LOCKING: templates lock
- */
-static void
-register_rgctx_vtable (MonoVTable *vtable)
-{
- MonoClass *class = vtable->klass;
-
- if (class->generic_class)
- class = class->generic_class->container_class;
-
- //g_print ("registering rgctx %p for class %s (%p)\n", vtable, mono_type_get_full_name (class), class);
-
- list_hash_table_insert (&generic_class_rgctx_hash, class, vtable);
-}
-
/*
* LOCKING: templates lock
*/
g_hash_table_destroy (old_hash);
}
-static void
-move_vtables_not_in_domain_foreach_func (MonoClass *class, GSList *list, MonoDomain *domain)
+/*
+ * LOCKING: loader lock
+ */
+static MonoRuntimeGenericContextTemplate*
+alloc_template (MonoClass *class)
{
- GSList *new_list = NULL;
- GSList *iter = list;
-
- while (iter) {
- MonoVTable *vtable = iter->data;
+ static gboolean inited = FALSE;
+ static int num_allocted = 0;
+ static int num_bytes = 0;
- if (vtable->domain != domain)
- new_list = g_slist_prepend (new_list, vtable);
+ int size = sizeof (MonoRuntimeGenericContextTemplate);
- iter = iter->next;
+ if (!inited) {
+ mono_counters_register ("RGCTX template num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
+ mono_counters_register ("RGCTX template bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
+ inited = TRUE;
}
- g_slist_free (list);
+ num_allocted++;
+ num_bytes += size;
- if (new_list)
- g_hash_table_insert (generic_class_rgctx_hash, class, new_list);
+ return mono_mempool_alloc0 (class->image->mempool, size);
}
/*
- * mono_class_unregister_domain_generic_vtables:
- * @domain: a domain
- *
- * Removes all vtables of the domain from the generic vtables hash.
- * Must be called when a domain is destroyed.
+ * LOCKING: loader lock
*/
-void
-mono_class_unregister_domain_generic_vtables (MonoDomain *domain)
+static MonoRuntimeGenericContextOtherInfoTemplate*
+alloc_oti (MonoImage *image)
{
- GHashTable *old_hash;
-
- if (!generic_class_rgctx_hash)
- return;
+ static gboolean inited = FALSE;
+ static int num_allocted = 0;
+ static int num_bytes = 0;
- templates_lock ();
+ int size = sizeof (MonoRuntimeGenericContextOtherInfoTemplate);
- old_hash = generic_class_rgctx_hash;
- generic_class_rgctx_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ if (!inited) {
+ mono_counters_register ("RGCTX oti num allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_allocted);
+ mono_counters_register ("RGCTX oti bytes allocted", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_bytes);
+ inited = TRUE;
+ }
- g_hash_table_foreach (old_hash, (GHFunc)move_vtables_not_in_domain_foreach_func, domain);
+ num_allocted++;
+ num_bytes += size;
- templates_unlock ();
-
- g_hash_table_destroy (old_hash);
+ return mono_mempool_alloc0 (image->mempool, size);
}
/*
MonoRuntimeGenericContextOtherInfoTemplate **oti;
g_assert (slot >= 0);
+ g_assert (data);
mono_loader_lock ();
if (i > 0)
oti = &(*oti)->next;
if (!*oti)
- *oti = mono_mempool_alloc0 (image->mempool, sizeof (MonoRuntimeGenericContextOtherInfoTemplate));
+ *oti = alloc_oti (image);
++i;
}
mono_loader_unlock ();
}
-static gboolean
-include_arg_info (MonoType *type, MonoRuntimeGenericContextTemplate *parent_template)
-{
- int i;
-
- if (!MONO_TYPE_IS_REFERENCE (type) &&
- mono_type_get_type (type) != MONO_TYPE_VAR &&
- mono_type_get_type (type) != MONO_TYPE_MVAR)
- return FALSE;
-
- if (!parent_template)
- return TRUE;
-
- for (i = 0; i < parent_template->num_arg_infos; ++i)
- if (type == parent_template->arg_infos [i])
- return FALSE;
-
- return TRUE;
-}
-
#define MONO_RGCTX_SLOT_USED_MARKER ((gpointer)&mono_defaults.object_class->byval_arg)
static gpointer
case MONO_RGCTX_INFO_STATIC_DATA:
case MONO_RGCTX_INFO_KLASS:
case MONO_RGCTX_INFO_VTABLE:
+ case MONO_RGCTX_INFO_TYPE:
case MONO_RGCTX_INFO_REFLECTION_TYPE:
return mono_class_inflate_generic_type (data, context);
case MONO_RGCTX_INFO_METHOD:
- case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
- return mono_class_inflate_generic_method (data, context);
+ case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: {
+ MonoMethod *method = data;
+
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ g_assert (method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE);
+
+ method = mono_marshal_method_from_wrapper (method);
+ method = mono_class_inflate_generic_method (method, context);
+ method = mono_marshal_get_static_rgctx_invoke (method);
+ }
+
+ return mono_class_inflate_generic_method (method, context);
+ }
+
+ case MONO_RGCTX_INFO_CLASS_FIELD: {
+ 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);
+ int i = field - field->parent->fields;
+ gpointer dummy;
+
+ mono_class_get_fields (inflated_class, &dummy);
+ g_assert (inflated_class->fields);
+
+ return &inflated_class->fields [i];
+ }
default:
g_assert_not_reached ();
return inflate_other_data (oti->data, oti->info_type, context);
}
+static MonoRuntimeGenericContextOtherInfoTemplate
+class_get_rgctx_template_oti (MonoClass *class, guint32 slot);
+
/*
* mono_class_get_runtime_generic_context_template:
* @class: a class
* Looks up or constructs, if necessary, the runtime generic context
* for class.
*/
-MonoRuntimeGenericContextTemplate*
+static MonoRuntimeGenericContextTemplate*
mono_class_get_runtime_generic_context_template (MonoClass *class)
{
- int num_parent_args, num_class_args, total_num_args;
MonoRuntimeGenericContextTemplate *parent_template, *template;
MonoGenericInst *inst;
- int i, j;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ guint32 i;
+
+ g_assert (!class->generic_class);
templates_lock ();
template = class_lookup_rgctx_template (class);
if (template)
return template;
- if (class->generic_class) {
- parent_template = mono_class_get_runtime_generic_context_template (class->generic_class->container_class);
-
- mono_loader_lock ();
- template = mono_mempool_alloc0 (class->image->mempool,
- sizeof (MonoRuntimeGenericContextTemplate) + sizeof (MonoType*) * parent_template->num_arg_infos);
- mono_loader_unlock ();
-
- template->num_arg_infos = parent_template->num_arg_infos;
-
- for (i = 0; i < parent_template->num_arg_infos; ++i) {
- template->arg_infos [i] = mono_class_inflate_generic_type (parent_template->arg_infos [i],
- &class->generic_class->context);
- /*
- g_print("arg info %d of %s is %s (from %s)\n", i,
- mono_type_get_full_name (class),
- mono_type_get_name (template->arg_infos [i]),
- mono_type_get_name (parent_template->arg_infos [i]));
- */
- }
-
- /* 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,
- inflate_other_info (oti, &class->generic_class->context),
- oti->info_type);
- }
- }
-
- templates_lock ();
-
- if (class_lookup_rgctx_template (class)) {
- /* some other thread already set the template */
- template = class_lookup_rgctx_template (class);
- } else {
- class_set_rgctx_template (class, template);
- register_open_instance (class);
- }
-
- templates_unlock ();
-
- return template;
- }
-
- if (class->parent)
- parent_template = mono_class_get_runtime_generic_context_template (class->parent);
- else
- parent_template = NULL;
-
- if (parent_template)
- num_parent_args = parent_template->num_arg_infos;
- else
- num_parent_args = 0;
-
if (class->generic_container)
inst = class->generic_container->context.class_inst;
else
inst = NULL;
- num_class_args = 0;
- if (inst) {
- for (i = 0; i < inst->type_argc; ++i) {
- if (include_arg_info (inst->type_argv [i], parent_template))
- ++num_class_args;
- }
- }
-
- total_num_args = num_parent_args + num_class_args;
-
mono_loader_lock ();
- template = mono_mempool_alloc0 (class->image->mempool,
- sizeof (MonoRuntimeGenericContextTemplate) + sizeof (MonoType*) * total_num_args);
+ template = alloc_template (class);
mono_loader_unlock ();
- template->num_arg_infos = total_num_args;
+ if (class->parent) {
+ if (class->parent->generic_class) {
+ guint32 num_entries;
- if (num_parent_args > 0)
- memcpy (template->arg_infos, parent_template->arg_infos,
- sizeof (MonoType*) * parent_template->num_arg_infos);
+ parent_template = mono_class_get_runtime_generic_context_template
+ (class->parent->generic_class->container_class);
+ num_entries = rgctx_template_num_other_infos (parent_template);
- j = 0;
- if (inst) {
- for (i = 0; i < inst->type_argc; ++i) {
- MonoType *type = inst->type_argv [i];
+ mono_loader_lock ();
- if (include_arg_info (type, parent_template))
- template->arg_infos [num_parent_args + j++] = type;
- }
- }
- g_assert (j == num_class_args);
+ /* FIXME: quadratic! */
+ for (i = 0; i < num_entries; ++i) {
+ MonoRuntimeGenericContextOtherInfoTemplate oti;
- /*
- g_print ("class %s has %d type args (%d from parent)\n",
- mono_type_get_full_name(class), total_num_args, num_parent_args);
- */
+ 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);
+ }
- if (parent_template) {
- MonoRuntimeGenericContextOtherInfoTemplate *oti, **new_oti;
+ mono_loader_unlock ();
+ } else {
+ MonoRuntimeGenericContextOtherInfoTemplate *oti;
- oti = parent_template->other_infos;
- new_oti = &template->other_infos;
+ parent_template = mono_class_get_runtime_generic_context_template (class->parent);
- mono_loader_lock ();
+ mono_loader_lock ();
- while (oti) {
- *new_oti = mono_mempool_alloc0 (class->image->mempool,
- sizeof (MonoRuntimeGenericContextOtherInfoTemplate));
- (*new_oti)->data = oti->data;
- (*new_oti)->info_type = oti->info_type;
+ /* 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);
+ }
- oti = oti->next;
- new_oti = &(*new_oti)->next;
+ mono_loader_unlock ();
}
-
- mono_loader_unlock ();
}
templates_lock ();
return template;
}
+static MonoRuntimeGenericContextOtherInfoTemplate
+class_get_rgctx_template_oti (MonoClass *class, guint32 slot)
+{
+ if (class->generic_class) {
+ MonoRuntimeGenericContextOtherInfoTemplate oti;
+
+ oti = class_get_rgctx_template_oti (class->generic_class->container_class, slot);
+ if (oti.data)
+ oti.data = inflate_other_info (&oti, &class->generic_class->context);
+
+ return oti;
+ } 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);
+
+ return *oti;
+ }
+}
+
static MonoClass*
class_uninstantiated (MonoClass *class)
{
return class_type_info (domain, arg_class, oti->info_type);
}
+ case MONO_RGCTX_INFO_TYPE:
+ return data;
case MONO_RGCTX_INFO_REFLECTION_TYPE:
return mono_type_get_object (domain, data);
case MONO_RGCTX_INFO_METHOD:
return data;
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
return mono_compile_method (data);
+ case MONO_RGCTX_INFO_CLASS_FIELD:
+ return data;
default:
g_assert_not_reached ();
}
{
MonoRuntimeGenericContextTemplate *template = mono_class_get_runtime_generic_context_template (class);
MonoClass *subclass;
- GSList *instances;
- int old_length, new_length, old_instances_extra_length;
+ int old_length, new_length;
int old_instances_length = -1;
g_assert (!class->generic_class);
rgctx_template_set_other_slot (class->image, template, index, data, info_type);
new_length = rgctx_template_num_other_infos (template);
- /* For all open instantiations on this level: Instantiate the
- * type and put it in the rgctx template.
- */
- if (class->image->generic_class_open_instances_hash)
- instances = g_hash_table_lookup (class->image->generic_class_open_instances_hash, class);
- else
- instances = NULL;
-
- while (instances) {
- MonoClass *instance = instances->data;
- MonoRuntimeGenericContextTemplate *instance_template = class_lookup_rgctx_template (instance);
- int length;
- gpointer inflated_data;
-
- g_assert (instance_template);
- g_assert (instance->generic_class != NULL && instance->generic_class->container_class == class);
-
- length = rgctx_template_num_other_infos (instance_template);
- if (old_instances_length < 0)
- old_instances_length = length;
-
- g_assert (length == old_instances_length);
-
- inflated_data = inflate_other_data (data, info_type, &instance->generic_class->context);
- rgctx_template_set_other_slot (instance->image, instance_template, index,
- inflated_data, info_type);
-
- g_assert (rgctx_template_num_other_infos (instance_template) == new_length);
-
- instances = instances->next;
- }
-
if (old_instances_length < 0)
old_instances_length = old_length;
- old_instances_extra_length = MAX(old_instances_length - MONO_RGCTX_MAX_OTHER_INFOS, 0);
-
- g_assert (old_instances_length <= old_length);
/* The reason why the instance's other_infos list can be
* shorter than the uninstanted class's is that when we mark
*/
g_assert (old_instances_length <= old_length);
- /* For all rgctx's on this level: Instantiate the type and put
- * the class in the rgctx.
- */
- if (generic_class_rgctx_hash)
- instances = g_hash_table_lookup (generic_class_rgctx_hash, class);
- else
- instances = NULL;
-
- while (instances) {
- MonoVTable *vtable = instances->data;
- MonoRuntimeGenericContextTemplate *instance_template;
- int real_index;
- gpointer *table;
-
- instance_template = mono_class_get_runtime_generic_context_template (class_uninstantiated (vtable->klass));
-
- g_assert (vtable->runtime_generic_context);
-
- if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
- real_index = index;
- table = vtable->runtime_generic_context->other_infos;
- } else {
- real_index = index - MONO_RGCTX_MAX_OTHER_INFOS;
-
- if (old_instances_length == new_length) {
- table = vtable->runtime_generic_context->extra_other_infos;
- } else {
- g_assert (old_instances_extra_length < real_index + 1);
-
- /* Allocate new table with the required number
- of slots and copy the old slots over. */
- mono_domain_lock (vtable->domain);
- table = mono_mempool_alloc0 (vtable->domain->mp,
- sizeof (gpointer) * (real_index + 1));
- mono_domain_unlock (vtable->domain);
-
- memcpy (table, vtable->runtime_generic_context->extra_other_infos,
- sizeof (gpointer) * old_instances_extra_length);
- mono_memory_write_barrier ();
- vtable->runtime_generic_context->extra_other_infos = table;
- }
- }
-
- g_assert (!table [real_index]);
-
- //g_print ("rgctx %s . other_infos [%d] = %s\n", mono_type_get_full_name (vtable->klass), index, mono_type_get_full_name (other_class));
-
- instances = instances->next;
- }
-
/* Recurse for all subclasses */
if (generic_subclass_hash)
subclass = g_hash_table_lookup (generic_subclass_hash, class);
subclass = NULL;
while (subclass) {
- MonoRuntimeGenericContextOtherInfoTemplate *subclass_oti;
+ MonoRuntimeGenericContextOtherInfoTemplate subclass_oti;
MonoRuntimeGenericContextTemplate *subclass_template = class_lookup_rgctx_template (subclass);
g_assert (!subclass->generic_class);
g_assert (subclass_template);
- subclass_oti = rgctx_template_get_other_slot (class_lookup_rgctx_template (subclass->parent), index);
- g_assert (subclass_oti->data);
+ subclass_oti = class_get_rgctx_template_oti (subclass->parent, index);
+ g_assert (subclass_oti.data);
- fill_in_rgctx_template_slot (subclass, index, subclass_oti->data, info_type);
+ fill_in_rgctx_template_slot (subclass, index, subclass_oti.data, info_type);
subclass = subclass_template->next_subclass;
}
parent = class->parent;
while (parent != NULL) {
MonoRuntimeGenericContextTemplate *parent_template;
+ MonoRuntimeGenericContextOtherInfoTemplate *oti;
if (parent->generic_class)
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);
- if (rgctx_template_get_other_slot (parent_template, i))
+ if (oti && oti->data)
break;
rgctx_template_set_other_slot (parent->image, parent_template, i, MONO_RGCTX_SLOT_USED_MARKER, 0);
case MONO_RGCTX_INFO_STATIC_DATA:
case MONO_RGCTX_INFO_KLASS:
case MONO_RGCTX_INFO_VTABLE:
+ case MONO_RGCTX_INFO_TYPE:
case MONO_RGCTX_INFO_REFLECTION_TYPE:
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:
return data1 == data2;
default:
g_assert_not_reached ();
mono_class_lookup_or_register_other_info (MonoClass *class, gpointer data, int info_type,
MonoGenericContext *generic_context)
{
+ static gboolean inited = FALSE;
+ static int max_slot = 0;
+
MonoRuntimeGenericContextTemplate *rgctx_template =
mono_class_get_runtime_generic_context_template (class);
- int i, num_other_infos;
+ MonoRuntimeGenericContextOtherInfoTemplate *oti;
+ int i;
+
+ g_assert (!class->generic_class && class->generic_container);
templates_lock ();
- num_other_infos = rgctx_template_num_other_infos (rgctx_template);
- for (i = 0; i < num_other_infos; ++i) {
- /* FIXME: This is quadratic in complexity! */
- MonoRuntimeGenericContextOtherInfoTemplate *oti = rgctx_template_get_other_slot (rgctx_template, i);
+ for (oti = rgctx_template->other_infos, i = 0; oti; oti = oti->next, ++i) {
gpointer inflated_data;
- if (!oti || oti->info_type != info_type)
+ if (!oti || oti->info_type != info_type || !oti->data)
continue;
inflated_data = inflate_other_info (oti, generic_context);
templates_unlock ();
+ if (!inited) {
+ mono_counters_register ("RGCTX max slot number", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &max_slot);
+ inited = TRUE;
+ }
+ if (i > max_slot)
+ max_slot = i;
+
+
return i;
}
-static void
-instantiate_arg_info (MonoDomain *domain, MonoRuntimeGenericArgInfo *destination, MonoType *arg_info,
- MonoGenericContext *context)
+int
+mono_class_rgctx_get_array_size (int n)
{
- MonoType *arg_type;
- MonoClass *arg_class;
- MonoVTable *vtable;
-
- if (!arg_info)
- return;
-
- arg_type = mono_class_inflate_generic_type (arg_info, context);
-
- arg_class = mono_class_from_mono_type (arg_type);
- g_assert (arg_class);
+ g_assert (n >= 0 && n < 30);
- vtable = mono_class_vtable (domain, arg_class);
-
- destination->static_data = vtable->data;
- destination->klass = arg_class;
- destination->vtable = vtable;
+ return 4 << n;
}
/*
- * LOCKING: domain lock for rgctx->vtable->domain
+ * LOCKING: domain lock
*/
-static void
-rgctx_alloc_extra_other_types (MonoRuntimeGenericContext *rgctx)
+static gpointer*
+alloc_rgctx_array (MonoDomain *domain, int n)
{
- MonoClass *class = rgctx->vtable->klass;
- MonoDomain *domain = rgctx->vtable->domain;
- MonoRuntimeGenericContextTemplate *rgctx_template;
- int num_extra_other_infos;
+ static gboolean inited = FALSE;
+ static int num_alloced = 0;
+ static int bytes_alloced = 0;
+
+ int size = mono_class_rgctx_get_array_size (n) * 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);
+ inited = TRUE;
+ }
- rgctx_template = mono_class_get_runtime_generic_context_template (class_uninstantiated (class));
- num_extra_other_infos = MAX (rgctx_template_num_other_infos (rgctx_template) - MONO_RGCTX_MAX_OTHER_INFOS, 0);
+ num_alloced++;
+ bytes_alloced += size;
- if (num_extra_other_infos > 0)
- rgctx->extra_other_infos = mono_mempool_alloc0 (domain->mp,
- sizeof (gpointer) * num_extra_other_infos);
+ return array;
}
/*
* mono_class_fill_runtime_generic_context:
- * @rgctx: a runtime generic context
+ * @class_vtable: a vtable
+ * @slot: a slot index to be instantiated
*
- * Instantiates all slots of the runtime generic context rgctx.
+ * Instantiates a slot in the RGCTX.
*/
-void
-mono_class_fill_runtime_generic_context (MonoRuntimeGenericContext *rgctx)
+gpointer
+mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
{
- MonoVTable *class_vtable = rgctx->vtable;
+ static gboolean inited = FALSE;
+ static int num_alloced = 0;
+
+ MonoRuntimeGenericContext *rgctx;
MonoDomain *domain = class_vtable->domain;
MonoClass *class = class_vtable->klass;
- int depth = class->idepth;
MonoGenericContext *context = &class->generic_class->context;
- MonoRuntimeGenericSuperInfo *super_infos = (MonoRuntimeGenericSuperInfo*)rgctx - depth;
- MonoRuntimeGenericContextTemplate *rgctx_template;
- MonoRuntimeGenericContextOtherInfoTemplate *oti;
- MonoClass *super;
- int i;
-
- rgctx_template = mono_class_get_runtime_generic_context_template (class_uninstantiated (class));
+ MonoRuntimeGenericContextOtherInfoTemplate oti;
+ int i, first_slot, size;
+ gpointer info;
mono_domain_lock (domain);
- depth = 0;
- for (super = class; super; super = super->parent) {
- MonoVTable *vtable = mono_class_vtable (domain, super);
-
- super_infos [depth].static_data = vtable->data;
- super_infos [depth].klass = super;
- super_infos [depth].vtable = vtable;
-
- depth++;
+ if (!inited) {
+ mono_counters_register ("RGCTX num alloced", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_alloced);
+ inited = TRUE;
}
- rgctx_alloc_extra_other_types (rgctx);
-
- for (i = 0, oti = rgctx_template->other_infos; oti; ++i, oti = oti->next) {
- gpointer *arg_info;
-
- if (i < MONO_RGCTX_MAX_OTHER_INFOS)
- arg_info = &rgctx->other_infos [i];
- else
- arg_info = &rgctx->extra_other_infos [i - MONO_RGCTX_MAX_OTHER_INFOS];
-
- *arg_info = instantiate_other_info (domain, oti, context);
+ rgctx = class_vtable->runtime_generic_context;
+ if (!rgctx) {
+ rgctx = alloc_rgctx_array (domain, 0);
+ class_vtable->runtime_generic_context = rgctx;
+ num_alloced++;
}
- for (i = 0; i < rgctx_template->num_arg_infos; ++i)
- instantiate_arg_info (domain, &rgctx->arg_infos [i], rgctx_template->arg_infos [i], context);
-
- mono_domain_unlock (domain);
-}
-
-/*
- * mono_class_setup_runtime_generic_context:
- * @class: a class
- * @domain: a domain
- *
- * Sets up the runtime generic context of class in domain.
- */
-void
-mono_class_setup_runtime_generic_context (MonoClass *class, MonoDomain *domain)
-{
- MonoVTable *class_vtable = mono_class_vtable (domain, class);
- int depth = class->idepth;
- MonoRuntimeGenericSuperInfo *super_infos;
- MonoRuntimeGenericContext *rgctx;
- MonoRuntimeGenericContextTemplate *rgctx_template;
-
- /* Never setup a rgctx for an open class. */
- if (mono_class_check_context_used (class))
- return;
+ /* 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);
+ }
- //g_print ("setting up rgctx for %s\n", mono_type_get_full_name (class));
+ g_assert (!rgctx [slot - first_slot + 1]);
- /* We have to take the lock here and only release it after
- * we've registered the vtable because otherwise another
- * thread might add a slot to the template which we wouldn't
- * know anything about and we'd end up with a rgctx that's not
- * fully filled in.
- */
- templates_lock ();
+ oti = class_get_rgctx_template_oti (class_uninstantiated (class), slot);
- rgctx_template = mono_class_get_runtime_generic_context_template (class_uninstantiated (class));
+ info = rgctx [slot - first_slot + 1] = instantiate_other_info (domain, &oti, context);
- mono_domain_lock (domain);
- /* We don't allocate arg_infos because we don't use it yet.
- */
- super_infos = mono_mempool_alloc0 (domain->mp,
- sizeof (MonoRuntimeGenericSuperInfo) * depth +
- sizeof (MonoRuntimeGenericContext) +
- sizeof (MonoRuntimeGenericArgInfo) * rgctx_template->num_arg_infos);
mono_domain_unlock (domain);
- rgctx = class_vtable->runtime_generic_context = (MonoRuntimeGenericContext*) (super_infos + depth);
-
- rgctx->domain = domain;
- rgctx->vtable = class_vtable;
-
- rgctx_alloc_extra_other_types (rgctx);
-
- register_rgctx_vtable (class_vtable);
-
- templates_unlock ();
+ return info;
}
if (image->rgctx_template_hash)
g_hash_table_destroy (image->rgctx_template_hash);
- if (image->generic_class_open_instances_hash)
- g_hash_table_destroy (image->generic_class_open_instances_hash);
-
if (image->interface_bitset) {
mono_unload_interface_ids (image->interface_bitset);
mono_bitset_free (image->interface_bitset);
GHashTable *castclass_cache;
GHashTable *proxy_isinst_cache;
GHashTable *rgctx_template_hash; /* LOCKING: templates lock */
- /* Maps from uninstantiated generic classes to GSList's of
- * instantiated open generic classes whose container class is the key
- * class.
- *
- * LOCKING: templates lock
- */
- GHashTable *generic_class_open_instances_hash;
/*
* indexed by token and MonoGenericContext pointer
return mono_class_create_runtime_vtable (domain, class);
}
-static gboolean
-class_needs_rgctx (MonoClass *class)
-{
- if (!mono_class_generic_sharing_enabled (class))
- return FALSE;
-
- while (class) {
- if (class->generic_class)
- return TRUE;
- class = class->parent;
- }
-
- return FALSE;
-}
-
static MonoVTable *
mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
{
}
}
- if (class_needs_rgctx (class))
- mono_class_setup_runtime_generic_context (class, domain);
-
mono_domain_unlock (domain);
/* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
+2008-04-28 Mark Probst <mark.probst@gmail.com>
+
+ * mini.h, mini.c: Lots of code for accessing the old RGCTX
+ deleted. The only way to access the new RGCTX is via the
+ trampline.
+
+ * mini.c, mini-amd64, mini-x86.c, mini-exceptions.c: Pass the
+ vtable instead of the RGCTX to static methods.
+
+ * mini-tramplines.c, tramp-amd64.c, tramp-x86.c: Trampoline for
+ accessing the new RGCTX.
+
+ * generic-sharing.c: There is no separation between self, type
+ arguments and other types in the RGCTX anymore.
+
2008-04-25 Jonathan Chambers <joncham@gmail.com>
* mini-amd64.c (add_general): Remove previous stack adjustment.
return inflated->declaring;
}
-static gboolean
-inflated_type_is_equal_to_class (MonoType *inflated_type, MonoClass *klass)
-{
- return klass == mono_class_from_mono_type (inflated_type);
-}
-
/*
* mono_class_generic_class_relation:
* @klass: the class to be investigated
mono_class_generic_class_relation (MonoClass *klass, int info_type, MonoClass *method_klass,
MonoGenericContext *generic_context, int *arg_num)
{
- MonoRuntimeGenericContextTemplate *rgctx_template =
- mono_class_get_runtime_generic_context_template (method_klass);
- int i;
-
- /* Reflection types can only be handled in the extensible
- rgctx part. */
- if (info_type != MONO_RGCTX_INFO_REFLECTION_TYPE) {
- for (i = 0; i < rgctx_template->num_arg_infos; ++i) {
- MonoType *arg_info = rgctx_template->arg_infos [i];
- MonoType *inflated_arg;
-
- if (arg_info == NULL)
- continue;
-
- inflated_arg = mono_class_inflate_generic_type(arg_info, generic_context);
-
- if (inflated_type_is_equal_to_class (inflated_arg, klass)) {
- if (arg_num)
- *arg_num = i;
- return MINI_GENERIC_CLASS_RELATION_ARGUMENT;
- }
- }
+ int i = mono_class_lookup_or_register_other_info (method_klass, &klass->byval_arg, info_type, generic_context);
- if (!klass->generic_class && !klass->generic_container)
- g_assert_not_reached ();
-
- if (mini_class_get_container_class (klass) == mini_class_get_container_class (method_klass) &&
- mono_generic_context_equal_deep (mini_class_get_context (klass), generic_context))
- return MINI_GENERIC_CLASS_RELATION_SELF;
- }
-
- 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;
}
/*
* mono_helper_get_rgctx_other_ptr:
* @caller_class: the klass of the calling method
- * @rgctx: the runtime generic context
+ * @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
* static_data pointer).
*/
gpointer
-mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoRuntimeGenericContext *rgctx,
+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;
- int depth = caller_class->idepth;
- MonoRuntimeGenericSuperInfo *super_info = &((MonoRuntimeGenericSuperInfo*)rgctx)[-depth];
- MonoClass *klass = super_info->klass;
+ MonoClass *klass = vtable->klass;
MonoClass *result = NULL;
MonoTokenAndContext tc = { token, &klass->generic_class->context };
- gpointer rgctx_result_ptr, result_ptr;
+ gpointer result_ptr;
mono_loader_lock ();
result_ptr = result;
break;
case MONO_RGCTX_INFO_STATIC_DATA: {
- MonoVTable *vtable = mono_class_vtable (rgctx->domain, result);
- result_ptr = vtable->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 (rgctx->domain, result);
+ result_ptr = mono_class_vtable (vtable->domain, result);
break;
default:
g_assert_not_reached ();
}
- g_assert (rgctx_index >= 0);
- if (rgctx_index < MONO_RGCTX_MAX_OTHER_INFOS) {
- rgctx_result_ptr = rgctx->other_infos [rgctx_index];
- } else {
- g_assert (rgctx->extra_other_infos);
-
- rgctx_result_ptr = rgctx->extra_other_infos [rgctx_index - MONO_RGCTX_MAX_OTHER_INFOS];
- }
-
- g_assert (rgctx_result_ptr == result);
-
return result_ptr;
}
}
#endif
-MonoRuntimeGenericContext*
-mono_arch_find_static_call_rgctx (gpointer *regs, guint8 *code)
+MonoVTable*
+mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
{
- return (MonoRuntimeGenericContext*) regs [MONO_ARCH_RGCTX_REG];
+ return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
}
MonoInst*
gi->this_offset);
if (ji->method->flags & METHOD_ATTRIBUTE_STATIC) {
- MonoRuntimeGenericContext *rgctx = info;
+ MonoVTable *vtable = info;
- class = rgctx->vtable->klass;
+ class = vtable->klass;
} else {
MonoObject *this = info;
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/tabledefs.h>
+#include <mono/utils/mono-counters.h>
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
if (m->flags & METHOD_ATTRIBUTE_STATIC) {
#ifdef MONO_ARCH_RGCTX_REG
- MonoRuntimeGenericContext *rgctx = mono_arch_find_static_call_rgctx ((gpointer*)regs, code);
+ MonoVTable *vtable = mono_arch_find_static_call_vtable ((gpointer*)regs, code);
- klass = rgctx->vtable->klass;
+ klass = vtable->klass;
#else
g_assert_not_reached ();
#endif
}
static gpointer
-mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, MonoRuntimeGenericContext *rgctx, guint8 *tramp)
+mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
{
- guint32 encoded_offset = mono_arch_get_rgctx_lazy_fetch_offset ((gpointer*)regs);
- gpointer result;
+ static gboolean inited = FALSE;
+ static int num_lookups = 0;
- mono_class_fill_runtime_generic_context (rgctx);
+ guint32 slot = mono_arch_get_rgctx_lazy_fetch_offset ((gpointer*)regs);
- if (MONO_RGCTX_OFFSET_IS_INDIRECT (encoded_offset)) {
- int indirect_slot = MONO_RGCTX_OFFSET_INDIRECT_SLOT (encoded_offset);
- int offset = MONO_RGCTX_OFFSET_INDIRECT_OFFSET (encoded_offset);
-
- g_assert (indirect_slot == 0);
-
- result = *(gpointer*)((guint8*)rgctx->extra_other_infos + offset);
- } else {
- int offset = MONO_RGCTX_OFFSET_DIRECT_OFFSET (encoded_offset);
-
- result = *(gpointer*)((guint8*)rgctx + offset);
+ if (!inited) {
+ mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups);
+ inited = TRUE;
}
- g_assert (result);
+ num_lookups++;
- return result;
+ return mono_class_fill_runtime_generic_context (vtable, slot);
}
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
}
#endif
-MonoRuntimeGenericContext*
-mono_arch_find_static_call_rgctx (gpointer *regs, guint8 *code)
+MonoVTable*
+mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
{
- return (MonoRuntimeGenericContext*) regs [MONO_ARCH_RGCTX_REG];
+ return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
}
MonoInst*
if (method->klass->valuetype) \
GENERIC_SHARING_FAILURE ((opcode)); \
} while (0)
+#define GET_RGCTX(rgctx) do { \
+ MonoInst *this = NULL; \
+ GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip); \
+ if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) \
+ NEW_ARGLOAD (cfg, this, 0); \
+ (rgctx) = get_runtime_generic_context (cfg, method, this, ip); \
+ } while (0)
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
}
static MonoInst *
-mono_get_rgctx_var (MonoCompile *cfg)
+mono_get_vtable_var (MonoCompile *cfg)
{
g_assert (cfg->generic_sharing_context);
g_free (method_code);
}
-/*
- * Generates this->vtable->runtime_generic_context
- */
-static MonoInst*
-get_runtime_generic_context_from_this (MonoCompile *cfg, MonoInst *this, unsigned char *ip)
-{
- MonoInst *vtable, *rgc_ptr_addr, *rgc_ptr_offset, *rgc_ptr;
-
- MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
- vtable->cil_code = ip;
- vtable->inst_left = this;
- vtable->type = STACK_PTR;
-
- NEW_ICONST (cfg, rgc_ptr_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
-
- MONO_INST_NEW (cfg, rgc_ptr_addr, OP_PADD);
- rgc_ptr_addr->cil_code = ip;
- rgc_ptr_addr->inst_left = vtable;
- rgc_ptr_addr->inst_right = rgc_ptr_offset;
- rgc_ptr_addr->type = STACK_PTR;
-
- MONO_INST_NEW (cfg, rgc_ptr, CEE_LDIND_I);
- rgc_ptr->cil_code = ip;
- rgc_ptr->inst_left = rgc_ptr_addr;
- rgc_ptr->type = STACK_PTR;
-
- return rgc_ptr;
-}
-
static MonoInst*
get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, MonoInst *this, unsigned char *ip)
{
g_assert (!method->klass->valuetype);
if (method->flags & METHOD_ATTRIBUTE_STATIC) {
- MonoInst *rgctx_loc, *rgctx_var;
+ MonoInst *vtable_loc, *vtable_var;
- rgctx_loc = mono_get_rgctx_var (cfg);
- NEW_TEMPLOAD (cfg, rgctx_var, rgctx_loc->inst_c0);
+ vtable_loc = mono_get_vtable_var (cfg);
+ NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
- return rgctx_var;
+ return vtable_var;
} else {
- return get_runtime_generic_context_from_this (cfg, this, ip);
+ MonoInst *vtable;
+
+ MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
+ vtable->cil_code = ip;
+ vtable->inst_left = this;
+ vtable->type = STACK_PTR;
+
+ return vtable;
}
}
static gpointer
create_rgctx_lazy_fetch_trampoline (guint32 offset)
{
+ static gboolean inited = FALSE;
+ static int num_trampolines = 0;
+
gpointer tramp, ptr;
mono_jit_lock ();
g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
mono_jit_unlock ();
- return ptr;
-}
-
-static MonoInst*
-lazy_fetch_rgctx_direct_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
-{
- MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
- guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_DIRECT_OFFSET (offset));
- int temp;
- MonoInst *field;
-
- temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
-
- NEW_TEMPLOAD (cfg, field, temp);
-
- return field;
-}
-
-static MonoInst*
-lazy_fetch_rgctx_indirect_field (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *rgc_ptr, int offset, unsigned char *ip)
-{
- MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
- guint8 *tramp = create_rgctx_lazy_fetch_trampoline (MONO_RGCTX_ENCODE_INDIRECT_OFFSET (offset));
- int temp;
- MonoInst *field;
-
- temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
-
- NEW_TEMPLOAD (cfg, field, temp);
-
- return field;
-}
-
-/*
- * Generates ((MonoRuntimeGenericSuperInfo*)rgc)[-depth].XXX where XXX
- * is specified by rgctx_type.
- */
-static MonoInst*
-get_runtime_generic_context_super_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int depth, int rgctx_type, unsigned char *ip)
-{
- int field_offset_const, offset;
-
- g_assert (depth >= 1);
-
- switch (rgctx_type) {
- case MONO_RGCTX_INFO_STATIC_DATA :
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, static_data);
- break;
- case MONO_RGCTX_INFO_KLASS :
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, klass);
- break;
- case MONO_RGCTX_INFO_VTABLE:
- field_offset_const = G_STRUCT_OFFSET (MonoRuntimeGenericSuperInfo, vtable);
- break;
- default :
- g_assert_not_reached ();
+ if (!inited) {
+ mono_counters_register ("RGCTX num lazy fetch trampolines",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
+ inited = TRUE;
}
+ num_trampolines++;
- offset = -depth * sizeof (MonoRuntimeGenericSuperInfo) + field_offset_const;
-
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
-}
-
-static int
-get_rgctx_arg_info_field_offset (int rgctx_type)
-{
- switch (rgctx_type) {
- case MONO_RGCTX_INFO_STATIC_DATA :
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, static_data);
- case MONO_RGCTX_INFO_KLASS:
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, klass);
- case MONO_RGCTX_INFO_VTABLE :
- return G_STRUCT_OFFSET (MonoRuntimeGenericArgInfo, vtable);
- default:
- g_assert_not_reached ();
- }
-}
-
-/*
- * Generates rgc->arg_infos [arg_num].XXX where XXX is specified by
- * rgctx_type;
- */
-static MonoInst*
-get_runtime_generic_context_arg_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int arg_num, int rgctx_type, unsigned char *ip)
-{
- int arg_info_offset, arg_info_field_offset, offset;
-
- g_assert (arg_num >= 0);
- //g_assert (!lazy);
-
- arg_info_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, arg_infos) +
- arg_num * sizeof (MonoRuntimeGenericArgInfo);
-
- arg_info_field_offset = get_rgctx_arg_info_field_offset (rgctx_type);
-
- offset = arg_info_offset + arg_info_field_offset;
-
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, offset, ip);
+ return ptr;
}
/*
*/
static MonoInst*
get_runtime_generic_context_other_table_ptr (MonoCompile *cfg, MonoBasicBlock *bblock,
- MonoInst *rgc_ptr, int index, unsigned char *ip)
+ MonoInst *rgc_ptr, int slot, const unsigned char *ip)
{
- if (index < MONO_RGCTX_MAX_OTHER_INFOS) {
- int other_type_offset;
-
- other_type_offset = G_STRUCT_OFFSET (MonoRuntimeGenericContext, other_infos) +
- index * sizeof (gpointer);
+ MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
+ guint8 *tramp = create_rgctx_lazy_fetch_trampoline (slot);
+ int temp;
+ MonoInst *field;
- return lazy_fetch_rgctx_direct_field (cfg, bblock, rgc_ptr, other_type_offset, ip);
- } else {
- int slot_offset;
+ temp = mono_emit_native_call (cfg, bblock, tramp, sig, &rgc_ptr, ip, FALSE, FALSE);
- slot_offset = (index - MONO_RGCTX_MAX_OTHER_INFOS) * sizeof (gpointer);
+ NEW_TEMPLOAD (cfg, field, temp);
- return lazy_fetch_rgctx_indirect_field (cfg, bblock, rgc_ptr, slot_offset, ip);
- }
+ return field;
}
static MonoInst*
int relation = mono_class_generic_class_relation (klass, rgctx_type, method->klass, generic_context, &arg_num);
switch (relation) {
- case MINI_GENERIC_CLASS_RELATION_SELF: {
- int depth = klass->idepth;
- return get_runtime_generic_context_super_ptr (cfg, bblock, rgctx, depth, rgctx_type, ip);
- }
- case MINI_GENERIC_CLASS_RELATION_ARGUMENT:
- return get_runtime_generic_context_arg_ptr (cfg, bblock, rgctx, arg_num, rgctx_type, ip);
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:
static MonoInst*
get_runtime_generic_context_method (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *bblock,
- MonoMethod *cmethod, MonoGenericContext *generic_context, MonoInst *rgctx, int rgctx_type, unsigned char *ip)
+ 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);
* (for non-static methods) are live.
*/
if (method->flags & METHOD_ATTRIBUTE_STATIC) {
- mono_get_rgctx_var (cfg);
+ mono_get_vtable_var (cfg);
} else {
MonoInst *this, *dummy_use;
MonoType *this_type;
MonoMethodSignature *fsig = NULL;
int temp, array_rank = 0;
int virtual = *ip == CEE_CALLVIRT;
- MonoInst *rgctx_arg = NULL;
gboolean no_spill;
int context_used = 0;
- gboolean pass_rgctx = FALSE;
+ gboolean pass_vtable = FALSE;
+ MonoInst *vtable_arg = NULL;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
/*
- * Pass rgctx iff target method might
+ * Pass vtable iff target method might
* be shared, which means that sharing
* is enabled for its class and its
* context is sharable (and it's not a
*/
if (sharing_enabled && context_sharable &&
!mini_method_get_context (cmethod)->method_inst)
- pass_rgctx = TRUE;
+ pass_vtable = TRUE;
}
if (cfg->generic_sharing_context && cmethod) {
}
}
- if (pass_rgctx) {
+ if (pass_vtable) {
if (context_used) {
- MonoInst *this = NULL, *rgctx, *vtable, *field_offset, *field_addr;
-
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD (*ip);
+ MonoInst *rgctx;
- if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
- NEW_ARGLOAD (cfg, this, 0);
- rgctx = get_runtime_generic_context (cfg, method, this, ip);
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
+ GET_RGCTX (rgctx);
+ vtable_arg = get_runtime_generic_context_ptr (cfg, method, bblock, cmethod->klass,
token, MINI_TOKEN_SOURCE_METHOD, generic_context,
rgctx, MONO_RGCTX_INFO_VTABLE, ip);
-
- NEW_ICONST (cfg, field_offset, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
-
- MONO_INST_NEW (cfg, field_addr, OP_PADD);
- field_addr->cil_code = ip;
- field_addr->inst_left = vtable;
- field_addr->inst_right = field_offset;
- field_addr->type = STACK_PTR;
-
- MONO_INST_NEW (cfg, rgctx_arg, CEE_LDIND_I);
- rgctx_arg->cil_code = ip;
- rgctx_arg->inst_left = field_addr;
- rgctx_arg->type = STACK_PTR;
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
- NEW_PCONST (cfg, rgctx_arg, vtable->runtime_generic_context);
+ NEW_VTABLECONST (cfg, vtable_arg, vtable);
}
}
/* tail recursion elimination */
if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET &&
- !rgctx_arg) {
+ !vtable_arg) {
gboolean has_vtargs = FALSE;
int i;
if (*ip == CEE_CALL)
g_assert (context_used);
else if (*ip == CEE_CALLI)
- g_assert (!rgctx_arg);
+ g_assert (!vtable_arg);
else
g_assert_not_reached ();
/* Prevent inlining of methods with indirect calls */
INLINE_FAILURE;
if (no_spill) {
- ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+ ins = (MonoInst*)mono_emit_rgctx_calli (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
*sp++ = ins;
} else {
- temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, rgctx_arg, ip);
+ temp = mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, addr, vtable_arg, ip);
if (temp != -1) {
NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
sp++;
}
} else if (no_spill) {
- ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL);
+ ins = (MonoInst*)mono_emit_rgctx_method_call (cfg, bblock, cmethod, fsig, sp,
+ vtable_arg, ip, virtual ? sp [0] : NULL);
*sp++ = ins;
} else {
- if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp, rgctx_arg, ip, virtual ? sp [0] : NULL)) != -1) {
+ if ((temp = mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
+ vtable_arg, ip, virtual ? sp [0] : NULL)) != -1) {
MonoInst *load;
NEW_TEMPLOAD (cfg, load, temp);
if (mono_class_needs_cctor_run (klass, method)) {
MonoMethodSignature *sig = helper_sig_generic_class_init_trampoline;
MonoCallInst *call;
- MonoInst *vtable;
+ MonoInst *vtable, *rgctx;
if (!(method->flags & METHOD_ATTRIBUTE_STATIC))
NEW_ARGLOAD (cfg, this, 0);
else
this = NULL;
- if (relation == MINI_GENERIC_CLASS_RELATION_SELF && this) {
- MONO_INST_NEW (cfg, vtable, CEE_LDIND_I);
- vtable->cil_code = ip;
- vtable->inst_left = this;
- vtable->type = STACK_PTR;
- vtable->klass = klass;
- } else {
- MonoInst *rgctx = get_runtime_generic_context (cfg, method, this, ip);
-
- vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
+ rgctx = get_runtime_generic_context (cfg, method, this, ip);
+ vtable = get_runtime_generic_context_ptr (cfg, method, bblock, klass,
token, MINI_TOKEN_SOURCE_FIELD, generic_context,
rgctx, MONO_RGCTX_INFO_VTABLE, ip);
- }
call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
call->inst.opcode = OP_TRAMPCALL_VTABLE;
};
enum {
- MINI_GENERIC_CLASS_RELATION_SELF,
- MINI_GENERIC_CLASS_RELATION_ARGUMENT,
MINI_GENERIC_CLASS_RELATION_OTHER_TABLE,
MINI_GENERIC_CLASS_RELATION_OTHER
};
gpointer mono_arch_create_jit_trampoline (MonoMethod *method) MONO_INTERNAL;
MonoJitInfo *mono_arch_create_jump_trampoline (MonoMethod *method) MONO_INTERNAL;
gpointer mono_arch_create_class_init_trampoline(MonoVTable *vtable) MONO_INTERNAL;
-gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset) MONO_INTERNAL;
+gpointer mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot) MONO_INTERNAL;
guint32 mono_arch_get_rgctx_lazy_fetch_offset (gpointer *regs) MONO_INTERNAL;
GList *mono_arch_get_allocatable_int_vars (MonoCompile *cfg) MONO_INTERNAL;
GList *mono_arch_get_global_int_regs (MonoCompile *cfg) MONO_INTERNAL;
gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) MONO_INTERNAL;
void mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call) MONO_INTERNAL;
MonoMethod* mono_arch_find_imt_method (gpointer *regs, guint8 *code) MONO_INTERNAL;
-MonoRuntimeGenericContext* mono_arch_find_static_call_rgctx (gpointer *regs, guint8 *code) MONO_INTERNAL;
+MonoVTable* mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code) MONO_INTERNAL;
gpointer mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count) MONO_INTERNAL;
void mono_arch_notify_pending_exc (void) MONO_INTERNAL;
int mono_class_generic_class_relation (MonoClass *klass, int info_type, MonoClass *method_klass,
MonoGenericContext *generic_context, int *arg_num) MONO_INTERNAL;
-gpointer mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoRuntimeGenericContext *rgctx,
+gpointer mono_helper_get_rgctx_other_ptr (MonoClass *caller_class, MonoVTable *vtable,
guint32 token, guint32 token_source, guint32 rgctx_type,
gint32 rgctx_index) MONO_INTERNAL;
}
gpointer
-mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
+mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot)
{
guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
- gboolean indirect = MONO_RGCTX_OFFSET_IS_INDIRECT (encoded_offset);
- int offset = indirect ? MONO_RGCTX_OFFSET_INDIRECT_OFFSET (encoded_offset) :
- MONO_RGCTX_OFFSET_DIRECT_OFFSET (encoded_offset);
- guint8 *code, *buf, *jump;
- guint8 *dummy;
- int slots_reg;
+ guint8 *code, *buf;
+ guint8 **rgctx_null_jumps;
+ int tramp_size;
+ int depth, index;
+ int i;
g_assert (tramp);
- if (indirect)
- g_assert (MONO_RGCTX_OFFSET_INDIRECT_SLOT (encoded_offset) == 0);
- code = buf = mono_global_codeman_reserve (32);
+ index = slot;
+ for (depth = 0; ; ++depth) {
+ int size = mono_class_rgctx_get_array_size (depth);
- /* load slots ptr */
- if (indirect) {
- /* if indirect, load extra_other_infos ptr */
- amd64_mov_reg_membase (buf, AMD64_RAX, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoRuntimeGenericContext, extra_other_infos), 8);
- slots_reg = AMD64_RAX;
- } else {
- slots_reg = AMD64_ARG_REG1;
+ if (index < size - 1)
+ break;
+ index -= size - 1;
}
- /* fetch slot */
- amd64_mov_reg_membase (buf, AMD64_RAX, slots_reg, offset, 8);
- dummy = buf;
+ tramp_size = 32 + 8 * depth;
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
- /* is slot null? */
+ rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
+
+ /* load rgctx ptr from vtable */
+ amd64_mov_reg_membase (buf, AMD64_RAX, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 8);
+ /* is the rgctx ptr null? */
amd64_test_reg_reg (buf, AMD64_RAX, AMD64_RAX);
- jump = buf;
/* if yes, jump to actual trampoline */
+ rgctx_null_jumps [0] = buf;
amd64_branch8 (buf, X86_CC_Z, -1, 1);
- /* if no, just return */
+ for (i = 0; i < depth; ++i) {
+ /* load ptr to next array */
+ amd64_mov_reg_membase (buf, AMD64_RAX, AMD64_RAX, 0, 8);
+ /* is the ptr null? */
+ amd64_test_reg_reg (buf, AMD64_RAX, AMD64_RAX);
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [i + 1] = buf;
+ amd64_branch8 (buf, X86_CC_Z, -1, 1);
+ }
+
+ /* fetch slot */
+ amd64_mov_reg_membase (buf, AMD64_RAX, AMD64_RAX, sizeof (gpointer) * (index + 1), 8);
+ /* is the slot null? */
+ amd64_test_reg_reg (buf, AMD64_RAX, AMD64_RAX);
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [depth + 1] = buf;
+ amd64_branch8 (buf, X86_CC_Z, -1, 1);
+ /* otherwise return */
amd64_ret (buf);
- x86_patch (jump, buf);
+ for (i = 0; i <= depth + 1; ++i)
+ x86_patch (rgctx_null_jumps [i], buf);
+
+ g_free (rgctx_null_jumps);
+
/* move the rgctx pointer to the VTABLE register */
amd64_mov_reg_reg (buf, MONO_ARCH_VTABLE_REG, AMD64_ARG_REG1, 8);
- /* store the offset in RAX */
- amd64_mov_reg_imm (buf, AMD64_RAX, encoded_offset);
+ /* store the slot in RAX */
+ amd64_mov_reg_imm (buf, AMD64_RAX, slot);
/* jump to the actual trampoline */
amd64_jump_code (buf, tramp);
mono_arch_flush_icache (code, buf - code);
- g_assert (buf - code <= 32);
+ g_assert (buf - code <= tramp_size);
return code;
}
}
gpointer
-mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 encoded_offset)
+mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot)
{
guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
- gboolean indirect = MONO_RGCTX_OFFSET_IS_INDIRECT (encoded_offset);
- int offset = indirect ? MONO_RGCTX_OFFSET_INDIRECT_OFFSET (encoded_offset) :
- MONO_RGCTX_OFFSET_DIRECT_OFFSET (encoded_offset);
- guint8 *code, *buf, *jump;
- guint8 *dummy;
+ guint8 *code, *buf;
+ guint8 **rgctx_null_jumps;
+ int tramp_size;
+ int depth, index;
+ int i;
g_assert (tramp);
- if (indirect)
- g_assert (MONO_RGCTX_OFFSET_INDIRECT_SLOT (encoded_offset) == 0);
- code = buf = mono_global_codeman_reserve (32);
+ index = slot;
+ for (depth = 0; ; ++depth) {
+ int size = mono_class_rgctx_get_array_size (depth);
- /* load rgctx ptr */
- x86_mov_reg_membase (buf, X86_EAX, X86_ESP, 4, 4);
- if (indirect) {
- /* if indirect, load extra_other_infos ptr */
- x86_mov_reg_membase (buf, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoRuntimeGenericContext, extra_other_infos), 4);
+ if (index < size - 1)
+ break;
+ index -= size - 1;
}
- /* fetch slot */
- x86_mov_reg_membase (buf, X86_EAX, X86_EAX, offset, 4);
- dummy = buf;
+ tramp_size = 36 + 6 * depth;
+
+ code = buf = mono_global_codeman_reserve (tramp_size);
+
+ rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
- /* is slot null? */
+ /* load vtable ptr */
+ x86_mov_reg_membase (buf, X86_EAX, X86_ESP, 4, 4);
+ /* load rgctx ptr from vtable */
+ x86_mov_reg_membase (buf, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 4);
+ /* is the rgctx ptr null? */
x86_test_reg_reg (buf, X86_EAX, X86_EAX);
- jump = buf;
/* if yes, jump to actual trampoline */
+ rgctx_null_jumps [0] = buf;
x86_branch8 (buf, X86_CC_Z, -1, 1);
- /* if no, just return */
+ for (i = 0; i < depth; ++i) {
+ /* load ptr to next array */
+ x86_mov_reg_membase (buf, X86_EAX, X86_EAX, 0, 4);
+ /* is the ptr null? */
+ x86_test_reg_reg (buf, X86_EAX, X86_EAX);
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [i + 1] = buf;
+ x86_branch8 (buf, X86_CC_Z, -1, 1);
+ }
+
+ /* fetch slot */
+ x86_mov_reg_membase (buf, X86_EAX, X86_EAX, sizeof (gpointer) * (index + 1), 4);
+ /* is the slot null? */
+ x86_test_reg_reg (buf, X86_EAX, X86_EAX);
+ /* if yes, jump to actual trampoline */
+ rgctx_null_jumps [depth + 1] = buf;
+ x86_branch8 (buf, X86_CC_Z, -1, 1);
+ /* otherwise return */
x86_ret (buf);
+ for (i = 0; i <= depth + 1; ++i)
+ x86_patch (rgctx_null_jumps [i], buf);
+
+ g_free (rgctx_null_jumps);
+
/*
* our stack looks like this (tos on top):
*
- * | ret addr |
- * | rgctx ptr |
- * | ... |
+ * | ret addr |
+ * | vtable ptr |
+ * | ... |
*
* the trampoline code expects it to look like this:
*
- * | rgctx ptr |
- * | ret addr |
- * | ... |
+ * | vtable ptr |
+ * | ret addr |
+ * | ... |
*
* whereas our caller expects to still have one argument on
* the stack when we return, so we transform the stack into
* this:
*
- * | rgctx ptr |
- * | ret addr |
- * | dummy |
- * | ... |
+ * | vtable ptr |
+ * | ret addr |
+ * | dummy |
+ * | ... |
*
- * which actually only requires us to push the rgctx ptr, and
- * the "old" rgctx ptr becomes the dummy.
+ * which actually only requires us to push the vtable ptr, and
+ * the "old" vtable ptr becomes the dummy.
*/
- x86_patch (jump, buf);
x86_push_membase (buf, X86_ESP, 4);
- x86_mov_reg_imm (buf, X86_EAX, encoded_offset);
+ x86_mov_reg_imm (buf, X86_EAX, slot);
x86_jump_code (buf, tramp);
mono_arch_flush_icache (code, buf - code);
- g_assert (buf - code <= 32);
+ g_assert (buf - code <= tramp_size);
return code;
}