X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fobject.c;h=ee7ecb9e25ef4668d8f2f032e1933f91123af5af;hb=1f771d12ba9c7e4e50810b02d7cf1b466e7009d7;hp=978733b7d2a1309017653cb2f3a4587af5477f1a;hpb=ab76e98c8814fdfa0aea7a31bbabfda5b4e86300;p=mono.git diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 978733b7d2a..ee7ecb9e25e 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -5,9 +5,13 @@ * 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 +#ifdef HAVE_ALLOCA_H +#include +#endif #include #include #include @@ -35,6 +39,8 @@ #include "mono/metadata/mono-debug-debugger.h" #include #include +#include +#include "cominterop.h" #ifdef HAVE_BOEHM_GC #define NEED_TO_ZERO_PTRFREE 1 @@ -69,7 +75,7 @@ static void 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) @@ -136,6 +142,9 @@ static GHashTable *blocked_thread_hash; /* 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 @@ -214,7 +223,6 @@ get_type_init_exception_for_vtable (MonoVTable *vtable) return ex; } - /* * mono_runtime_class_init: * @vtable: vtable that needs to be initialized @@ -223,6 +231,18 @@ get_type_init_exception_for_vtable (MonoVTable *vtable) */ 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; @@ -233,7 +253,7 @@ mono_runtime_class_init (MonoVTable *vtable) MONO_ARCH_SAVE_REGS; if (vtable->initialized) - return; + return NULL; exc = NULL; klass = vtable->klass; @@ -242,7 +262,10 @@ mono_runtime_class_init (MonoVTable *vtable) mono_image_check_for_module_cctor (klass->image); if (klass->image->has_module_cctor) { MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1); - mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass)); + MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception); + if (!module_vtable) + return NULL; + mono_runtime_class_init (module_vtable); } } method = mono_class_get_cctor (klass); @@ -258,14 +281,15 @@ mono_runtime_class_init (MonoVTable *vtable) /* 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) { @@ -276,7 +300,9 @@ mono_runtime_class_init (MonoVTable *vtable) 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)); @@ -294,7 +320,7 @@ mono_runtime_class_init (MonoVTable *vtable) 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); @@ -302,7 +328,7 @@ mono_runtime_class_init (MonoVTable *vtable) 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 @@ -372,12 +398,15 @@ mono_runtime_class_init (MonoVTable *vtable) 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 @@ -406,7 +435,7 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user) } void -mono_release_type_locks (MonoThread *thread) +mono_release_type_locks (MonoInternalThread *thread) { mono_type_initialization_lock (); g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid)); @@ -428,7 +457,7 @@ default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sy } 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; @@ -451,6 +480,18 @@ static MonoImtThunkBuilder imt_thunk_builder = 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) { @@ -557,6 +598,8 @@ mono_runtime_free_method (MonoDomain *domain, MonoMethod *method) if (default_mono_free_method != NULL) default_mono_free_method (domain, method); + mono_method_clear_object (domain, method); + mono_free_method (method); } @@ -604,6 +647,10 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int if (field->type->byref) break; + if (static_fields && field->offset == -1) + /* special static */ + continue; + pos = field->offset / sizeof (gpointer); pos += offset; @@ -821,7 +868,7 @@ mono_string_alloc (int length) return mono_string_new_size (mono_domain_get (), length); } -static void +void mono_class_compute_gc_descriptor (MonoClass *class) { int max_set = 0; @@ -933,6 +980,22 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field) 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; \ @@ -953,17 +1016,22 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field) } guint32 -mono_method_get_imt_slot (MonoMethod *method) { +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; @@ -1030,10 +1098,10 @@ add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, gu /* 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; @@ -1075,7 +1143,7 @@ compare_imt_builder_entries (const void *p1, const void *p2) { 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 @@ -1087,8 +1155,9 @@ imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray * 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; @@ -1100,7 +1169,7 @@ imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray * 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); @@ -1133,36 +1202,50 @@ imt_sort_slot_entries (MonoImtBuilderEntry *entries) { } 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); @@ -1171,9 +1254,25 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* 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); } } @@ -1183,9 +1282,8 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* 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; @@ -1193,10 +1291,39 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* } 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 @@ -1219,7 +1346,7 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* MonoImtBuilderEntry* entry = imt_builder [i]; while (entry != NULL) { MonoImtBuilderEntry* next = entry->next; - free (entry); + g_free (entry); entry = next; } } @@ -1233,22 +1360,6 @@ build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, 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 @@ -1257,6 +1368,8 @@ mono_install_vtable_trampoline (gpointer tramp_code) * 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) @@ -1270,14 +1383,287 @@ 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 MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class); +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, gboolean raise_on_error); /** * mono_class_vtable: @@ -1290,20 +1676,62 @@ static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoCla */ MonoVTable * mono_class_vtable (MonoDomain *domain, MonoClass *class) +{ + return mono_class_vtable_full (domain, class, FALSE); +} + +/** + * mono_class_vtable_full: + * @domain: the application domain + * @class: the class to initialize + * @raise_on_error if an exception should be raised on failure or not + * + * VTables are domain specific because we create domain specific code, and + * they contain the domain specific static class data. + */ +MonoVTable * +mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error) { MonoClassRuntimeInfo *runtime_info; g_assert (class); + if (class->exception_type) { + if (raise_on_error) + mono_raise_exception (mono_class_get_exception_for_failure (class)); + return NULL; + } + /* this check can be inlined in jitted code, too */ 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 mono_class_create_runtime_vtable (domain, class); + return mono_class_create_runtime_vtable (domain, class, raise_on_error); +} + +/** + * 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) +mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error) { MonoVTable *vt; MonoClassRuntimeInfo *runtime_info, *old_info; @@ -1313,27 +1741,48 @@ 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; + if (!mono_class_init (class) || class->exception_type) { mono_domain_unlock (domain); - exc = mono_class_get_exception_for_failure (class); - g_assert (exc); - mono_raise_exception (exc); + mono_loader_unlock (); + if (raise_on_error) + mono_raise_exception (mono_class_get_exception_for_failure (class)); + return NULL; } } - mono_class_init (class); + /* Array types require that their element type be valid*/ + if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) { + MonoClass *element_class = class->element_class; + if (!element_class->inited) + mono_class_init (element_class); + + /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/ + if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size) + mono_class_setup_vtable (element_class); + + if (element_class->exception_type != MONO_EXCEPTION_NONE) { + /*Can happen if element_class only got bad after mono_class_setup_vtable*/ + if (class->exception_type == MONO_EXCEPTION_NONE) + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + mono_domain_unlock (domain); + mono_loader_unlock (); + if (raise_on_error) + mono_raise_exception (mono_class_get_exception_for_failure (class)); + return NULL; + } + } /* * For some classes, mono_class_init () already computed class->vtable_size, and @@ -1344,11 +1793,14 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) if (class->exception_type) { mono_domain_unlock (domain); + mono_loader_unlock (); + if (raise_on_error) + mono_raise_exception (mono_class_get_exception_for_failure (class)); 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); @@ -1357,12 +1809,12 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) } } 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); @@ -1401,13 +1853,13 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) 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; } @@ -1429,39 +1881,32 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) 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; @@ -1487,7 +1932,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) /* 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 */ @@ -1506,7 +1951,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) /* 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) { @@ -1517,7 +1962,6 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) mono_memory_barrier (); class->runtime_info = runtime_info; } - mono_loader_unlock (); /* Initialize vtable */ if (vtable_trampoline) { @@ -1531,13 +1975,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) 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); } } @@ -1553,18 +1992,18 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class) } 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)) { - MonoException *exc = mono_class_get_exception_for_failure (class); - g_assert (exc); - mono_raise_exception (exc); - } + if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error) + mono_raise_exception (mono_class_get_exception_for_failure (class)); /* make sure the parent is initialized */ + /*FIXME shouldn't this fail the current type?*/ if (class->parent) - mono_class_vtable (domain, class->parent); + mono_class_vtable_full (domain, class->parent, raise_on_error); + /*FIXME check for OOM*/ vt->type = mono_type_get_object (domain, &class->byval_arg); if (class->contextbound) vt->remote = 1; @@ -1595,6 +2034,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono gpointer *interface_offsets; vt = mono_class_vtable (domain, class); + g_assert (vt); /*FIXME property handle failure*/ max_interface_id = vt->max_interface_id; /* Calculate vtable space for extra interfaces */ @@ -1634,20 +2074,20 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono 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 */ @@ -1659,8 +2099,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono 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; } @@ -1672,12 +2111,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono 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 */ @@ -1711,7 +2150,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono 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); } @@ -1825,13 +2264,13 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class) /** * 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); @@ -1863,17 +2302,17 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_ 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; } @@ -1881,6 +2320,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_ 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); @@ -1905,13 +2345,13 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass 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; @@ -1926,7 +2366,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass 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) @@ -1945,11 +2385,13 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass 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) { @@ -1964,6 +2406,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon } mono_domain_unlock (domain); + mono_loader_unlock (); return remote_class->default_vtable; } @@ -1984,6 +2427,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla MonoRemoteClass *remote_class; gboolean redo_vtable; + mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/ mono_domain_lock (domain); tproxy = (MonoTransparentProxy*) proxy_object; @@ -2006,6 +2450,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla } mono_domain_unlock (domain); + mono_loader_unlock (); } @@ -2039,22 +2484,27 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) 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) @@ -2063,10 +2513,16 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) /* 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); } @@ -2123,6 +2579,9 @@ static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke; 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); } @@ -2188,6 +2647,8 @@ set_value (MonoType *type, void *dest, void *value, int deref_pointer) { 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; @@ -2255,15 +2716,15 @@ handle_enum: 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); + MonoClass *class = mono_class_from_mono_type (type); + int size = mono_class_value_size (class, NULL); if (value == NULL) memset (dest, 0, size); else - memcpy (dest, value, size); + mono_gc_wbarrier_value_copy (dest, value, 1, class); } return; case MONO_TYPE_GENERICINST: @@ -2316,8 +2777,14 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value) 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); } @@ -2413,6 +2880,12 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) { is_static = TRUE; vtable = mono_class_vtable (domain, field->parent); + if (!vtable) { + char *name = mono_type_get_full_name (field->parent); + g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name); + g_free (name); + return NULL; + } if (!vtable->initialized) mono_runtime_class_init (vtable); } @@ -2472,7 +2945,7 @@ mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const 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; @@ -2487,8 +2960,11 @@ mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const 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); } /** @@ -2518,8 +2994,14 @@ mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value) get_default_field_value (vt->domain, field, 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); } @@ -2590,10 +3072,14 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass) g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class); *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0; - if (value) - memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL)); - else + if (value) { + if (param_class->has_references) + mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class); + else + memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL)); + } else { memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL)); + } } /** @@ -2614,7 +3100,10 @@ mono_nullable_box (guint8 *buf, MonoClass *klass) if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) { MonoObject *o = mono_object_new (mono_domain_get (), param_class); - memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL)); + if (param_class->has_references) + mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class); + else + memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL)); return o; } else @@ -2632,6 +3121,9 @@ mono_get_delegate_invoke (MonoClass *klass) { 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); @@ -2810,6 +3302,130 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[], return result; } +static MonoObject* +serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc) +{ + static MonoMethod *serialize_method; + + void *params [1]; + MonoObject *array; + + if (!serialize_method) { + MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices"); + serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1); + } + + if (!serialize_method) { + *failure = TRUE; + return NULL; + } + + g_assert (!mono_object_class (obj)->marshalbyref); + + params [0] = obj; + *exc = NULL; + array = mono_runtime_invoke (serialize_method, NULL, params, exc); + if (*exc) + *failure = TRUE; + + return array; +} + +static MonoObject* +deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc) +{ + static MonoMethod *deserialize_method; + + void *params [1]; + MonoObject *result; + + if (!deserialize_method) { + MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices"); + deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1); + } + if (!deserialize_method) { + *failure = TRUE; + return NULL; + } + + params [0] = obj; + *exc = NULL; + result = mono_runtime_invoke (deserialize_method, NULL, params, exc); + if (*exc) + *failure = TRUE; + + return result; +} + +static MonoObject* +make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc) +{ + static MonoMethod *get_proxy_method; + + MonoDomain *domain = mono_domain_get (); + MonoRealProxy *real_proxy; + MonoReflectionType *reflection_type; + MonoTransparentProxy *transparent_proxy; + + if (!get_proxy_method) + get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0); + + g_assert (obj->vtable->klass->marshalbyref); + + real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class); + reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg); + + MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type); + MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj); + + *exc = NULL; + transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc); + if (*exc) + *failure = TRUE; + + return (MonoObject*) transparent_proxy; +} + +/** + * mono_object_xdomain_representation + * @obj: an object + * @target_domain: a domain + * @exc: pointer to a MonoObject* + * + * Creates a representation of obj in the domain target_domain. This + * is either a copy of obj arrived through via serialization and + * deserialization or a proxy, depending on whether the object is + * serializable or marshal by ref. obj must not be in target_domain. + * + * If the object cannot be represented in target_domain, NULL is + * returned and *exc is set to an appropriate exception. + */ +MonoObject* +mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc) +{ + MonoObject *deserialized = NULL; + gboolean failure = FALSE; + + *exc = NULL; + + if (mono_object_class (obj)->marshalbyref) { + deserialized = make_transparent_proxy (obj, &failure, exc); + } else { + MonoDomain *domain = mono_domain_get (); + MonoObject *serialized; + + mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE); + serialized = serialize_object (obj, &failure, exc); + mono_domain_set_internal_with_options (target_domain, FALSE); + if (!failure) + deserialized = deserialize_object (serialized, &failure, exc); + if (domain != target_domain) + mono_domain_set_internal_with_options (domain, FALSE); + } + + return deserialized; +} + /* Used in call_unhandled_exception_delegate */ static MonoObject * create_unhandled_exception_eventargs (MonoObject *exc) @@ -2843,11 +3459,38 @@ static void call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) { MonoObject *e = NULL; gpointer pa [2]; + MonoDomain *current_domain = mono_domain_get (); + + if (domain != current_domain) + mono_domain_set_internal_with_options (domain, FALSE); + + g_assert (domain == mono_object_domain (domain->domain)); + + if (mono_object_domain (exc) != domain) { + MonoObject *serialization_exc; + + exc = mono_object_xdomain_representation (exc, domain, &serialization_exc); + if (!exc) { + if (serialization_exc) { + MonoObject *dummy; + exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy); + g_assert (exc); + } else { + exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (), + "System.Runtime.Serialization", "SerializationException", + "Could not serialize unhandled exception."); + } + } + } + g_assert (mono_object_domain (exc) == domain); pa [0] = domain->domain; pa [1] = create_unhandled_exception_eventargs (exc); mono_runtime_delegate_invoke (delegate, pa, &e); - + + if (domain != current_domain) + mono_domain_set_internal_with_options (current_domain, FALSE); + if (e) { gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message); g_warning ("exception inside UnhandledException handler: %s\n", msg); @@ -2855,7 +3498,7 @@ call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, Mon } } -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: @@ -2908,10 +3551,10 @@ mono_unhandled_exception (MonoObject *exc) g_assert (field); 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); + gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) || + (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; @@ -2966,7 +3609,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc) int rval; MonoCustomAttrInfo* cinfo; gboolean has_stathread_attribute; - MonoThread* thread = mono_thread_current (); + MonoInternalThread* thread = mono_thread_internal_current (); g_assert (args); @@ -2979,11 +3622,17 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc) 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); @@ -2999,7 +3648,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc) } 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; @@ -3094,7 +3743,9 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params, { 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)); @@ -3119,11 +3770,10 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *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)) @@ -3162,8 +3812,21 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params, 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); } } } @@ -3208,7 +3871,44 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params, } /* 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; } } @@ -3271,12 +3971,19 @@ mono_object_allocate_spec (size_t size, MonoVTable *vtable) * looked up using @klass. This will not invoke any constructors, * so the consumer of this routine has to invoke any constructors on * its own to initialize the object. + * + * It returns NULL on failure. */ MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) { + MonoVTable *vtable; + MONO_ARCH_SAVE_REGS; - return mono_object_new_specific (mono_class_vtable (domain, klass)); + vtable = mono_class_vtable (domain, klass); + if (!vtable) + return NULL; + return mono_object_new_specific (vtable); } /** @@ -3458,17 +4165,17 @@ MonoObject * mono_object_clone (MonoObject *obj) { MonoObject *o; - int size; + int size = obj->vtable->klass->instance_size; - size = obj->vtable->klass->instance_size; o = mono_object_allocate (size, obj->vtable); - /* do not copy the sync state */ - memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject)); -#ifdef HAVE_SGEN_GC - if (obj->vtable->klass->has_references) - mono_gc_wbarrier_object (o); -#endif + if (obj->vtable->klass->has_references) { + mono_gc_wbarrier_object_copy (o, obj); + } else { + int size = obj->vtable->klass->instance_size; + /* do not copy the sync state */ + memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject)); + } if (G_UNLIKELY (profile_allocs)) mono_profiler_allocation (o, obj->vtable->klass); @@ -3500,7 +4207,7 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest) #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 { @@ -3537,7 +4244,7 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array) #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 { @@ -3560,7 +4267,7 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array) #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 { @@ -3590,7 +4297,7 @@ mono_array_clone (MonoArray *array) #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)) + (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))))) @@ -3604,6 +4311,24 @@ mono_array_clone (MonoArray *array) ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))))) #endif +gboolean +mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res) +{ + mono_array_size_t byte_len; + + byte_len = mono_array_element_size (class); + if (CHECK_MUL_OVERFLOW_UN (byte_len, len)) + return FALSE; + byte_len *= len; + if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) + return FALSE; + byte_len += sizeof (MonoArray); + + *res = byte_len; + + return TRUE; +} + /** * mono_array_new_full: * @domain: domain where the object is created @@ -3620,13 +4345,13 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size mono_array_size_t byte_len, len, bounds_size; MonoObject *o; MonoArray *array; + MonoArrayBounds *bounds; MonoVTable *vtable; int i; if (!array_class->inited) mono_class_init (array_class); - byte_len = mono_array_element_size (array_class); len = 1; /* A single dimensional array with a 0 lower bound is the same as an szarray */ @@ -3647,12 +4372,9 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size } } - if (CHECK_MUL_OVERFLOW_UN (byte_len, len)) + if (!mono_array_calc_byte_len (array_class, len, &byte_len)) 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 (MONO_ARRAY_MAX_SIZE); - byte_len += sizeof (MonoArray); + if (bounds_size) { /* align */ if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) @@ -3666,7 +4388,8 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size * Following three lines almost taken from mono_object_new (): * they need to be kept in sync. */ - vtable = mono_class_vtable (domain, array_class); + vtable = mono_class_vtable_full (domain, array_class, TRUE); +#ifndef HAVE_SGEN_GC if (!array_class->has_references) { o = mono_object_allocate_ptrfree (byte_len, vtable); #if NEED_TO_ZERO_PTRFREE @@ -3682,8 +4405,21 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size array->max_length = len; if (bounds_size) { - MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size); + bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size); array->bounds = bounds; + } +#else + if (bounds_size) + o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size); + else + o = mono_gc_alloc_vector (vtable, byte_len, len); + array = (MonoArray*)o; + mono_stats.new_object_count++; + + bounds = array->bounds; +#endif + + if (bounds_size) { for (i = 0; i < array_class->rank; ++i) { bounds [i].length = lengths [i]; if (lower_bounds) @@ -3715,7 +4451,7 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n) ac = mono_array_class_get (eclass, 1); g_assert (ac); - return mono_array_new_specific (mono_class_vtable (domain, ac), n); + return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n); } /** @@ -3731,7 +4467,7 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n) { MonoObject *o; MonoArray *ao; - guint32 byte_len, elem_size; + guint32 byte_len; MONO_ARCH_SAVE_REGS; @@ -3739,18 +4475,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n) 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 (MONO_ARRAY_MAX_SIZE); - return NULL; - } - byte_len = n * elem_size; - if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) { + + if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) { mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE); return NULL; } - byte_len += sizeof (MonoArray); +#ifndef HAVE_SGEN_GC if (!vtable->klass->has_references) { o = mono_object_allocate_ptrfree (byte_len, vtable); #if NEED_TO_ZERO_PTRFREE @@ -3766,6 +4496,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n) ao = (MonoArray *)o; ao->max_length = n; +#else + o = mono_gc_alloc_vector (vtable, byte_len, n); + ao = (MonoArray*)o; + mono_stats.new_object_count++; +#endif + if (G_UNLIKELY (profile_allocs)) mono_profiler_allocation (o, vtable->klass); @@ -3811,6 +4547,7 @@ mono_string_new_size (MonoDomain *domain, gint32 len) mono_gc_out_of_memory (-1); vtable = mono_class_vtable (domain, mono_defaults.string_class); + g_assert (vtable); s = mono_object_allocate_ptrfree (size, vtable); @@ -3860,23 +4597,41 @@ mono_string_new_len (MonoDomain *domain, const char *text, guint length) 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; } @@ -3918,6 +4673,8 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value) return mono_nullable_box (value, class); vtable = mono_class_vtable (domain, class); + if (!vtable) + return NULL; size = mono_class_instance_size (class); res = mono_object_new_alloc_specific (vtable); if (G_UNLIKELY (profile_allocs)) @@ -3926,9 +4683,9 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value) size = size - sizeof (MonoObject); #ifdef HAVE_SGEN_GC + g_assert (size == mono_class_value_size (class, NULL)); mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class); -#endif - +#else #if NO_UNALIGNED_ACCESS memcpy ((char *)res + sizeof (MonoObject), value, size); #else @@ -3948,6 +4705,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value) default: memcpy ((char *)res + sizeof (MonoObject), value, size); } +#endif #endif if (class->has_finalize) mono_object_register_finalizer (res); @@ -3966,9 +4724,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value) void mono_value_copy (gpointer dest, gpointer src, MonoClass *klass) { - int size = mono_class_value_size (klass, NULL); mono_gc_wbarrier_value_copy (dest, src, 1, klass); - memcpy (dest, src, size); } /* @@ -3978,8 +4734,8 @@ mono_value_copy (gpointer dest, gpointer src, MonoClass *klass) * @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 @@ -3987,8 +4743,8 @@ mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count) { int size = mono_array_element_size (dest->obj.vtable->klass); char *d = mono_array_addr_with_size (dest, size, dest_idx); + g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL)); mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class); - memmove (d, src, size * count); } /** @@ -4264,18 +5020,18 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx) 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; @@ -4398,24 +5154,27 @@ mono_string_from_utf16 (gunichar2 *data) 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); @@ -4423,6 +5182,30 @@ mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s) 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) { @@ -4462,8 +5245,11 @@ mono_raise_exception (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) { + MonoInternalThread *thread = mono_thread_internal_current (); + g_assert (ex->object.vtable->domain == mono_domain_get ()); + MONO_OBJECT_SETREF (thread, abort_exc, ex); + } ex_handler (ex); } @@ -4482,11 +5268,11 @@ mono_wait_handle_new (MonoDomain *domain, HANDLE handle) gpointer params [1]; static MonoMethod *handle_set; - res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class); + res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class); /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */ if (!handle_set) - handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set; + handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set; params [0] = &handle; mono_runtime_invoke (handle_set, res, params, NULL); @@ -4501,8 +5287,8 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle) static MonoClassField *f_safe_handle; if (!f_os_handle && !f_safe_handle) { - f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle"); - f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle"); + f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle"); + f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle"); } if (f_os_handle) { @@ -4516,6 +5302,26 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle) } } + +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. @@ -4531,11 +5337,10 @@ MonoAsyncResult * 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 */ } @@ -4794,7 +5599,7 @@ mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer a method = mono_marshal_get_remoting_invoke (method); delegate->method_ptr = mono_compile_method (method); MONO_OBJECT_SETREF (delegate, target, target); - } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) { + } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) { method = mono_marshal_get_unbox_wrapper (method); delegate->method_ptr = mono_compile_method (method); MONO_OBJECT_SETREF (delegate, target, target); @@ -4918,42 +5723,22 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr arg = mono_array_get (out_args, gpointer, j); type = pt->type; - switch (type) { - case MONO_TYPE_VOID: - g_assert_not_reached (); - break; - case MONO_TYPE_U1: - case MONO_TYPE_I1: - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_U2: - case MONO_TYPE_I2: - case MONO_TYPE_CHAR: - case MONO_TYPE_U4: - case MONO_TYPE_I4: - case MONO_TYPE_I8: - case MONO_TYPE_U8: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_VALUETYPE: { + g_assert (type != MONO_TYPE_VOID); + + if (MONO_TYPE_IS_REFERENCE (pt)) { + mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg); + } else { if (arg) { - size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL); - memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); - } - else { + MonoClass *class = ((MonoObject*)arg)->vtable->klass; + size = mono_class_value_size (class, NULL); + if (class->has_references) + mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class); + else + memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); + } else { size = mono_class_value_size (mono_class_from_mono_type (pt), NULL); memset (*((gpointer *)params [i]), 0, size); } - break; - } - case MONO_TYPE_STRING: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - case MONO_TYPE_OBJECT: - **((MonoObject ***)params [i]) = (MonoObject *)arg; - break; - default: - g_assert_not_reached (); } j++; @@ -5008,7 +5793,7 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel 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); @@ -5074,7 +5859,7 @@ mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField * 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); @@ -5139,7 +5924,7 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie 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); @@ -5189,7 +5974,7 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField 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); @@ -5202,53 +5987,24 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField * 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