* Miguel de Icaza (miguel@ximian.com)
* Paolo Molaro (lupus@ximian.com)
*
- * (C) 2001-2004 Ximian, Inc.
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
*/
#include <config.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "mono/metadata/mono-debug-debugger.h"
#include <mono/metadata/gc-internal.h>
#include <mono/utils/strenc.h>
+#include <mono/utils/mono-counters.h>
+#include "cominterop.h"
#ifdef HAVE_BOEHM_GC
#define NEED_TO_ZERO_PTRFREE 1
get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
static MonoString*
-mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
#define ldstr_lock() EnterCriticalSection (&ldstr_section)
#define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
static CRITICAL_SECTION ldstr_section;
+static gboolean profile_allocs = TRUE;
+
void
mono_runtime_object_init (MonoObject *this)
{
/* Main thread */
static MonoThread *main_thread;
+/* Functions supplied by the runtime */
+static MonoRuntimeCallbacks callbacks;
+
/**
* mono_thread_set_main:
* @thread: thread to set as the main thread
return ex;
}
-
/*
* mono_runtime_class_init:
* @vtable: vtable that needs to be initialized
*/
void
mono_runtime_class_init (MonoVTable *vtable)
+{
+ mono_runtime_class_init_full (vtable, TRUE);
+}
+
+/*
+ * mono_runtime_class_init_full:
+ * @vtable that neeeds to be initialized
+ * @raise_exception is TRUE, exceptions are raised intead of returned
+ *
+ */
+MonoException *
+mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
{
MonoException *exc;
MonoException *exc_to_throw;
MONO_ARCH_SAVE_REGS;
if (vtable->initialized)
- return;
+ return NULL;
exc = NULL;
klass = vtable->klass;
/* double check... */
if (vtable->initialized) {
mono_type_initialization_unlock ();
- return;
+ return NULL;
}
if (vtable->init_failed) {
mono_type_initialization_unlock ();
/* The type initialization already failed once, rethrow the same exception */
- mono_raise_exception (get_type_init_exception_for_vtable (vtable));
- return;
+ if (raise_exception)
+ mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+ return get_type_init_exception_for_vtable (vtable);
}
lock = g_hash_table_lookup (type_initialization_hash, vtable);
if (lock == NULL) {
if (!mono_domain_set (domain, FALSE)) {
vtable->initialized = 1;
mono_type_initialization_unlock ();
- mono_raise_exception (mono_get_exception_appdomain_unloaded ());
+ if (raise_exception)
+ mono_raise_exception (mono_get_exception_appdomain_unloaded ());
+ return mono_get_exception_appdomain_unloaded ();
}
}
lock = g_malloc (sizeof(TypeInitializationLock));
if (lock->initializing_tid == tid || lock->done) {
mono_type_initialization_unlock ();
- return;
+ return NULL;
}
/* see if the thread doing the initialization is already blocked on this thread */
blocked = GUINT_TO_POINTER (lock->initializing_tid);
if (pending_lock->initializing_tid == tid) {
if (!pending_lock->done) {
mono_type_initialization_unlock ();
- return;
+ return NULL;
} else {
/* the thread doing the initialization is blocked on this thread,
but on a lock that has already been freed. It just hasn't got
if (vtable->init_failed) {
/* Either we were the initializing thread or we waited for the initialization */
- mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+ if (raise_exception)
+ mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+ return get_type_init_exception_for_vtable (vtable);
}
} else {
vtable->initialized = 1;
- return;
+ return NULL;
}
+ return NULL;
}
static
}
static gpointer
-default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
+default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
{
g_error ("remoting not installed");
return NULL;
#error "MONO_IMT_SIZE cannot be larger than 32"
#endif
+void
+mono_install_callbacks (MonoRuntimeCallbacks *cbs)
+{
+ memcpy (&callbacks, cbs, sizeof (*cbs));
+}
+
+MonoRuntimeCallbacks*
+mono_get_runtime_callbacks (void)
+{
+ return &callbacks;
+}
+
void
mono_install_trampoline (MonoTrampoline func)
{
if (default_mono_free_method != NULL)
default_mono_free_method (domain, method);
+ mono_method_clear_object (domain, method);
+
mono_free_method (method);
}
if (field->type->byref)
break;
+ if (static_fields && field->offset == -1)
+ /* special static */
+ continue;
+
pos = field->offset / sizeof (gpointer);
pos += offset;
return mono_string_new_size (mono_domain_get (), length);
}
-static void
+void
mono_class_compute_gc_descriptor (MonoClass *class)
{
int max_set = 0;
return SPECIAL_STATIC_NONE;
}
+static gpointer imt_trampoline = NULL;
+
+void
+mono_install_imt_trampoline (gpointer tramp_code)
+{
+ imt_trampoline = tramp_code;
+}
+
+static gpointer vtable_trampoline = NULL;
+
+void
+mono_install_vtable_trampoline (gpointer tramp_code)
+{
+ vtable_trampoline = tramp_code;
+}
+
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
#define mix(a,b,c) { \
a -= c; a ^= rot(c, 4); c += b; \
}
guint32
-mono_method_get_imt_slot (MonoMethod *method) {
- MonoMethodSignature *sig = mono_method_signature (method);
- int hashes_count = sig->param_count + 4;
- guint32 *hashes_start = malloc (hashes_count * sizeof (guint32));
- guint32 *hashes = hashes_start;
+mono_method_get_imt_slot (MonoMethod *method)
+{
+ MonoMethodSignature *sig;
+ int hashes_count;
+ guint32 *hashes_start, *hashes;
guint32 a, b, c;
int i;
-
+
+ /* This can be used to stress tests the collision code */
+ //return 0;
+
+ /*
+ * We do this to simplify generic sharing. It will hurt
+ * performance in cases where a class implements two different
+ * instantiations of the same generic interface.
+ * The code in build_imt_slots () depends on this.
+ */
+ if (method->is_inflated)
+ method = ((MonoMethodInflated*)method)->declaring;
+
+ sig = mono_method_signature (method);
+ hashes_count = sig->param_count + 4;
+ hashes_start = malloc (hashes_count * sizeof (guint32));
+ hashes = hashes_start;
+
if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
method->klass->name_space, method->klass->name, method->name);
/* we build just a single imt slot and this is not it */
return;
}
-
- entry = malloc (sizeof (MonoImtBuilderEntry));
- entry->method = method;
- entry->vtable_slot = vtable_slot;
+
+ entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
+ entry->key = method;
+ entry->value.vtable_slot = vtable_slot;
entry->next = imt_builder [imt_slot];
if (imt_builder [imt_slot] != NULL) {
entry->children = imt_builder [imt_slot]->children + 1;
MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
- return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
+ return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
}
static int
int i;
for (i = start; i < end; ++i) {
MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
- item->method = sorted_array [i]->method;
- item->vtable_slot = sorted_array [i]->vtable_slot;
+ item->key = sorted_array [i]->key;
+ item->value = sorted_array [i]->value;
+ item->has_target_code = sorted_array [i]->has_target_code;
item->is_equals = TRUE;
if (i < end - 1)
item->check_target_idx = out_array->len + 1;
int middle = start + count / 2;
MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
- item->method = sorted_array [middle]->method;
+ item->key = sorted_array [middle]->key;
item->is_equals = FALSE;
g_ptr_array_add (out_array, item);
imt_emit_ir (sorted_array, start, middle, out_array);
}
static gpointer
-initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
+initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
+{
if (imt_builder_entry != NULL) {
- if (imt_builder_entry->children == 0) {
+ if (imt_builder_entry->children == 0 && !fail_tramp) {
/* No collision, return the vtable slot contents */
- return vtable->vtable [imt_builder_entry->vtable_slot];
+ return vtable->vtable [imt_builder_entry->value.vtable_slot];
} else {
/* Collision, build the thunk */
GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
gpointer result;
int i;
- result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
+ result = imt_thunk_builder (vtable, domain,
+ (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
for (i = 0; i < imt_ir->len; ++i)
g_free (g_ptr_array_index (imt_ir, i));
g_ptr_array_free (imt_ir, TRUE);
return result;
}
} else {
- /* Empty slot */
- return NULL;
+ if (fail_tramp)
+ return fail_tramp;
+ else
+ /* Empty slot */
+ return NULL;
}
}
+static MonoImtBuilderEntry*
+get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
+
+/*
+ * LOCKING: requires the loader and domain locks.
+ *
+*/
static void
-build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
+build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
+{
int i;
GSList *list_item;
guint32 imt_collisions_bitmap = 0;
MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
int method_count = 0;
gboolean record_method_count_for_max_collisions = FALSE;
+ gboolean has_generic_virtual = FALSE;
#if DEBUG_IMT
printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
MonoClass *iface = klass->interfaces_packed [i];
int interface_offset = klass->interface_offsets_packed [i];
int method_slot_in_interface;
- mono_class_setup_methods (iface);
for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
- MonoMethod *method = iface->methods [method_slot_in_interface];
+ MonoMethod *method;
+
+ if (slot_num >= 0 && iface->is_inflated) {
+ /*
+ * The imt slot of the method is the same as for its declaring method,
+ * see the comment in mono_method_get_imt_slot (), so we can
+ * avoid inflating methods which will be discarded by
+ * add_imt_builder_entry anyway.
+ */
+ method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
+ if (mono_method_get_imt_slot (method) != slot_num)
+ continue;
+ }
+ method = mono_class_get_method_by_index (iface, method_slot_in_interface);
+ if (method->is_generic) {
+ has_generic_virtual = TRUE;
+ continue;
+ }
add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
}
}
for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
MonoClass* iface = list_item->data;
int method_slot_in_interface;
- mono_class_setup_methods (iface);
for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
- MonoMethod *method = iface->methods [method_slot_in_interface];
+ MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
}
interface_offset += iface->method.count;
}
for (i = 0; i < MONO_IMT_SIZE; ++i) {
/* overwrite the imt slot only if we're building all the entries or if
- * we're uilding this specific one
+ * we're building this specific one
*/
- if (slot_num < 0 || i == slot_num)
- imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
+ if (slot_num < 0 || i == slot_num) {
+ MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
+
+ if (entries) {
+ if (imt_builder [i]) {
+ MonoImtBuilderEntry *entry;
+
+ /* Link entries with imt_builder [i] */
+ for (entry = entries; entry->next; entry = entry->next)
+ ;
+ entry->next = imt_builder [i];
+ entries->children += imt_builder [i]->children + 1;
+ }
+ imt_builder [i] = entries;
+ }
+
+ if (has_generic_virtual) {
+ /*
+ * There might be collisions later when the the thunk is expanded.
+ */
+ imt_collisions_bitmap |= (1 << i);
+
+ /*
+ * The IMT thunk might be called with an instance of one of the
+ * generic virtual methods, so has to fallback to the IMT trampoline.
+ */
+ imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
+ } else {
+ imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
+ }
+ }
#if DEBUG_IMT
printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
#endif
MonoImtBuilderEntry* entry = imt_builder [i];
while (entry != NULL) {
MonoImtBuilderEntry* next = entry->next;
- free (entry);
+ g_free (entry);
entry = next;
}
}
build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
}
-static gpointer imt_trampoline = NULL;
-
-void
-mono_install_imt_trampoline (gpointer tramp_code)
-{
- imt_trampoline = tramp_code;
-}
-
-static gpointer vtable_trampoline = NULL;
-
-void
-mono_install_vtable_trampoline (gpointer tramp_code)
-{
- vtable_trampoline = tramp_code;
-}
-
/**
* mono_vtable_build_imt_slot:
* @vtable: virtual object table struct
* Fill the given @imt_slot in the IMT table of @vtable with
* a trampoline or a thunk for the case of collisions.
* This is part of the internal mono API.
+ *
+ * LOCKING: Take the domain lock.
*/
void
mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
* Update and heck needs to ahppen inside the proper domain lock, as all
* the changes made to a MonoVTable.
*/
+ mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
mono_domain_lock (vtable->domain);
/* we change the slot only if it wasn't changed from the generic imt trampoline already */
if (imt [imt_slot] == imt_trampoline)
build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
mono_domain_unlock (vtable->domain);
+ mono_loader_unlock ();
+}
+
+
+/*
+ * The first two free list entries both belong to the wait list: The
+ * first entry is the pointer to the head of the list and the second
+ * entry points to the last element. That way appending and removing
+ * the first element are both O(1) operations.
+ */
+#define NUM_FREE_LISTS 12
+#define FIRST_FREE_LIST_SIZE 64
+#define MAX_WAIT_LENGTH 50
+#define THUNK_THRESHOLD 10
+
+/*
+ * LOCKING: The domain lock must be held.
+ */
+static void
+init_thunk_free_lists (MonoDomain *domain)
+{
+ if (domain->thunk_free_lists)
+ return;
+ domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
+}
+
+static int
+list_index_for_size (int item_size)
+{
+ int i = 2;
+ int size = FIRST_FREE_LIST_SIZE;
+
+ while (item_size > size && i < NUM_FREE_LISTS - 1) {
+ i++;
+ size <<= 1;
+ }
+
+ return i;
+}
+
+/**
+ * mono_method_alloc_generic_virtual_thunk:
+ * @domain: a domain
+ * @size: size in bytes
+ *
+ * Allocs size bytes to be used for the code of a generic virtual
+ * thunk. It's either allocated from the domain's code manager or
+ * reused from a previously invalidated piece.
+ *
+ * LOCKING: The domain lock must be held.
+ */
+gpointer
+mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
+{
+ static gboolean inited = FALSE;
+ static int generic_virtual_thunks_size = 0;
+
+ guint32 *p;
+ int i;
+ MonoThunkFreeList **l;
+
+ init_thunk_free_lists (domain);
+
+ size += sizeof (guint32);
+ if (size < sizeof (MonoThunkFreeList))
+ size = sizeof (MonoThunkFreeList);
+
+ i = list_index_for_size (size);
+ for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
+ if ((*l)->size >= size) {
+ MonoThunkFreeList *item = *l;
+ *l = item->next;
+ return ((guint32*)item) + 1;
+ }
+ }
+
+ /* no suitable item found - search lists of larger sizes */
+ while (++i < NUM_FREE_LISTS) {
+ MonoThunkFreeList *item = domain->thunk_free_lists [i];
+ if (!item)
+ continue;
+ g_assert (item->size > size);
+ domain->thunk_free_lists [i] = item->next;
+ return ((guint32*)item) + 1;
+ }
+
+ /* still nothing found - allocate it */
+ if (!inited) {
+ mono_counters_register ("Generic virtual thunk bytes",
+ MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
+ inited = TRUE;
+ }
+ generic_virtual_thunks_size += size;
+
+ p = mono_domain_code_reserve (domain, size);
+ *p = size;
+
+ return p + 1;
+}
+
+/*
+ * LOCKING: The domain lock must be held.
+ */
+static void
+invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
+{
+ guint32 *p = code;
+ MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
+
+ init_thunk_free_lists (domain);
+
+ while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
+ MonoThunkFreeList *item = domain->thunk_free_lists [0];
+ int length = item->length;
+ int i;
+
+ /* unlink the first item from the wait list */
+ domain->thunk_free_lists [0] = item->next;
+ domain->thunk_free_lists [0]->length = length - 1;
+
+ i = list_index_for_size (item->size);
+
+ /* put it in the free list */
+ item->next = domain->thunk_free_lists [i];
+ domain->thunk_free_lists [i] = item;
+ }
+
+ l->next = NULL;
+ if (domain->thunk_free_lists [1]) {
+ domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
+ domain->thunk_free_lists [0]->length++;
+ } else {
+ g_assert (!domain->thunk_free_lists [0]);
+
+ domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
+ domain->thunk_free_lists [0]->length = 1;
+ }
+}
+
+typedef struct _GenericVirtualCase {
+ MonoMethod *method;
+ gpointer code;
+ int count;
+ struct _GenericVirtualCase *next;
+} GenericVirtualCase;
+
+/*
+ * get_generic_virtual_entries:
+ *
+ * Return IMT entries for the generic virtual method instances for vtable slot
+ * VTABLE_SLOT.
+ */
+static MonoImtBuilderEntry*
+get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
+{
+ GenericVirtualCase *list;
+ MonoImtBuilderEntry *entries;
+
+ mono_domain_lock (domain);
+ if (!domain->generic_virtual_cases)
+ domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
+ list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+
+ entries = NULL;
+ for (; list; list = list->next) {
+ MonoImtBuilderEntry *entry;
+
+ if (list->count < THUNK_THRESHOLD)
+ continue;
+
+ entry = g_new0 (MonoImtBuilderEntry, 1);
+ entry->key = list->method;
+ entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
+ entry->has_target_code = 1;
+ if (entries)
+ entry->children = entries->children + 1;
+ entry->next = entries;
+ entries = entry;
+ }
+
+ mono_domain_unlock (domain);
+
+ /* FIXME: Leaking memory ? */
+ return entries;
+}
+
+/**
+ * mono_method_add_generic_virtual_invocation:
+ * @domain: a domain
+ * @vtable_slot: pointer to the vtable slot
+ * @method: the inflated generic virtual method
+ * @code: the method's code
+ *
+ * Registers a call via unmanaged code to a generic virtual method
+ * instantiation. If the number of calls reaches a threshold
+ * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
+ * virtual method thunk.
+ */
+void
+mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
+ gpointer *vtable_slot,
+ MonoMethod *method, gpointer code)
+{
+ static gboolean inited = FALSE;
+ static int num_added = 0;
+
+ GenericVirtualCase *gvc, *list;
+ MonoImtBuilderEntry *entries;
+ int i;
+ GPtrArray *sorted;
+
+ mono_domain_lock (domain);
+ if (!domain->generic_virtual_cases)
+ domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
+ /* Check whether the case was already added */
+ list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+ gvc = list;
+ while (gvc) {
+ if (gvc->method == method)
+ break;
+ gvc = gvc->next;
+ }
+
+ /* If not found, make a new one */
+ if (!gvc) {
+ gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
+ gvc->method = method;
+ gvc->code = code;
+ gvc->count = 0;
+ gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+
+ g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
+
+ if (!inited) {
+ mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
+ inited = TRUE;
+ }
+ num_added++;
+ }
+
+ if (++gvc->count == THUNK_THRESHOLD) {
+ gpointer *old_thunk = *vtable_slot;
+
+ if ((gpointer)vtable_slot < (gpointer)vtable)
+ /* Force the rebuild of the thunk at the next call */
+ *vtable_slot = imt_trampoline;
+ else {
+ entries = get_generic_virtual_entries (domain, vtable_slot);
+
+ sorted = imt_sort_slot_entries (entries);
+
+ *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
+ vtable_trampoline);
+
+ while (entries) {
+ MonoImtBuilderEntry *next = entries->next;
+ g_free (entries);
+ entries = next;
+ }
+
+ for (i = 0; i < sorted->len; ++i)
+ g_free (g_ptr_array_index (sorted, i));
+ g_ptr_array_free (sorted, TRUE);
+ }
+
+ if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
+ invalidate_generic_virtual_thunk (domain, old_thunk);
+ }
+
+ mono_domain_unlock (domain);
}
static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
*
* VTables are domain specific because we create domain specific code, and
* they contain the domain specific static class data.
+ * On failure, NULL is returned, and class->exception_type is set.
*/
MonoVTable *
mono_class_vtable (MonoDomain *domain, MonoClass *class)
runtime_info = class->runtime_info;
if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
return runtime_info->domain_vtables [domain->domain_id];
+ if (class->exception_type)
+ return NULL;
return mono_class_create_runtime_vtable (domain, class);
}
+/**
+ * mono_class_try_get_vtable:
+ * @domain: the application domain
+ * @class: the class to initialize
+ *
+ * This function tries to get the associated vtable from @class if
+ * it was already created.
+ */
+MonoVTable *
+mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
+{
+ MonoClassRuntimeInfo *runtime_info;
+
+ g_assert (class);
+
+ runtime_info = class->runtime_info;
+ if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
+ return runtime_info->domain_vtables [domain->domain_id];
+ return NULL;
+}
+
static MonoVTable *
mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
{
int imt_table_bytes = 0;
guint32 vtable_size, class_size;
guint32 cindex;
- guint32 constant_cols [MONO_CONSTANT_SIZE];
gpointer iter;
gpointer *interface_offsets;
+ mono_loader_lock (); /*FIXME mono_class_init acquires it*/
mono_domain_lock (domain);
runtime_info = class->runtime_info;
if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
mono_domain_unlock (domain);
+ mono_loader_unlock ();
return runtime_info->domain_vtables [domain->domain_id];
}
if (!class->inited || class->exception_type) {
if (!mono_class_init (class) || class->exception_type){
MonoException *exc;
mono_domain_unlock (domain);
+ mono_loader_unlock ();
exc = mono_class_get_exception_for_failure (class);
g_assert (exc);
mono_raise_exception (exc);
mono_class_init (class);
- /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
- if (class->image->dynamic)
- mono_class_setup_vtable (class);
-
/*
- * For szarrays, mono_class_init () already computed class->vtable_size, and that is
- * all that is needed because of the vtable trampolines.
+ * For some classes, mono_class_init () already computed class->vtable_size, and
+ * that is all that is needed because of the vtable trampolines.
*/
+ if (!class->vtable_size)
+ mono_class_setup_vtable (class);
+
+ if (class->exception_type) {
+ mono_domain_unlock (domain);
+ mono_loader_unlock ();
+ return NULL;
+ }
if (ARCH_USE_IMT) {
- vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
if (class->interface_offsets_count) {
imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
}
} else {
vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
}
mono_stats.used_class_count++;
mono_stats.class_vtable_size += vtable_size;
- interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
+ interface_offsets = mono_domain_alloc0 (domain, vtable_size);
if (ARCH_USE_IMT)
vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
* vtable is reachable by other roots after the appdomain is unloaded.
*/
#ifdef HAVE_BOEHM_GC
- if (domain != mono_get_root_domain ())
+ if (domain != mono_get_root_domain () && !mono_dont_free_domains)
vt->gc_descr = GC_NO_DESCRIPTOR;
else
#endif
bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
/*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
- statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
+ statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
mono_domain_add_class_static_data (domain, class, vt->data, NULL);
if (bitmap != default_bitmap)
g_free (bitmap);
} else {
- vt->data = mono_mempool_alloc0 (domain->mp, class_size);
+ vt->data = mono_domain_alloc0 (domain, class_size);
}
mono_stats.class_static_data_size += class_size;
}
if (!domain->special_static_fields)
domain->special_static_fields = g_hash_table_new (NULL, NULL);
g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
+ /*
+ * This marks the field as special static to speed up the
+ * checks in mono_field_static_get/set_value ().
+ */
+ field->offset = -1;
continue;
}
}
if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
MonoClass *fklass = mono_class_from_mono_type (field->type);
+ const char *data = mono_field_get_data (field);
+
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
t = (char*)vt->data + field->offset;
/* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
- if (!field->data)
+ if (!data)
continue;
if (fklass->valuetype) {
- memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+ memcpy (t, data, mono_class_value_size (fklass, NULL));
} else {
/* it's a pointer type: add check */
g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
- *t = *(char *)field->data;
+ *t = *(char *)data;
}
continue;
- }
- if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
- continue;
-
- /* later do this only on demand if needed */
- if (!field->data) {
- cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
- g_assert (cindex);
- g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
-
- mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
- field->def_type = constant_cols [MONO_CONSTANT_TYPE];
- field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
- }
-
+ }
}
vt->max_interface_id = class->max_interface_id;
/* class->runtime_info is protected by the loader lock, both when
* it it enlarged and when it is stored info.
*/
- mono_loader_lock ();
+
old_info = class->runtime_info;
if (old_info && old_info->max_domain >= domain->domain_id) {
/* someone already created a large enough runtime info */
/* this is a bounded memory retention issue: may want to
* handle it differently when we'll have a rcu-like system.
*/
- runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+ runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
runtime_info->max_domain = new_size - 1;
/* copy the stuff from the older info */
if (old_info) {
mono_memory_barrier ();
class->runtime_info = runtime_info;
}
- mono_loader_unlock ();
/* Initialize vtable */
if (vtable_trampoline) {
for (i = 0; i < class->vtable_size; ++i) {
MonoMethod *cm;
- if ((cm = class->vtable [i])) {
- if (mono_method_signature (cm)->generic_param_count)
- /* FIXME: Why is this needed ? */
- vt->vtable [i] = cm;
- else
- vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
- }
+ if ((cm = class->vtable [i]))
+ vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
}
}
}
mono_domain_unlock (domain);
+ mono_loader_unlock ();
/* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
mono_raise_exception (exc);
}
- /* make sure the the parent is initialized */
+ /* make sure the parent is initialized */
if (class->parent)
mono_class_vtable (domain, class->parent);
mono_stats.imt_number_of_tables++;
mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
} else {
vtsize = sizeof (gpointer) * (max_interface_id + 1) +
- sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+ MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
}
mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
- interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
+ interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
if (ARCH_USE_IMT)
pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
else
pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
- memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
+ memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
pvt->klass = mono_defaults.transparent_proxy_class;
/* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
MonoMethod *cm;
if ((cm = class->vtable [i]))
- pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
- ? cm : arch_create_remoting_trampoline (cm, target_type);
+ pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
else
pvt->vtable [i] = NULL;
}
gpointer iter = NULL;
while ((m = mono_class_get_methods (k, &iter)))
if (!pvt->vtable [m->slot])
- pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
+ pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
}
}
pvt->max_interface_id = max_interface_id;
- pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
+ pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
if (! ARCH_USE_IMT) {
/* initialize interface offsets */
iter = NULL;
j = 0;
while ((cm = mono_class_get_methods (interf, &iter)))
- pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
+ pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
slot += mono_class_num_methods (interf);
}
return pvt;
}
+/**
+ * mono_class_field_is_special_static:
+ *
+ * Returns whether @field is a thread/context static field.
+ */
+gboolean
+mono_class_field_is_special_static (MonoClassField *field)
+{
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+ return FALSE;
+ if (mono_field_is_deleted (field))
+ return FALSE;
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
+ if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
+ return TRUE;
+ }
+ return FALSE;
+}
+
/**
* mono_class_has_special_static_fields:
*
iter = NULL;
while ((field = mono_class_get_fields (klass, &iter))) {
- if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
- continue;
- if (mono_field_is_deleted (field))
- continue;
- if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
- if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
- return TRUE;
- }
+ g_assert (field->parent == klass);
+ if (mono_class_field_is_special_static (field))
+ return TRUE;
}
return FALSE;
/**
* copy_remote_class_key:
*
- * Make a copy of KEY in the mempool MP and return the copy.
+ * Make a copy of KEY in the domain and return the copy.
*/
static gpointer*
-copy_remote_class_key (MonoMemPool *mp, gpointer *key)
+copy_remote_class_key (MonoDomain *domain, gpointer *key)
{
int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
- gpointer *mp_key = mono_mempool_alloc (mp, key_size);
+ gpointer *mp_key = mono_domain_alloc (domain, key_size);
memcpy (mp_key, key, key_size);
return rc;
}
- mp_key = copy_remote_class_key (domain->mp, key);
+ mp_key = copy_remote_class_key (domain, key);
g_free (key);
key = mp_key;
if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
- rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
rc->interface_count = 1;
rc->interfaces [0] = proxy_class;
rc->proxy_class = mono_defaults.marshalbyrefobject_class;
} else {
- rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
rc->interface_count = 0;
rc->proxy_class = proxy_class;
}
rc->default_vtable = NULL;
rc->xdomain_vtable = NULL;
rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
+ mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
return rc;
}
- mp_key = copy_remote_class_key (domain->mp, key);
+ mp_key = copy_remote_class_key (domain, key);
g_free (key);
key = mp_key;
if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
int i,j;
- rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
rc->proxy_class = remote_class->proxy_class;
rc->interface_count = remote_class->interface_count + 1;
rc->interfaces [j] = extra_class;
} else {
// Replace the old class. The interface array is the same
- rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+ rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
rc->proxy_class = extra_class;
rc->interface_count = remote_class->interface_count;
if (rc->interface_count > 0)
gpointer
mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
{
+ mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
mono_domain_lock (domain);
if (rp->target_domain_id != -1) {
if (remote_class->xdomain_vtable == NULL)
remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
mono_domain_unlock (domain);
+ mono_loader_unlock ();
return remote_class->xdomain_vtable;
}
if (remote_class->default_vtable == NULL) {
}
mono_domain_unlock (domain);
+ mono_loader_unlock ();
return remote_class->default_vtable;
}
MonoRemoteClass *remote_class;
gboolean redo_vtable;
+ mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
mono_domain_lock (domain);
tproxy = (MonoTransparentProxy*) proxy_object;
}
mono_domain_unlock (domain);
+ mono_loader_unlock ();
}
mono_class_setup_vtable (klass);
vtable = klass->vtable;
- /* check method->slot is a valid index: perform isinstance? */
- if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- if (!is_proxy)
- res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
- } else {
- if (method->slot != -1) {
- res = vtable [method->slot];
+ if (method->slot == -1) {
+ /* method->slot might not be set for instances of generic methods */
+ if (method->is_inflated) {
+ g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
+ method->slot = ((MonoMethodInflated*)method)->declaring->slot;
} else {
- /* method->slot might not be set for instances of generic methods in the AOT case */
- if (method->is_inflated) {
- g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
- res = vtable [((MonoMethodInflated*)method)->declaring->slot];
- }
+ if (!is_proxy)
+ g_assert_not_reached ();
}
}
+ /* check method->slot is a valid index: perform isinstance? */
+ if (method->slot != -1) {
+ if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+ if (!is_proxy)
+ res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
+ } else {
+ res = vtable [method->slot];
+ }
+ }
+
if (is_proxy) {
/* It may be an interface, abstract class method or generic method */
if (!res || mono_method_signature (res)->generic_param_count)
/* generic methods demand invoke_with_check */
if (mono_method_signature (res)->generic_param_count)
res = mono_marshal_get_remoting_invoke_with_check (res);
- else
- res = mono_marshal_get_remoting_invoke (res);
+ else {
+#ifndef DISABLE_COM
+ if (klass == mono_defaults.com_object_class || klass->is_com_object)
+ res = mono_cominterop_get_invoke (res);
+ else
+#endif
+ res = mono_marshal_get_remoting_invoke (res);
+ }
} else {
- if (method->is_inflated && !res->is_inflated) {
+ if (method->is_inflated) {
/* Have to inflate the result */
res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
}
MonoObject*
mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
{
+ if (mono_runtime_get_no_exec ())
+ g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
+
return default_mono_runtime_invoke (method, obj, params, exc);
}
{
int t;
if (type->byref) {
+ /* object fields cannot be byref, so we don't need a
+ wbarrier here */
gpointer *p = (gpointer*)dest;
*p = value;
return;
case MONO_TYPE_VALUETYPE:
/* note that 't' and 'type->type' can be different */
if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
- t = type->data.klass->enum_basetype->type;
+ t = mono_class_enum_basetype (type->data.klass)->type;
goto handle_enum;
} else {
- int size;
- size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
- if (value == NULL)
+ MonoClass *class = mono_class_from_mono_type (type);
+ int size = mono_class_value_size (class, NULL);
+ if (value == NULL) {
memset (dest, 0, size);
- else
+ } else {
memcpy (dest, value, size);
+ mono_gc_wbarrier_value_copy (dest, value, size, class);
+ }
}
return;
case MONO_TYPE_GENERICINST:
g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
/* you cant set a constant! */
g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
-
- dest = (char*)vt->data + field->offset;
+
+ if (field->offset == -1) {
+ /* Special static */
+ gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+ dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+ } else {
+ dest = (char*)vt->data + field->offset;
+ }
set_value (field->type, dest, value, FALSE);
}
readr8 (p, (double*) value);
break;
case MONO_TYPE_STRING:
- *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
+ *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
break;
case MONO_TYPE_CLASS:
*(gpointer*) value = NULL;
static void
get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
{
- g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
- mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
+ MonoTypeEnum def_type;
+ const char* data;
+
+ data = mono_class_get_field_default_value (field, &def_type);
+ mono_get_constant_value_from_blob (domain, def_type, data, value);
}
/**
return;
}
- src = (char*)vt->data + field->offset;
+ if (field->offset == -1) {
+ /* Special static */
+ gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+ src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+ } else {
+ src = (char*)vt->data + field->offset;
+ }
set_value (field->type, value, src, TRUE);
}
{
MonoMethod *im;
+ /* This is called at runtime, so avoid the slower search in metadata */
+ mono_class_setup_methods (klass);
+
im = mono_class_get_method_from_name (klass, "Invoke", -1);
g_assert (im);
}
}
-static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
+static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
/**
* mono_runtime_unhandled_exception_policy_set:
if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
gboolean abort_process = (mono_thread_current () == main_thread) ||
- (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
+ (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
- if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
+ if (current_domain != root_domain && (mono_framework_version () >= 2)) {
current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
} else {
current_appdomain_delegate = NULL;
assembly = method->klass->image->assembly;
domain->entry_assembly = assembly;
- MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
+ /* Domains created from another domain already have application_base and configuration_file set */
+ if (domain->setup->application_base == NULL) {
+ MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
+ }
- str = g_strconcat (assembly->image->name, ".config", NULL);
- MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
- g_free (str);
+ if (domain->setup->configuration_file == NULL) {
+ str = g_strconcat (assembly->image->name, ".config", NULL);
+ MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
+ g_free (str);
+ mono_set_private_bin_path_from_config (domain);
+ }
}
cinfo = mono_custom_attrs_from_method (method);
}
if (has_stathread_attribute) {
thread->apartment_state = ThreadApartmentState_STA;
- } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
+ } else if (mono_framework_version () == 1) {
thread->apartment_state = ThreadApartmentState_Unknown;
} else {
thread->apartment_state = ThreadApartmentState_MTA;
{
MonoMethodSignature *sig = mono_method_signature (method);
gpointer *pa = NULL;
+ MonoObject *res;
int i;
+ gboolean has_byref_nullables = FALSE;
if (NULL != params) {
pa = alloca (sizeof (gpointer) * mono_array_length (params));
case MONO_TYPE_R8:
case MONO_TYPE_VALUETYPE:
if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
- if (t->byref)
- /* FIXME: */
- g_assert_not_reached ();
- /* The runtime invoke wrapper needs the original boxed vtype */
+ /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
pa [i] = mono_array_get (params, MonoObject*, i);
+ if (t->byref)
+ has_byref_nullables = TRUE;
} else {
/* MS seems to create the objects if a null is passed in */
if (!mono_array_get (params, MonoObject*, i))
else
t = &t->data.generic_class->container_class->byval_arg;
goto again;
+ case MONO_TYPE_PTR: {
+ MonoObject *arg;
+
+ /* The argument should be an IntPtr */
+ arg = mono_array_get (params, MonoObject*, i);
+ if (arg == NULL) {
+ pa [i] = NULL;
+ } else {
+ g_assert (arg->vtable->klass == mono_defaults.int_class);
+ pa [i] = ((MonoIntPtr*)arg)->m_value;
+ }
+ break;
+ }
default:
- g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+ g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
}
}
}
}
/* obj must be already unboxed if needed */
- return mono_runtime_invoke (method, obj, pa, exc);
+ res = mono_runtime_invoke (method, obj, pa, exc);
+
+ if (sig->ret->type == MONO_TYPE_PTR) {
+ MonoClass *pointer_class;
+ static MonoMethod *box_method;
+ void *box_args [2];
+ MonoObject *box_exc;
+
+ /*
+ * The runtime-invoke wrapper returns a boxed IntPtr, need to
+ * convert it to a Pointer object.
+ */
+ pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+ if (!box_method)
+ box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
+
+ g_assert (res->vtable->klass == mono_defaults.int_class);
+ box_args [0] = ((MonoIntPtr*)res)->m_value;
+ box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
+ res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
+ g_assert (!box_exc);
+ }
+
+ if (has_byref_nullables) {
+ /*
+ * The runtime invoke wrapper already converted byref nullables back,
+ * and stored them in pa, we just need to copy them back to the
+ * managed array.
+ */
+ for (i = 0; i < mono_array_length (params); i++) {
+ MonoType *t = sig->params [i];
+
+ if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
+ mono_array_setref (params, i, pa [i]);
+ }
+ }
+
+ return res;
}
}
/* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
o = mono_object_allocate (vtable->klass->instance_size, vtable);
}
- if (vtable->klass->has_finalize)
+ if (G_UNLIKELY (vtable->klass->has_finalize))
mono_object_register_finalizer (o);
- mono_profiler_allocation (o, vtable->klass);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation (o, vtable->klass);
return o;
}
{
*pass_size_in_words = FALSE;
+ if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
+ profile_allocs = FALSE;
+
if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
return mono_object_new_specific;
if (obj->vtable->klass->has_references)
mono_gc_wbarrier_object (o);
#endif
- mono_profiler_allocation (o, obj->vtable->klass);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation (o, obj->vtable->klass);
if (obj->vtable->klass->has_finalize)
mono_object_register_finalizer (o);
void
mono_array_full_copy (MonoArray *src, MonoArray *dest)
{
- int size;
+ mono_array_size_t size;
MonoClass *klass = src->obj.vtable->klass;
MONO_ARCH_SAVE_REGS;
#ifdef HAVE_SGEN_GC
if (klass->element_class->valuetype) {
if (klass->element_class->has_references)
- mono_value_copy_array (dest, 0, src, mono_array_length (src));
+ mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
else
memcpy (&dest->vector, &src->vector, size);
} else {
mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
{
MonoArray *o;
- guint32 size, i;
- guint32 *sizes;
+ mono_array_size_t size, i;
+ mono_array_size_t *sizes;
MonoClass *klass = array->obj.vtable->klass;
MONO_ARCH_SAVE_REGS;
#ifdef HAVE_SGEN_GC
if (klass->element_class->valuetype) {
if (klass->element_class->has_references)
- mono_value_copy_array (o, 0, array, mono_array_length (array));
+ mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
else
memcpy (&o->vector, &array->vector, size);
} else {
return o;
}
- sizes = alloca (klass->rank * sizeof(guint32) * 2);
+ sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
size = mono_array_element_size (klass);
for (i = 0; i < klass->rank; ++i) {
sizes [i] = array->bounds [i].length;
#ifdef HAVE_SGEN_GC
if (klass->element_class->valuetype) {
if (klass->element_class->has_references)
- mono_value_copy_array (o, 0, array, mono_array_length (array));
+ mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
else
memcpy (&o->vector, &array->vector, size);
} else {
}
/* helper macros to check for overflow when calculating the size of arrays */
+#ifdef MONO_BIG_ARRAYS
+#define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
+#define MYGUINT_MAX MYGUINT64_MAX
+#define CHECK_ADD_OVERFLOW_UN(a,b) \
+ (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
+#define CHECK_MUL_OVERFLOW_UN(a,b) \
+ (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
+ ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
+#else
#define MYGUINT32_MAX 4294967295U
+#define MYGUINT_MAX MYGUINT32_MAX
#define CHECK_ADD_OVERFLOW_UN(a,b) \
- (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
+ (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
#define CHECK_MUL_OVERFLOW_UN(a,b) \
- ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
- (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
+ (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
+ ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
+#endif
/**
* mono_array_new_full:
* lower bounds and type.
*/
MonoArray*
-mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
+mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
{
- guint32 byte_len, len, bounds_size;
+ mono_array_size_t byte_len, len, bounds_size;
MonoObject *o;
MonoArray *array;
MonoVTable *vtable;
/* A single dimensional array with a 0 lower bound is the same as an szarray */
if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
len = lengths [0];
- if ((int) len < 0)
+ if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
arith_overflow ();
bounds_size = 0;
} else {
bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
for (i = 0; i < array_class->rank; ++i) {
- if ((int) lengths [i] < 0)
+ if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
arith_overflow ();
if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
len *= lengths [i];
}
}
if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
byte_len *= len;
if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
byte_len += sizeof (MonoArray);
if (bounds_size) {
/* align */
if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
byte_len = (byte_len + 3) & ~3;
if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
byte_len += bounds_size;
}
/*
}
}
- mono_profiler_allocation (o, array_class);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation (o, array_class);
return array;
}
* This routine creates a new szarray with @n elements of type @eclass.
*/
MonoArray *
-mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
+mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
{
MonoClass *ac;
MONO_ARCH_SAVE_REGS;
ac = mono_array_class_get (eclass, 1);
- g_assert (ac != NULL);
+ g_assert (ac);
return mono_array_new_specific (mono_class_vtable (domain, ac), n);
}
* can be sure about the domain it operates in.
*/
MonoArray *
-mono_array_new_specific (MonoVTable *vtable, guint32 n)
+mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
{
MonoObject *o;
MonoArray *ao;
MONO_ARCH_SAVE_REGS;
- if ((int) n < 0)
+ if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
arith_overflow ();
+ return NULL;
+ }
elem_size = mono_array_element_size (vtable->klass);
- if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
byte_len = n * elem_size;
- if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
- mono_gc_out_of_memory (MYGUINT32_MAX);
+ if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
+ mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+ return NULL;
+ }
byte_len += sizeof (MonoArray);
if (!vtable->klass->has_references) {
o = mono_object_allocate_ptrfree (byte_len, vtable);
#if NEED_TO_ZERO_PTRFREE
+ ((MonoArray*)o)->bounds = NULL;
memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
#endif
} else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
}
ao = (MonoArray *)o;
- ao->bounds = NULL;
ao->max_length = n;
- mono_profiler_allocation (o, vtable->klass);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation (o, vtable->klass);
return ao;
}
#if NEED_TO_ZERO_PTRFREE
s->chars [len] = 0;
#endif
- mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
return s;
}
MonoString*
mono_string_new (MonoDomain *domain, const char *text)
{
- GError *error = NULL;
- MonoString *o = NULL;
- guint16 *ut;
- glong items_written;
- int l;
+ GError *error = NULL;
+ MonoString *o = NULL;
+ guint16 *ut;
+ glong items_written;
+ int l;
- l = strlen (text);
-
- ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
+ l = strlen (text);
+
+ ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
- if (!error)
- o = mono_string_new_utf16 (domain, ut, items_written);
- else
- g_error_free (error);
+ if (!error)
+ o = mono_string_new_utf16 (domain, ut, items_written);
+ else
+ g_error_free (error);
- g_free (ut);
+ g_free (ut);
+/*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
+#if 0
+ gunichar2 *str;
+ const gchar *end;
+ int len;
+ MonoString *o = NULL;
+ if (!g_utf8_validate (text, -1, &end))
+ return NULL;
+
+ len = g_utf8_strlen (text, -1);
+ o = mono_string_new_size (domain, len);
+ str = mono_string_chars (o);
+
+ while (text < end) {
+ *str++ = g_utf8_get_char (text);
+ text = g_utf8_next_char (text);
+ }
+#endif
return o;
}
MonoVTable *vtable;
g_assert (class->valuetype);
+ if (mono_class_is_nullable (class))
+ return mono_nullable_box (value, class);
vtable = mono_class_vtable (domain, class);
size = mono_class_instance_size (class);
res = mono_object_new_alloc_specific (vtable);
- mono_profiler_allocation (res, class);
+ if (G_UNLIKELY (profile_allocs))
+ mono_profiler_allocation (res, class);
size = size - sizeof (MonoObject);
* @src: source pointer
* @count: number of items
*
- * Copy @count valuetype items from @src to @dest. This function must be used
- * when @klass contains references fields.
+ * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
+ * This function must be used when @klass contains references fields.
* Overlap is handled.
*/
void
if (image->dynamic)
return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
else
- return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
+ return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
}
/**
- * mono_ldstr_metdata_sig
+ * mono_ldstr_metadata_sig
* @domain: the domain for the string
* @sig: the signature of a metadata string
*
* Returns: a MonoString for a string stored in the metadata
*/
static MonoString*
-mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
{
const char *str = sig;
MonoString *o, *interned;
return mono_string_new_utf16 (domain, data, len);
}
-/**
- * mono_string_to_utf8_mp:
- * @s: a System.String
- *
- * Same as mono_string_to_utf8, but allocate the string from a mempool.
- */
-char *
-mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+
+static char *
+mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
{
- char *r = mono_string_to_utf8 (s);
+ char *r;
char *mp_s;
int len;
+ if (!mp && !image)
+ return mono_string_to_utf8 (s);
+
+ r = mono_string_to_utf8 (s);
if (!r)
return NULL;
len = strlen (r) + 1;
- mp_s = mono_mempool_alloc (mp, len);
+ if (mp)
+ mp_s = mono_mempool_alloc (mp, len);
+ else
+ mp_s = mono_image_alloc (image, len);
+
memcpy (mp_s, r, len);
g_free (r);
return mp_s;
}
+/**
+ * mono_string_to_utf8_image:
+ * @s: a System.String
+ *
+ * Same as mono_string_to_utf8, but allocate the string from the image mempool.
+ */
+char *
+mono_string_to_utf8_image (MonoImage *image, MonoString *s)
+{
+ return mono_string_to_utf8_internal (NULL, image, s);
+}
+
+/**
+ * mono_string_to_utf8_mp:
+ * @s: a System.String
+ *
+ * Same as mono_string_to_utf8, but allocate the string from a mempool.
+ */
+char *
+mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+{
+ return mono_string_to_utf8_internal (mp, NULL, s);
+}
+
static void
default_ex_handler (MonoException *ex)
{
* will point into the next function in the executable, not this one.
*/
- if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
- MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
+ if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
+ MonoThread *thread = mono_thread_current ();
+ g_assert (ex->object.vtable->domain == mono_domain_get ());
+ MONO_OBJECT_SETREF (thread, abort_exc, ex);
+ }
ex_handler (ex);
}
}
}
+
+static MonoObject*
+mono_runtime_capture_context (MonoDomain *domain)
+{
+ RuntimeInvokeFunction runtime_invoke;
+
+ if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
+ MonoMethod *method = mono_get_context_capture_method ();
+ MonoMethod *wrapper;
+ if (!method)
+ return NULL;
+ wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
+ domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
+ domain->capture_context_method = mono_compile_method (method);
+ }
+
+ runtime_invoke = domain->capture_context_runtime_invoke;
+
+ return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+}
/**
* mono_async_result_new:
* @domain:domain where the object will be created.
mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
{
MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
- MonoMethod *method = mono_get_context_capture_method ();
-
+ MonoObject *context = mono_runtime_capture_context (domain);
/* we must capture the execution context from the original thread */
- if (method) {
- MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
+ if (context) {
+ MONO_OBJECT_SETREF (res, execution_context, context);
/* note: result may be null if the flow is suppressed */
}
MonoReflectionMethod *method,
MonoArray *out_args)
{
+ static MonoClass *object_array_klass;
+ static MonoClass *byte_array_klass;
+ static MonoClass *string_array_klass;
MonoMethodSignature *sig = mono_method_signature (method->method);
MonoString *name;
int i, j;
char **names;
guint8 arg_type;
+ if (!object_array_klass) {
+ MonoClass *klass;
+
+ klass = mono_array_class_get (mono_defaults.object_class, 1);
+ g_assert (klass);
+
+ mono_memory_barrier ();
+ object_array_klass = klass;
+
+ klass = mono_array_class_get (mono_defaults.byte_class, 1);
+ g_assert (klass);
+
+ mono_memory_barrier ();
+ byte_array_klass = klass;
+
+ klass = mono_array_class_get (mono_defaults.string_class, 1);
+ g_assert (klass);
+
+ mono_memory_barrier ();
+ string_array_klass = klass;
+ }
+
MONO_OBJECT_SETREF (this, method, method);
- MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
- MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
+ MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
+ MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
this->async_result = NULL;
this->call_type = CallType_Sync;
names = g_new (char *, sig->param_count);
mono_method_get_param_names (method->method, (const char **) names);
- MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
+ MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
for (i = 0; i < sig->param_count; i++) {
- name = mono_string_new (domain, names [i]);
- mono_array_setref (this->names, i, name);
+ name = mono_string_new (domain, names [i]);
+ mono_array_setref (this->names, i, name);
}
g_free (names);
for (i = 0, j = 0; i < sig->param_count; i++) {
-
if (sig->params [i]->byref) {
if (out_args) {
MonoObject* arg = mono_array_get (out_args, gpointer, j);
mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
MonoObject **exc, MonoArray **out_args)
{
+ static MonoClass *object_array_klass;
MonoDomain *domain;
MonoMethod *method;
MonoMethodSignature *sig;
outarg_count++;
}
+ if (!object_array_klass) {
+ MonoClass *klass;
+
+ klass = mono_array_class_get (mono_defaults.object_class, 1);
+ g_assert (klass);
+
+ mono_memory_barrier ();
+ object_array_klass = klass;
+ }
+
/* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
- *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
+ *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
*exc = NULL;
ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
* @this: pointer to an uninitialized delegate object
* @target: target object
* @addr: pointer to native code
+ * @method: method
*
- * This is used to initialize a delegate.
+ * Initialize a delegate and sets a specific method, not the one
+ * associated with addr. This is useful when sharing generic code.
+ * In that case addr will most probably not be associated with the
+ * correct instantiation of the method.
*/
void
-mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
+mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
{
- MonoDomain *domain = mono_domain_get ();
MonoDelegate *delegate = (MonoDelegate *)this;
- MonoMethod *method = NULL;
MonoClass *class;
- MonoJitInfo *ji;
g_assert (this);
g_assert (addr);
+ if (method)
+ delegate->method = method;
+
class = this->vtable->klass;
mono_stats.delegate_creations++;
- if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
- method = ji->method;
- delegate->method = method;
- }
-
if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
g_assert (method);
method = mono_marshal_get_remoting_invoke (method);
delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
}
+/**
+ * mono_delegate_ctor:
+ * @this: pointer to an uninitialized delegate object
+ * @target: target object
+ * @addr: pointer to native code
+ *
+ * This is used to initialize a delegate.
+ */
+void
+mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoJitInfo *ji;
+ MonoMethod *method = NULL;
+
+ g_assert (addr);
+
+ if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
+ method = ji->method;
+ g_assert (!method->klass->generic_container);
+ }
+
+ mono_delegate_ctor_with_method (this, target, addr, method);
+}
+
/**
* mono_method_call_message_new:
* @method: method to encapsulate
full_name = mono_type_get_full_name (klass);
mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+ mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
g_free (full_name);
mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
full_name = mono_type_get_full_name (klass);
mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+ mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
g_free (full_name);
mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
full_name = mono_type_get_full_name (klass);
mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+ mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
mono_array_setref (msg->args, 2, arg);
g_free (full_name);
full_name = mono_type_get_full_name (klass);
mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
- mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+ mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
mono_array_setref (msg->args, 2, arg);
g_free (full_name);
* mono_create_ftnptr:
*
* Given a function address, create a function descriptor for it.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
*/
gpointer
mono_create_ftnptr (MonoDomain *domain, gpointer addr)
{
-#ifdef __ia64__
- gpointer *desc;
-
- mono_domain_lock (domain);
- desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
- mono_domain_unlock (domain);
-
- desc [0] = addr;
- desc [1] = NULL;
-
- return desc;
-#elif defined(__ppc64__) || defined(__powerpc64__)
- gpointer *desc;
-
- mono_domain_lock (domain);
- desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
- mono_domain_unlock (domain);
-
- desc [0] = addr;
- desc [1] = NULL;
- desc [2] = NULL;
-
- return desc;
-#else
- return addr;
-#endif
+ return callbacks.create_ftnptr (domain, addr);
}
/*
* mono_get_addr_from_ftnptr:
*
* Given a pointer to a function descriptor, return the function address.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
*/
gpointer
mono_get_addr_from_ftnptr (gpointer descr)
{
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
- return *(gpointer*)descr;
-#else
- return descr;
-#endif
+ return callbacks.get_addr_from_ftnptr (descr);
}
#if 0