2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
45 #define NEED_TO_ZERO_PTRFREE 1
46 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
47 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
48 #ifdef HAVE_GC_GCJ_MALLOC
49 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
62 #define NEED_TO_ZERO_PTRFREE 1
63 #define GC_NO_DESCRIPTOR (NULL)
64 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
65 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
66 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
70 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
71 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
74 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
77 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
79 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
80 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
81 static CRITICAL_SECTION ldstr_section;
83 static gboolean profile_allocs = TRUE;
86 mono_runtime_object_init (MonoObject *this)
88 MonoMethod *method = NULL;
89 MonoClass *klass = this->vtable->klass;
91 method = mono_class_get_method_from_name (klass, ".ctor", 0);
94 if (method->klass->valuetype)
95 this = mono_object_unbox (this);
96 mono_runtime_invoke (method, this, NULL, NULL);
99 /* The pseudo algorithm for type initialization from the spec
100 Note it doesn't say anything about domains - only threads.
102 2. If the type is initialized you are done.
103 2.1. If the type is not yet initialized, try to take an
105 2.2. If successful, record this thread as responsible for
106 initializing the type and proceed to step 2.3.
107 2.2.1. If not, see whether this thread or any thread
108 waiting for this thread to complete already holds the lock.
109 2.2.2. If so, return since blocking would create a deadlock. This thread
110 will now see an incompletely initialized state for the type,
111 but no deadlock will arise.
112 2.2.3 If not, block until the type is initialized then return.
113 2.3 Initialize the parent type and then all interfaces implemented
115 2.4 Execute the type initialization code for this type.
116 2.5 Mark the type as initialized, release the initialization lock,
117 awaken any threads waiting for this type to be initialized,
124 guint32 initializing_tid;
125 guint32 waiting_count;
127 CRITICAL_SECTION initialization_section;
128 } TypeInitializationLock;
130 /* for locking access to type_initialization_hash and blocked_thread_hash */
131 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
132 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
133 static CRITICAL_SECTION type_initialization_section;
135 /* from vtable to lock */
136 static GHashTable *type_initialization_hash;
138 /* from thread id to thread id being waited on */
139 static GHashTable *blocked_thread_hash;
142 static MonoThread *main_thread;
144 /* Functions supplied by the runtime */
145 static MonoRuntimeCallbacks callbacks;
148 * mono_thread_set_main:
149 * @thread: thread to set as the main thread
151 * This function can be used to instruct the runtime to treat @thread
152 * as the main thread, ie, the thread that would normally execute the Main()
153 * method. This basically means that at the end of @thread, the runtime will
154 * wait for the existing foreground threads to quit and other such details.
157 mono_thread_set_main (MonoThread *thread)
159 main_thread = thread;
163 mono_thread_get_main (void)
169 mono_type_initialization_init (void)
171 InitializeCriticalSection (&type_initialization_section);
172 type_initialization_hash = g_hash_table_new (NULL, NULL);
173 blocked_thread_hash = g_hash_table_new (NULL, NULL);
174 InitializeCriticalSection (&ldstr_section);
178 mono_type_initialization_cleanup (void)
181 /* This is causing race conditions with
182 * mono_release_type_locks
184 DeleteCriticalSection (&type_initialization_section);
186 DeleteCriticalSection (&ldstr_section);
190 * get_type_init_exception_for_vtable:
192 * Return the stored type initialization exception for VTABLE.
194 static MonoException*
195 get_type_init_exception_for_vtable (MonoVTable *vtable)
197 MonoDomain *domain = vtable->domain;
198 MonoClass *klass = vtable->klass;
202 g_assert (vtable->init_failed);
205 * If the initializing thread was rudely aborted, the exception is not stored
209 mono_domain_lock (domain);
210 if (domain->type_init_exception_hash)
211 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
212 mono_domain_unlock (domain);
215 if (klass->name_space && *klass->name_space)
216 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
218 full_name = g_strdup (klass->name);
219 ex = mono_get_exception_type_initialization (full_name, NULL);
226 * mono_runtime_class_init:
227 * @vtable: vtable that needs to be initialized
229 * This routine calls the class constructor for @vtable.
232 mono_runtime_class_init (MonoVTable *vtable)
234 mono_runtime_class_init_full (vtable, TRUE);
238 * mono_runtime_class_init_full:
239 * @vtable that neeeds to be initialized
240 * @raise_exception is TRUE, exceptions are raised intead of returned
244 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
247 MonoException *exc_to_throw;
248 MonoMethod *method = NULL;
254 if (vtable->initialized)
258 klass = vtable->klass;
260 if (!klass->image->checked_module_cctor) {
261 mono_image_check_for_module_cctor (klass->image);
262 if (klass->image->has_module_cctor) {
263 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
264 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
267 method = mono_class_get_cctor (klass);
270 MonoDomain *domain = vtable->domain;
271 TypeInitializationLock *lock;
272 guint32 tid = GetCurrentThreadId();
273 int do_initialization = 0;
274 MonoDomain *last_domain = NULL;
276 mono_type_initialization_lock ();
277 /* double check... */
278 if (vtable->initialized) {
279 mono_type_initialization_unlock ();
282 if (vtable->init_failed) {
283 mono_type_initialization_unlock ();
285 /* The type initialization already failed once, rethrow the same exception */
287 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
288 return get_type_init_exception_for_vtable (vtable);
290 lock = g_hash_table_lookup (type_initialization_hash, vtable);
292 /* This thread will get to do the initialization */
293 if (mono_domain_get () != domain) {
294 /* Transfer into the target domain */
295 last_domain = mono_domain_get ();
296 if (!mono_domain_set (domain, FALSE)) {
297 vtable->initialized = 1;
298 mono_type_initialization_unlock ();
300 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
301 return mono_get_exception_appdomain_unloaded ();
304 lock = g_malloc (sizeof(TypeInitializationLock));
305 InitializeCriticalSection (&lock->initialization_section);
306 lock->initializing_tid = tid;
307 lock->waiting_count = 1;
309 /* grab the vtable lock while this thread still owns type_initialization_section */
310 EnterCriticalSection (&lock->initialization_section);
311 g_hash_table_insert (type_initialization_hash, vtable, lock);
312 do_initialization = 1;
315 TypeInitializationLock *pending_lock;
317 if (lock->initializing_tid == tid || lock->done) {
318 mono_type_initialization_unlock ();
321 /* see if the thread doing the initialization is already blocked on this thread */
322 blocked = GUINT_TO_POINTER (lock->initializing_tid);
323 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
324 if (pending_lock->initializing_tid == tid) {
325 if (!pending_lock->done) {
326 mono_type_initialization_unlock ();
329 /* the thread doing the initialization is blocked on this thread,
330 but on a lock that has already been freed. It just hasn't got
335 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
337 ++lock->waiting_count;
338 /* record the fact that we are waiting on the initializing thread */
339 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
341 mono_type_initialization_unlock ();
343 if (do_initialization) {
344 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
346 /* If the initialization failed, mark the class as unusable. */
347 /* Avoid infinite loops */
349 (klass->image == mono_defaults.corlib &&
350 !strcmp (klass->name_space, "System") &&
351 !strcmp (klass->name, "TypeInitializationException")))) {
352 vtable->init_failed = 1;
354 if (klass->name_space && *klass->name_space)
355 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
357 full_name = g_strdup (klass->name);
358 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
362 * Store the exception object so it could be thrown on subsequent
365 mono_domain_lock (domain);
366 if (!domain->type_init_exception_hash)
367 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
368 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
369 mono_domain_unlock (domain);
373 mono_domain_set (last_domain, TRUE);
375 LeaveCriticalSection (&lock->initialization_section);
377 /* this just blocks until the initializing thread is done */
378 EnterCriticalSection (&lock->initialization_section);
379 LeaveCriticalSection (&lock->initialization_section);
382 mono_type_initialization_lock ();
383 if (lock->initializing_tid != tid)
384 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
385 --lock->waiting_count;
386 if (lock->waiting_count == 0) {
387 DeleteCriticalSection (&lock->initialization_section);
388 g_hash_table_remove (type_initialization_hash, vtable);
391 if (!vtable->init_failed)
392 vtable->initialized = 1;
393 mono_type_initialization_unlock ();
395 if (vtable->init_failed) {
396 /* Either we were the initializing thread or we waited for the initialization */
398 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
399 return get_type_init_exception_for_vtable (vtable);
402 vtable->initialized = 1;
409 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
411 MonoVTable *vtable = (MonoVTable*)key;
413 TypeInitializationLock *lock = (TypeInitializationLock*) value;
414 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
417 * Have to set this since it cannot be set by the normal code in
418 * mono_runtime_class_init (). In this case, the exception object is not stored,
419 * and get_type_init_exception_for_class () needs to be aware of this.
421 vtable->init_failed = 1;
422 LeaveCriticalSection (&lock->initialization_section);
423 --lock->waiting_count;
424 if (lock->waiting_count == 0) {
425 DeleteCriticalSection (&lock->initialization_section);
434 mono_release_type_locks (MonoThread *thread)
436 mono_type_initialization_lock ();
437 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
438 mono_type_initialization_unlock ();
442 default_trampoline (MonoMethod *method)
448 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
450 g_assert_not_reached ();
456 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
458 g_error ("remoting not installed");
463 default_delegate_trampoline (MonoClass *klass)
465 g_assert_not_reached ();
469 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
470 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
471 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
472 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
473 static MonoImtThunkBuilder imt_thunk_builder = NULL;
474 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
475 #if (MONO_IMT_SIZE > 32)
476 #error "MONO_IMT_SIZE cannot be larger than 32"
480 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
482 memcpy (&callbacks, cbs, sizeof (*cbs));
485 MonoRuntimeCallbacks*
486 mono_get_runtime_callbacks (void)
492 mono_install_trampoline (MonoTrampoline func)
494 arch_create_jit_trampoline = func? func: default_trampoline;
498 mono_install_jump_trampoline (MonoJumpTrampoline func)
500 arch_create_jump_trampoline = func? func: default_jump_trampoline;
504 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
506 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
510 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
512 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
516 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
517 imt_thunk_builder = func;
520 static MonoCompileFunc default_mono_compile_method = NULL;
523 * mono_install_compile_method:
524 * @func: function to install
526 * This is a VM internal routine
529 mono_install_compile_method (MonoCompileFunc func)
531 default_mono_compile_method = func;
535 * mono_compile_method:
536 * @method: The method to compile.
538 * This JIT-compiles the method, and returns the pointer to the native code
542 mono_compile_method (MonoMethod *method)
544 if (!default_mono_compile_method) {
545 g_error ("compile method called on uninitialized runtime");
548 return default_mono_compile_method (method);
552 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
554 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
558 mono_runtime_create_delegate_trampoline (MonoClass *klass)
560 return arch_create_delegate_trampoline (klass);
563 static MonoFreeMethodFunc default_mono_free_method = NULL;
566 * mono_install_free_method:
567 * @func: pointer to the MonoFreeMethodFunc used to release a method
569 * This is an internal VM routine, it is used for the engines to
570 * register a handler to release the resources associated with a method.
572 * Methods are freed when no more references to the delegate that holds
576 mono_install_free_method (MonoFreeMethodFunc func)
578 default_mono_free_method = func;
582 * mono_runtime_free_method:
583 * @domain; domain where the method is hosted
584 * @method: method to release
586 * This routine is invoked to free the resources associated with
587 * a method that has been JIT compiled. This is used to discard
588 * methods that were used only temporarily (for example, used in marshalling)
592 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
594 if (default_mono_free_method != NULL)
595 default_mono_free_method (domain, method);
597 mono_method_clear_object (domain, method);
599 mono_free_method (method);
603 * The vtables in the root appdomain are assumed to be reachable by other
604 * roots, and we don't use typed allocation in the other domains.
607 /* The sync block is no longer a GC pointer */
608 #define GC_HEADER_BITMAP (0)
610 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
613 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
615 MonoClassField *field;
621 max_size = mono_class_data_size (class) / sizeof (gpointer);
623 max_size = class->instance_size / sizeof (gpointer);
624 if (max_size >= size) {
625 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
628 for (p = class; p != NULL; p = p->parent) {
629 gpointer iter = NULL;
630 while ((field = mono_class_get_fields (p, &iter))) {
634 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
636 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
639 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
642 /* FIXME: should not happen, flag as type load error */
643 if (field->type->byref)
646 if (static_fields && field->offset == -1)
650 pos = field->offset / sizeof (gpointer);
653 type = mono_type_get_underlying_type (field->type);
654 switch (type->type) {
657 case MONO_TYPE_FNPTR:
659 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
664 if (class->image != mono_defaults.corlib)
667 case MONO_TYPE_STRING:
668 case MONO_TYPE_SZARRAY:
669 case MONO_TYPE_CLASS:
670 case MONO_TYPE_OBJECT:
671 case MONO_TYPE_ARRAY:
672 g_assert ((field->offset % sizeof(gpointer)) == 0);
674 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
675 *max_set = MAX (*max_set, pos);
677 case MONO_TYPE_GENERICINST:
678 if (!mono_type_generic_inst_is_valuetype (type)) {
679 g_assert ((field->offset % sizeof(gpointer)) == 0);
681 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
682 *max_set = MAX (*max_set, pos);
687 case MONO_TYPE_VALUETYPE: {
688 MonoClass *fclass = mono_class_from_mono_type (field->type);
689 if (fclass->has_references) {
690 /* remove the object header */
691 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
705 case MONO_TYPE_BOOLEAN:
709 g_assert_not_reached ();
721 * similar to the above, but sets the bits in the bitmap for any non-ref field
722 * and ignores static fields
725 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
727 MonoClassField *field;
732 max_size = class->instance_size / sizeof (gpointer);
733 if (max_size >= size) {
734 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
737 for (p = class; p != NULL; p = p->parent) {
738 gpointer iter = NULL;
739 while ((field = mono_class_get_fields (p, &iter))) {
742 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
744 /* FIXME: should not happen, flag as type load error */
745 if (field->type->byref)
748 pos = field->offset / sizeof (gpointer);
751 type = mono_type_get_underlying_type (field->type);
752 switch (type->type) {
753 #if SIZEOF_VOID_P == 8
757 case MONO_TYPE_FNPTR:
762 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
763 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
764 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
767 #if SIZEOF_VOID_P == 4
771 case MONO_TYPE_FNPTR:
776 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
777 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
778 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
784 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
785 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
786 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
789 case MONO_TYPE_BOOLEAN:
792 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
794 case MONO_TYPE_STRING:
795 case MONO_TYPE_SZARRAY:
796 case MONO_TYPE_CLASS:
797 case MONO_TYPE_OBJECT:
798 case MONO_TYPE_ARRAY:
800 case MONO_TYPE_GENERICINST:
801 if (!mono_type_generic_inst_is_valuetype (type)) {
806 case MONO_TYPE_VALUETYPE: {
807 MonoClass *fclass = mono_class_from_mono_type (field->type);
808 /* remove the object header */
809 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
813 g_assert_not_reached ();
822 * mono_class_insecure_overlapping:
823 * check if a class with explicit layout has references and non-references
824 * fields overlapping.
826 * Returns: TRUE if it is insecure to load the type.
829 mono_class_insecure_overlapping (MonoClass *klass)
833 gsize default_bitmap [4] = {0};
835 gsize default_nrbitmap [4] = {0};
836 int i, insecure = FALSE;
839 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
840 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
842 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
843 int idx = i % (sizeof (bitmap [0]) * 8);
844 if (bitmap [idx] & nrbitmap [idx]) {
849 if (bitmap != default_bitmap)
851 if (nrbitmap != default_nrbitmap)
854 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
862 mono_string_alloc (int length)
864 return mono_string_new_size (mono_domain_get (), length);
868 mono_class_compute_gc_descriptor (MonoClass *class)
872 gsize default_bitmap [4] = {0};
873 static gboolean gcj_inited = FALSE;
878 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
879 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
880 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
881 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
883 #ifdef HAVE_GC_GCJ_MALLOC
885 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
889 #ifdef GC_REDIRECT_TO_LOCAL
890 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
891 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
893 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
894 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
899 mono_loader_unlock ();
903 mono_class_init (class);
905 if (class->gc_descr_inited)
908 class->gc_descr_inited = TRUE;
909 class->gc_descr = GC_NO_DESCRIPTOR;
911 bitmap = default_bitmap;
912 if (class == mono_defaults.string_class) {
913 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
914 } else if (class->rank) {
915 mono_class_compute_gc_descriptor (class->element_class);
916 if (!class->element_class->valuetype) {
918 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
919 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
920 class->name_space, class->name);*/
922 /* remove the object header */
923 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
924 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
925 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
926 class->name_space, class->name);*/
927 if (bitmap != default_bitmap)
931 /*static int count = 0;
934 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
935 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
937 if (class->gc_descr == GC_NO_DESCRIPTOR)
938 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
940 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
941 if (bitmap != default_bitmap)
947 * field_is_special_static:
948 * @fklass: The MonoClass to look up.
949 * @field: The MonoClassField describing the field.
951 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
952 * SPECIAL_STATIC_NONE otherwise.
955 field_is_special_static (MonoClass *fklass, MonoClassField *field)
957 MonoCustomAttrInfo *ainfo;
959 ainfo = mono_custom_attrs_from_field (fklass, field);
962 for (i = 0; i < ainfo->num_attrs; ++i) {
963 MonoClass *klass = ainfo->attrs [i].ctor->klass;
964 if (klass->image == mono_defaults.corlib) {
965 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
966 mono_custom_attrs_free (ainfo);
967 return SPECIAL_STATIC_THREAD;
969 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
970 mono_custom_attrs_free (ainfo);
971 return SPECIAL_STATIC_CONTEXT;
975 mono_custom_attrs_free (ainfo);
976 return SPECIAL_STATIC_NONE;
979 static gpointer imt_trampoline = NULL;
982 mono_install_imt_trampoline (gpointer tramp_code)
984 imt_trampoline = tramp_code;
987 static gpointer vtable_trampoline = NULL;
990 mono_install_vtable_trampoline (gpointer tramp_code)
992 vtable_trampoline = tramp_code;
995 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
996 #define mix(a,b,c) { \
997 a -= c; a ^= rot(c, 4); c += b; \
998 b -= a; b ^= rot(a, 6); a += c; \
999 c -= b; c ^= rot(b, 8); b += a; \
1000 a -= c; a ^= rot(c,16); c += b; \
1001 b -= a; b ^= rot(a,19); a += c; \
1002 c -= b; c ^= rot(b, 4); b += a; \
1004 #define final(a,b,c) { \
1005 c ^= b; c -= rot(b,14); \
1006 a ^= c; a -= rot(c,11); \
1007 b ^= a; b -= rot(a,25); \
1008 c ^= b; c -= rot(b,16); \
1009 a ^= c; a -= rot(c,4); \
1010 b ^= a; b -= rot(a,14); \
1011 c ^= b; c -= rot(b,24); \
1015 mono_method_get_imt_slot (MonoMethod *method)
1017 MonoMethodSignature *sig;
1019 guint32 *hashes_start, *hashes;
1023 /* This can be used to stress tests the collision code */
1027 * We do this to simplify generic sharing. It will hurt
1028 * performance in cases where a class implements two different
1029 * instantiations of the same generic interface.
1030 * The code in build_imt_slots () depends on this.
1032 if (method->is_inflated)
1033 method = ((MonoMethodInflated*)method)->declaring;
1035 sig = mono_method_signature (method);
1036 hashes_count = sig->param_count + 4;
1037 hashes_start = malloc (hashes_count * sizeof (guint32));
1038 hashes = hashes_start;
1040 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1041 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1042 method->klass->name_space, method->klass->name, method->name);
1043 g_assert_not_reached ();
1046 /* Initialize hashes */
1047 hashes [0] = g_str_hash (method->klass->name);
1048 hashes [1] = g_str_hash (method->klass->name_space);
1049 hashes [2] = g_str_hash (method->name);
1050 hashes [3] = mono_metadata_type_hash (sig->ret);
1051 for (i = 0; i < sig->param_count; i++) {
1052 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1055 /* Setup internal state */
1056 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1058 /* Handle most of the hashes */
1059 while (hashes_count > 3) {
1068 /* Handle the last 3 hashes (all the case statements fall through) */
1069 switch (hashes_count) {
1070 case 3 : c += hashes [2];
1071 case 2 : b += hashes [1];
1072 case 1 : a += hashes [0];
1074 case 0: /* nothing left to add */
1078 free (hashes_start);
1079 /* Report the result */
1080 return c % MONO_IMT_SIZE;
1089 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1090 guint32 imt_slot = mono_method_get_imt_slot (method);
1091 MonoImtBuilderEntry *entry;
1093 if (slot_num >= 0 && imt_slot != slot_num) {
1094 /* we build just a single imt slot and this is not it */
1098 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1099 entry->key = method;
1100 entry->value.vtable_slot = vtable_slot;
1101 entry->next = imt_builder [imt_slot];
1102 if (imt_builder [imt_slot] != NULL) {
1103 entry->children = imt_builder [imt_slot]->children + 1;
1104 if (entry->children == 1) {
1105 mono_stats.imt_slots_with_collisions++;
1106 *imt_collisions_bitmap |= (1 << imt_slot);
1109 entry->children = 0;
1110 mono_stats.imt_used_slots++;
1112 imt_builder [imt_slot] = entry;
1114 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1115 method, method->klass->name_space, method->klass->name,
1116 method->name, imt_slot, vtable_slot, entry->children);
1122 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1124 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1128 e->method->klass->name_space,
1129 e->method->klass->name,
1132 printf (" * %s: NULL\n", message);
1138 compare_imt_builder_entries (const void *p1, const void *p2) {
1139 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1140 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1142 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1146 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1148 int count = end - start;
1149 int chunk_start = out_array->len;
1152 for (i = start; i < end; ++i) {
1153 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1154 item->key = sorted_array [i]->key;
1155 item->value = sorted_array [i]->value;
1156 item->has_target_code = sorted_array [i]->has_target_code;
1157 item->is_equals = TRUE;
1159 item->check_target_idx = out_array->len + 1;
1161 item->check_target_idx = 0;
1162 g_ptr_array_add (out_array, item);
1165 int middle = start + count / 2;
1166 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1168 item->key = sorted_array [middle]->key;
1169 item->is_equals = FALSE;
1170 g_ptr_array_add (out_array, item);
1171 imt_emit_ir (sorted_array, start, middle, out_array);
1172 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1178 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1179 int number_of_entries = entries->children + 1;
1180 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1181 GPtrArray *result = g_ptr_array_new ();
1182 MonoImtBuilderEntry *current_entry;
1185 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1186 sorted_array [i] = current_entry;
1188 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1190 /*for (i = 0; i < number_of_entries; i++) {
1191 print_imt_entry (" sorted array:", sorted_array [i], i);
1194 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1196 free (sorted_array);
1201 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1203 if (imt_builder_entry != NULL) {
1204 if (imt_builder_entry->children == 0 && !fail_tramp) {
1205 /* No collision, return the vtable slot contents */
1206 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1208 /* Collision, build the thunk */
1209 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1212 result = imt_thunk_builder (vtable, domain,
1213 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1214 for (i = 0; i < imt_ir->len; ++i)
1215 g_free (g_ptr_array_index (imt_ir, i));
1216 g_ptr_array_free (imt_ir, TRUE);
1228 static MonoImtBuilderEntry*
1229 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1232 * LOCKING: requires the loader and domain locks.
1236 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1240 guint32 imt_collisions_bitmap = 0;
1241 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1242 int method_count = 0;
1243 gboolean record_method_count_for_max_collisions = FALSE;
1244 gboolean has_generic_virtual = FALSE;
1247 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1249 for (i = 0; i < klass->interface_offsets_count; ++i) {
1250 MonoClass *iface = klass->interfaces_packed [i];
1251 int interface_offset = klass->interface_offsets_packed [i];
1252 int method_slot_in_interface;
1253 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1256 if (slot_num >= 0 && iface->is_inflated) {
1258 * The imt slot of the method is the same as for its declaring method,
1259 * see the comment in mono_method_get_imt_slot (), so we can
1260 * avoid inflating methods which will be discarded by
1261 * add_imt_builder_entry anyway.
1263 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1264 if (mono_method_get_imt_slot (method) != slot_num)
1267 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1268 if (method->is_generic) {
1269 has_generic_virtual = TRUE;
1272 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1275 if (extra_interfaces) {
1276 int interface_offset = klass->vtable_size;
1278 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1279 MonoClass* iface = list_item->data;
1280 int method_slot_in_interface;
1281 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1282 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1283 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1285 interface_offset += iface->method.count;
1288 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1289 /* overwrite the imt slot only if we're building all the entries or if
1290 * we're building this specific one
1292 if (slot_num < 0 || i == slot_num) {
1293 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1296 if (imt_builder [i]) {
1297 MonoImtBuilderEntry *entry;
1299 /* Link entries with imt_builder [i] */
1300 for (entry = entries; entry->next; entry = entry->next)
1302 entry->next = imt_builder [i];
1303 entries->children += imt_builder [i]->children + 1;
1305 imt_builder [i] = entries;
1308 if (has_generic_virtual) {
1310 * There might be collisions later when the the thunk is expanded.
1312 imt_collisions_bitmap |= (1 << i);
1315 * The IMT thunk might be called with an instance of one of the
1316 * generic virtual methods, so has to fallback to the IMT trampoline.
1318 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1320 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1324 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1326 if (imt_builder [i] != NULL) {
1327 int methods_in_slot = imt_builder [i]->children + 1;
1328 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1329 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1330 record_method_count_for_max_collisions = TRUE;
1332 method_count += methods_in_slot;
1336 mono_stats.imt_number_of_methods += method_count;
1337 if (record_method_count_for_max_collisions) {
1338 mono_stats.imt_method_count_when_max_collisions = method_count;
1341 for (i = 0; i < MONO_IMT_SIZE; i++) {
1342 MonoImtBuilderEntry* entry = imt_builder [i];
1343 while (entry != NULL) {
1344 MonoImtBuilderEntry* next = entry->next;
1350 /* we OR the bitmap since we may build just a single imt slot at a time */
1351 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1355 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1356 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1360 * mono_vtable_build_imt_slot:
1361 * @vtable: virtual object table struct
1362 * @imt_slot: slot in the IMT table
1364 * Fill the given @imt_slot in the IMT table of @vtable with
1365 * a trampoline or a thunk for the case of collisions.
1366 * This is part of the internal mono API.
1368 * LOCKING: Take the domain lock.
1371 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1373 gpointer *imt = (gpointer*)vtable;
1374 imt -= MONO_IMT_SIZE;
1375 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1377 /* no support for extra interfaces: the proxy objects will need
1378 * to build the complete IMT
1379 * Update and heck needs to ahppen inside the proper domain lock, as all
1380 * the changes made to a MonoVTable.
1382 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1383 mono_domain_lock (vtable->domain);
1384 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1385 if (imt [imt_slot] == imt_trampoline)
1386 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1387 mono_domain_unlock (vtable->domain);
1388 mono_loader_unlock ();
1393 * The first two free list entries both belong to the wait list: The
1394 * first entry is the pointer to the head of the list and the second
1395 * entry points to the last element. That way appending and removing
1396 * the first element are both O(1) operations.
1398 #define NUM_FREE_LISTS 12
1399 #define FIRST_FREE_LIST_SIZE 64
1400 #define MAX_WAIT_LENGTH 50
1401 #define THUNK_THRESHOLD 10
1404 * LOCKING: The domain lock must be held.
1407 init_thunk_free_lists (MonoDomain *domain)
1409 if (domain->thunk_free_lists)
1411 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1415 list_index_for_size (int item_size)
1418 int size = FIRST_FREE_LIST_SIZE;
1420 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1429 * mono_method_alloc_generic_virtual_thunk:
1431 * @size: size in bytes
1433 * Allocs size bytes to be used for the code of a generic virtual
1434 * thunk. It's either allocated from the domain's code manager or
1435 * reused from a previously invalidated piece.
1437 * LOCKING: The domain lock must be held.
1440 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1442 static gboolean inited = FALSE;
1443 static int generic_virtual_thunks_size = 0;
1447 MonoThunkFreeList **l;
1449 init_thunk_free_lists (domain);
1451 size += sizeof (guint32);
1452 if (size < sizeof (MonoThunkFreeList))
1453 size = sizeof (MonoThunkFreeList);
1455 i = list_index_for_size (size);
1456 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1457 if ((*l)->size >= size) {
1458 MonoThunkFreeList *item = *l;
1460 return ((guint32*)item) + 1;
1464 /* no suitable item found - search lists of larger sizes */
1465 while (++i < NUM_FREE_LISTS) {
1466 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1469 g_assert (item->size > size);
1470 domain->thunk_free_lists [i] = item->next;
1471 return ((guint32*)item) + 1;
1474 /* still nothing found - allocate it */
1476 mono_counters_register ("Generic virtual thunk bytes",
1477 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1480 generic_virtual_thunks_size += size;
1482 p = mono_domain_code_reserve (domain, size);
1489 * LOCKING: The domain lock must be held.
1492 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1495 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1497 init_thunk_free_lists (domain);
1499 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1500 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1501 int length = item->length;
1504 /* unlink the first item from the wait list */
1505 domain->thunk_free_lists [0] = item->next;
1506 domain->thunk_free_lists [0]->length = length - 1;
1508 i = list_index_for_size (item->size);
1510 /* put it in the free list */
1511 item->next = domain->thunk_free_lists [i];
1512 domain->thunk_free_lists [i] = item;
1516 if (domain->thunk_free_lists [1]) {
1517 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1518 domain->thunk_free_lists [0]->length++;
1520 g_assert (!domain->thunk_free_lists [0]);
1522 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1523 domain->thunk_free_lists [0]->length = 1;
1527 typedef struct _GenericVirtualCase {
1531 struct _GenericVirtualCase *next;
1532 } GenericVirtualCase;
1535 * get_generic_virtual_entries:
1537 * Return IMT entries for the generic virtual method instances for vtable slot
1540 static MonoImtBuilderEntry*
1541 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1543 GenericVirtualCase *list;
1544 MonoImtBuilderEntry *entries;
1546 mono_domain_lock (domain);
1547 if (!domain->generic_virtual_cases)
1548 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1550 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1553 for (; list; list = list->next) {
1554 MonoImtBuilderEntry *entry;
1556 if (list->count < THUNK_THRESHOLD)
1559 entry = g_new0 (MonoImtBuilderEntry, 1);
1560 entry->key = list->method;
1561 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1562 entry->has_target_code = 1;
1564 entry->children = entries->children + 1;
1565 entry->next = entries;
1569 mono_domain_unlock (domain);
1571 /* FIXME: Leaking memory ? */
1576 * mono_method_add_generic_virtual_invocation:
1578 * @vtable_slot: pointer to the vtable slot
1579 * @method: the inflated generic virtual method
1580 * @code: the method's code
1582 * Registers a call via unmanaged code to a generic virtual method
1583 * instantiation. If the number of calls reaches a threshold
1584 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1585 * virtual method thunk.
1588 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1589 gpointer *vtable_slot,
1590 MonoMethod *method, gpointer code)
1592 static gboolean inited = FALSE;
1593 static int num_added = 0;
1595 GenericVirtualCase *gvc, *list;
1596 MonoImtBuilderEntry *entries;
1600 mono_domain_lock (domain);
1601 if (!domain->generic_virtual_cases)
1602 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1604 /* Check whether the case was already added */
1605 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1608 if (gvc->method == method)
1613 /* If not found, make a new one */
1615 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1616 gvc->method = method;
1619 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1621 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1624 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1630 if (++gvc->count == THUNK_THRESHOLD) {
1631 gpointer *old_thunk = *vtable_slot;
1633 if ((gpointer)vtable_slot < (gpointer)vtable)
1634 /* Force the rebuild of the thunk at the next call */
1635 *vtable_slot = imt_trampoline;
1637 entries = get_generic_virtual_entries (domain, vtable_slot);
1639 sorted = imt_sort_slot_entries (entries);
1641 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1645 MonoImtBuilderEntry *next = entries->next;
1650 for (i = 0; i < sorted->len; ++i)
1651 g_free (g_ptr_array_index (sorted, i));
1652 g_ptr_array_free (sorted, TRUE);
1655 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1656 invalidate_generic_virtual_thunk (domain, old_thunk);
1659 mono_domain_unlock (domain);
1662 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1665 * mono_class_vtable:
1666 * @domain: the application domain
1667 * @class: the class to initialize
1669 * VTables are domain specific because we create domain specific code, and
1670 * they contain the domain specific static class data.
1671 * On failure, NULL is returned, and class->exception_type is set.
1674 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1676 MonoClassRuntimeInfo *runtime_info;
1680 /* this check can be inlined in jitted code, too */
1681 runtime_info = class->runtime_info;
1682 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1683 return runtime_info->domain_vtables [domain->domain_id];
1684 if (class->exception_type)
1686 return mono_class_create_runtime_vtable (domain, class);
1690 * mono_class_try_get_vtable:
1691 * @domain: the application domain
1692 * @class: the class to initialize
1694 * This function tries to get the associated vtable from @class if
1695 * it was already created.
1698 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1700 MonoClassRuntimeInfo *runtime_info;
1704 runtime_info = class->runtime_info;
1705 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1706 return runtime_info->domain_vtables [domain->domain_id];
1711 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1714 MonoClassRuntimeInfo *runtime_info, *old_info;
1715 MonoClassField *field;
1718 int imt_table_bytes = 0;
1719 guint32 vtable_size, class_size;
1722 gpointer *interface_offsets;
1724 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1725 mono_domain_lock (domain);
1726 runtime_info = class->runtime_info;
1727 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1728 mono_domain_unlock (domain);
1729 mono_loader_unlock ();
1730 return runtime_info->domain_vtables [domain->domain_id];
1732 if (!class->inited || class->exception_type) {
1733 if (!mono_class_init (class) || class->exception_type){
1735 mono_domain_unlock (domain);
1736 mono_loader_unlock ();
1737 exc = mono_class_get_exception_for_failure (class);
1739 mono_raise_exception (exc);
1743 mono_class_init (class);
1746 * For some classes, mono_class_init () already computed class->vtable_size, and
1747 * that is all that is needed because of the vtable trampolines.
1749 if (!class->vtable_size)
1750 mono_class_setup_vtable (class);
1752 if (class->exception_type) {
1753 mono_domain_unlock (domain);
1754 mono_loader_unlock ();
1759 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1760 if (class->interface_offsets_count) {
1761 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1762 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1763 mono_stats.imt_number_of_tables++;
1764 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1767 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1768 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1771 mono_stats.used_class_count++;
1772 mono_stats.class_vtable_size += vtable_size;
1773 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1776 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1778 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1780 vt->rank = class->rank;
1781 vt->domain = domain;
1783 mono_class_compute_gc_descriptor (class);
1785 * We can't use typed allocation in the non-root domains, since the
1786 * collector needs the GC descriptor stored in the vtable even after
1787 * the mempool containing the vtable is destroyed when the domain is
1788 * unloaded. An alternative might be to allocate vtables in the GC
1789 * heap, but this does not seem to work (it leads to crashes inside
1790 * libgc). If that approach is tried, two gc descriptors need to be
1791 * allocated for each class: one for the root domain, and one for all
1792 * other domains. The second descriptor should contain a bit for the
1793 * vtable field in MonoObject, since we can no longer assume the
1794 * vtable is reachable by other roots after the appdomain is unloaded.
1796 #ifdef HAVE_BOEHM_GC
1797 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1798 vt->gc_descr = GC_NO_DESCRIPTOR;
1801 vt->gc_descr = class->gc_descr;
1803 if ((class_size = mono_class_data_size (class))) {
1804 if (class->has_static_refs) {
1805 gpointer statics_gc_descr;
1807 gsize default_bitmap [4] = {0};
1810 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1811 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1812 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1813 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1814 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1815 if (bitmap != default_bitmap)
1818 vt->data = mono_domain_alloc0 (domain, class_size);
1820 mono_stats.class_static_data_size += class_size;
1825 while ((field = mono_class_get_fields (class, &iter))) {
1826 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1828 if (mono_field_is_deleted (field))
1830 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1831 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1832 if (special_static != SPECIAL_STATIC_NONE) {
1833 guint32 size, offset;
1835 size = mono_type_size (field->type, &align);
1836 offset = mono_alloc_special_static_data (special_static, size, align);
1837 if (!domain->special_static_fields)
1838 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1839 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1841 * This marks the field as special static to speed up the
1842 * checks in mono_field_static_get/set_value ().
1848 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1849 MonoClass *fklass = mono_class_from_mono_type (field->type);
1850 const char *data = mono_field_get_data (field);
1852 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1853 t = (char*)vt->data + field->offset;
1854 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1857 if (fklass->valuetype) {
1858 memcpy (t, data, mono_class_value_size (fklass, NULL));
1860 /* it's a pointer type: add check */
1861 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1868 vt->max_interface_id = class->max_interface_id;
1869 vt->interface_bitmap = class->interface_bitmap;
1871 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1872 // class->name, class->interface_offsets_count);
1874 if (! ARCH_USE_IMT) {
1875 /* initialize interface offsets */
1876 for (i = 0; i < class->interface_offsets_count; ++i) {
1877 int interface_id = class->interfaces_packed [i]->interface_id;
1878 int slot = class->interface_offsets_packed [i];
1879 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1883 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1884 * as we change the code in appdomain.c to invalidate vtables by
1885 * looking at the possible MonoClasses created for the domain.
1887 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1888 /* class->runtime_info is protected by the loader lock, both when
1889 * it it enlarged and when it is stored info.
1892 old_info = class->runtime_info;
1893 if (old_info && old_info->max_domain >= domain->domain_id) {
1894 /* someone already created a large enough runtime info */
1895 mono_memory_barrier ();
1896 old_info->domain_vtables [domain->domain_id] = vt;
1898 int new_size = domain->domain_id;
1900 new_size = MAX (new_size, old_info->max_domain);
1902 /* make the new size a power of two */
1904 while (new_size > i)
1907 /* this is a bounded memory retention issue: may want to
1908 * handle it differently when we'll have a rcu-like system.
1910 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1911 runtime_info->max_domain = new_size - 1;
1912 /* copy the stuff from the older info */
1914 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1916 runtime_info->domain_vtables [domain->domain_id] = vt;
1918 mono_memory_barrier ();
1919 class->runtime_info = runtime_info;
1922 /* Initialize vtable */
1923 if (vtable_trampoline) {
1924 // This also covers the AOT case
1925 for (i = 0; i < class->vtable_size; ++i) {
1926 vt->vtable [i] = vtable_trampoline;
1929 mono_class_setup_vtable (class);
1931 for (i = 0; i < class->vtable_size; ++i) {
1934 if ((cm = class->vtable [i]))
1935 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1939 if (ARCH_USE_IMT && imt_table_bytes) {
1940 /* Now that the vtable is full, we can actually fill up the IMT */
1941 if (imt_trampoline) {
1942 /* lazy construction of the IMT entries enabled */
1943 for (i = 0; i < MONO_IMT_SIZE; ++i)
1944 interface_offsets [i] = imt_trampoline;
1946 build_imt (class, vt, domain, interface_offsets, NULL);
1950 mono_domain_unlock (domain);
1951 mono_loader_unlock ();
1953 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1954 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1955 MonoException *exc = mono_class_get_exception_for_failure (class);
1957 mono_raise_exception (exc);
1960 /* make sure the parent is initialized */
1962 mono_class_vtable (domain, class->parent);
1964 vt->type = mono_type_get_object (domain, &class->byval_arg);
1965 if (class->contextbound)
1974 * mono_class_proxy_vtable:
1975 * @domain: the application domain
1976 * @remove_class: the remote class
1978 * Creates a vtable for transparent proxies. It is basically
1979 * a copy of the real vtable of the class wrapped in @remote_class,
1980 * but all function pointers invoke the remoting functions, and
1981 * vtable->klass points to the transparent proxy class, and not to @class.
1984 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1986 MonoVTable *vt, *pvt;
1987 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1989 GSList *extra_interfaces = NULL;
1990 MonoClass *class = remote_class->proxy_class;
1991 gpointer *interface_offsets;
1993 vt = mono_class_vtable (domain, class);
1994 max_interface_id = vt->max_interface_id;
1996 /* Calculate vtable space for extra interfaces */
1997 for (j = 0; j < remote_class->interface_count; j++) {
1998 MonoClass* iclass = remote_class->interfaces[j];
2002 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2003 continue; /* interface implemented by the class */
2004 if (g_slist_find (extra_interfaces, iclass))
2007 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2009 method_count = mono_class_num_methods (iclass);
2011 ifaces = mono_class_get_implemented_interfaces (iclass);
2013 for (i = 0; i < ifaces->len; ++i) {
2014 MonoClass *ic = g_ptr_array_index (ifaces, i);
2015 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2016 continue; /* interface implemented by the class */
2017 if (g_slist_find (extra_interfaces, ic))
2019 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2020 method_count += mono_class_num_methods (ic);
2022 g_ptr_array_free (ifaces, TRUE);
2025 extra_interface_vtsize += method_count * sizeof (gpointer);
2026 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2030 mono_stats.imt_number_of_tables++;
2031 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2032 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2033 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2035 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2036 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2039 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2041 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2043 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2045 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2046 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2048 pvt->klass = mono_defaults.transparent_proxy_class;
2049 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2050 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2052 /* initialize vtable */
2053 mono_class_setup_vtable (class);
2054 for (i = 0; i < class->vtable_size; ++i) {
2057 if ((cm = class->vtable [i]))
2058 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2060 pvt->vtable [i] = NULL;
2063 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2064 /* create trampolines for abstract methods */
2065 for (k = class; k; k = k->parent) {
2067 gpointer iter = NULL;
2068 while ((m = mono_class_get_methods (k, &iter)))
2069 if (!pvt->vtable [m->slot])
2070 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2074 pvt->max_interface_id = max_interface_id;
2075 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2077 if (! ARCH_USE_IMT) {
2078 /* initialize interface offsets */
2079 for (i = 0; i < class->interface_offsets_count; ++i) {
2080 int interface_id = class->interfaces_packed [i]->interface_id;
2081 int slot = class->interface_offsets_packed [i];
2082 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2085 for (i = 0; i < class->interface_offsets_count; ++i) {
2086 int interface_id = class->interfaces_packed [i]->interface_id;
2087 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2090 if (extra_interfaces) {
2091 int slot = class->vtable_size;
2097 /* Create trampolines for the methods of the interfaces */
2098 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2099 interf = list_item->data;
2101 if (! ARCH_USE_IMT) {
2102 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2104 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2108 while ((cm = mono_class_get_methods (interf, &iter)))
2109 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2111 slot += mono_class_num_methods (interf);
2113 if (! ARCH_USE_IMT) {
2114 g_slist_free (extra_interfaces);
2119 /* Now that the vtable is full, we can actually fill up the IMT */
2120 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2121 if (extra_interfaces) {
2122 g_slist_free (extra_interfaces);
2130 * mono_class_field_is_special_static:
2132 * Returns whether @field is a thread/context static field.
2135 mono_class_field_is_special_static (MonoClassField *field)
2137 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2139 if (mono_field_is_deleted (field))
2141 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2142 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2149 * mono_class_has_special_static_fields:
2151 * Returns whenever @klass has any thread/context static fields.
2154 mono_class_has_special_static_fields (MonoClass *klass)
2156 MonoClassField *field;
2160 while ((field = mono_class_get_fields (klass, &iter))) {
2161 g_assert (field->parent == klass);
2162 if (mono_class_field_is_special_static (field))
2170 * create_remote_class_key:
2171 * Creates an array of pointers that can be used as a hash key for a remote class.
2172 * The first element of the array is the number of pointers.
2175 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2180 if (remote_class == NULL) {
2181 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2182 key = g_malloc (sizeof(gpointer) * 3);
2183 key [0] = GINT_TO_POINTER (2);
2184 key [1] = mono_defaults.marshalbyrefobject_class;
2185 key [2] = extra_class;
2187 key = g_malloc (sizeof(gpointer) * 2);
2188 key [0] = GINT_TO_POINTER (1);
2189 key [1] = extra_class;
2192 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2193 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2194 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2195 key [1] = remote_class->proxy_class;
2197 // Keep the list of interfaces sorted
2198 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2199 if (extra_class && remote_class->interfaces [i] > extra_class) {
2200 key [j++] = extra_class;
2203 key [j] = remote_class->interfaces [i];
2206 key [j] = extra_class;
2208 // Replace the old class. The interface list is the same
2209 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2210 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2211 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2212 for (i = 0; i < remote_class->interface_count; i++)
2213 key [2 + i] = remote_class->interfaces [i];
2221 * copy_remote_class_key:
2223 * Make a copy of KEY in the domain and return the copy.
2226 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2228 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2229 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2231 memcpy (mp_key, key, key_size);
2237 * mono_remote_class:
2238 * @domain: the application domain
2239 * @class_name: name of the remote class
2241 * Creates and initializes a MonoRemoteClass object for a remote type.
2245 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2247 MonoRemoteClass *rc;
2248 gpointer* key, *mp_key;
2250 key = create_remote_class_key (NULL, proxy_class);
2252 mono_domain_lock (domain);
2253 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2257 mono_domain_unlock (domain);
2261 mp_key = copy_remote_class_key (domain, key);
2265 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2266 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2267 rc->interface_count = 1;
2268 rc->interfaces [0] = proxy_class;
2269 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2271 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2272 rc->interface_count = 0;
2273 rc->proxy_class = proxy_class;
2276 rc->default_vtable = NULL;
2277 rc->xdomain_vtable = NULL;
2278 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2279 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2281 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2283 mono_domain_unlock (domain);
2288 * clone_remote_class:
2289 * Creates a copy of the remote_class, adding the provided class or interface
2291 static MonoRemoteClass*
2292 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2294 MonoRemoteClass *rc;
2295 gpointer* key, *mp_key;
2297 key = create_remote_class_key (remote_class, extra_class);
2298 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2304 mp_key = copy_remote_class_key (domain, key);
2308 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2310 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2311 rc->proxy_class = remote_class->proxy_class;
2312 rc->interface_count = remote_class->interface_count + 1;
2314 // Keep the list of interfaces sorted, since the hash key of
2315 // the remote class depends on this
2316 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2317 if (remote_class->interfaces [i] > extra_class && i == j)
2318 rc->interfaces [j++] = extra_class;
2319 rc->interfaces [j] = remote_class->interfaces [i];
2322 rc->interfaces [j] = extra_class;
2324 // Replace the old class. The interface array is the same
2325 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2326 rc->proxy_class = extra_class;
2327 rc->interface_count = remote_class->interface_count;
2328 if (rc->interface_count > 0)
2329 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2332 rc->default_vtable = NULL;
2333 rc->xdomain_vtable = NULL;
2334 rc->proxy_class_name = remote_class->proxy_class_name;
2336 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2342 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2344 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2345 mono_domain_lock (domain);
2346 if (rp->target_domain_id != -1) {
2347 if (remote_class->xdomain_vtable == NULL)
2348 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2349 mono_domain_unlock (domain);
2350 mono_loader_unlock ();
2351 return remote_class->xdomain_vtable;
2353 if (remote_class->default_vtable == NULL) {
2356 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2357 klass = mono_class_from_mono_type (type);
2358 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2359 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2361 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2364 mono_domain_unlock (domain);
2365 mono_loader_unlock ();
2366 return remote_class->default_vtable;
2370 * mono_upgrade_remote_class:
2371 * @domain: the application domain
2372 * @tproxy: the proxy whose remote class has to be upgraded.
2373 * @klass: class to which the remote class can be casted.
2375 * Updates the vtable of the remote class by adding the necessary method slots
2376 * and interface offsets so it can be safely casted to klass. klass can be a
2377 * class or an interface.
2380 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2382 MonoTransparentProxy *tproxy;
2383 MonoRemoteClass *remote_class;
2384 gboolean redo_vtable;
2386 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2387 mono_domain_lock (domain);
2389 tproxy = (MonoTransparentProxy*) proxy_object;
2390 remote_class = tproxy->remote_class;
2392 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2395 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2396 if (remote_class->interfaces [i] == klass)
2397 redo_vtable = FALSE;
2400 redo_vtable = (remote_class->proxy_class != klass);
2404 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2405 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2408 mono_domain_unlock (domain);
2409 mono_loader_unlock ();
2414 * mono_object_get_virtual_method:
2415 * @obj: object to operate on.
2418 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2419 * the instance of a callvirt of method.
2422 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2425 MonoMethod **vtable;
2427 MonoMethod *res = NULL;
2429 klass = mono_object_class (obj);
2430 if (klass == mono_defaults.transparent_proxy_class) {
2431 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2437 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2440 mono_class_setup_vtable (klass);
2441 vtable = klass->vtable;
2443 if (method->slot == -1) {
2444 /* method->slot might not be set for instances of generic methods */
2445 if (method->is_inflated) {
2446 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2447 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2450 g_assert_not_reached ();
2454 /* check method->slot is a valid index: perform isinstance? */
2455 if (method->slot != -1) {
2456 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2458 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2460 res = vtable [method->slot];
2465 /* It may be an interface, abstract class method or generic method */
2466 if (!res || mono_method_signature (res)->generic_param_count)
2469 /* generic methods demand invoke_with_check */
2470 if (mono_method_signature (res)->generic_param_count)
2471 res = mono_marshal_get_remoting_invoke_with_check (res);
2473 res = mono_marshal_get_remoting_invoke (res);
2475 if (method->is_inflated) {
2476 /* Have to inflate the result */
2477 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2487 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2489 g_error ("runtime invoke called on uninitialized runtime");
2493 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2496 * mono_runtime_invoke:
2497 * @method: method to invoke
2498 * @obJ: object instance
2499 * @params: arguments to the method
2500 * @exc: exception information.
2502 * Invokes the method represented by @method on the object @obj.
2504 * obj is the 'this' pointer, it should be NULL for static
2505 * methods, a MonoObject* for object instances and a pointer to
2506 * the value type for value types.
2508 * The params array contains the arguments to the method with the
2509 * same convention: MonoObject* pointers for object instances and
2510 * pointers to the value type otherwise.
2512 * From unmanaged code you'll usually use the
2513 * mono_runtime_invoke() variant.
2515 * Note that this function doesn't handle virtual methods for
2516 * you, it will exec the exact method you pass: we still need to
2517 * expose a function to lookup the derived class implementation
2518 * of a virtual method (there are examples of this in the code,
2521 * You can pass NULL as the exc argument if you don't want to
2522 * catch exceptions, otherwise, *exc will be set to the exception
2523 * thrown, if any. if an exception is thrown, you can't use the
2524 * MonoObject* result from the function.
2526 * If the method returns a value type, it is boxed in an object
2530 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2532 if (mono_runtime_get_no_exec ())
2533 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2535 return default_mono_runtime_invoke (method, obj, params, exc);
2539 * mono_method_get_unmanaged_thunk:
2540 * @method: method to generate a thunk for.
2542 * Returns an unmanaged->managed thunk that can be used to call
2543 * a managed method directly from C.
2545 * The thunk's C signature closely matches the managed signature:
2547 * C#: public bool Equals (object obj);
2548 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2549 * MonoObject*, MonoException**);
2551 * The 1st ("this") parameter must not be used with static methods:
2553 * C#: public static bool ReferenceEquals (object a, object b);
2554 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2557 * The last argument must be a non-null pointer of a MonoException* pointer.
2558 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2559 * exception has been thrown in managed code. Otherwise it will point
2560 * to the MonoException* caught by the thunk. In this case, the result of
2561 * the thunk is undefined:
2563 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2564 * MonoException *ex = NULL;
2565 * Equals func = mono_method_get_unmanaged_thunk (method);
2566 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2568 * // handle exception
2571 * The calling convention of the thunk matches the platform's default
2572 * convention. This means that under Windows, C declarations must
2573 * contain the __stdcall attribute:
2575 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2576 * MonoObject*, MonoException**);
2580 * Value type arguments and return values are treated as they were objects:
2582 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2583 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2585 * Arguments must be properly boxed upon trunk's invocation, while return
2586 * values must be unboxed.
2589 mono_method_get_unmanaged_thunk (MonoMethod *method)
2591 method = mono_marshal_get_thunk_invoke_wrapper (method);
2592 return mono_compile_method (method);
2596 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2600 /* object fields cannot be byref, so we don't need a
2602 gpointer *p = (gpointer*)dest;
2609 case MONO_TYPE_BOOLEAN:
2611 case MONO_TYPE_U1: {
2612 guint8 *p = (guint8*)dest;
2613 *p = value ? *(guint8*)value : 0;
2618 case MONO_TYPE_CHAR: {
2619 guint16 *p = (guint16*)dest;
2620 *p = value ? *(guint16*)value : 0;
2623 #if SIZEOF_VOID_P == 4
2628 case MONO_TYPE_U4: {
2629 gint32 *p = (gint32*)dest;
2630 *p = value ? *(gint32*)value : 0;
2633 #if SIZEOF_VOID_P == 8
2638 case MONO_TYPE_U8: {
2639 gint64 *p = (gint64*)dest;
2640 *p = value ? *(gint64*)value : 0;
2643 case MONO_TYPE_R4: {
2644 float *p = (float*)dest;
2645 *p = value ? *(float*)value : 0;
2648 case MONO_TYPE_R8: {
2649 double *p = (double*)dest;
2650 *p = value ? *(double*)value : 0;
2653 case MONO_TYPE_STRING:
2654 case MONO_TYPE_SZARRAY:
2655 case MONO_TYPE_CLASS:
2656 case MONO_TYPE_OBJECT:
2657 case MONO_TYPE_ARRAY:
2658 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2660 case MONO_TYPE_FNPTR:
2661 case MONO_TYPE_PTR: {
2662 gpointer *p = (gpointer*)dest;
2663 *p = deref_pointer? *(gpointer*)value: value;
2666 case MONO_TYPE_VALUETYPE:
2667 /* note that 't' and 'type->type' can be different */
2668 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2669 t = mono_class_enum_basetype (type->data.klass)->type;
2672 MonoClass *class = mono_class_from_mono_type (type);
2673 int size = mono_class_value_size (class, NULL);
2674 if (value == NULL) {
2675 memset (dest, 0, size);
2677 memcpy (dest, value, size);
2678 mono_gc_wbarrier_value_copy (dest, value, size, class);
2682 case MONO_TYPE_GENERICINST:
2683 t = type->data.generic_class->container_class->byval_arg.type;
2686 g_warning ("got type %x", type->type);
2687 g_assert_not_reached ();
2692 * mono_field_set_value:
2693 * @obj: Instance object
2694 * @field: MonoClassField describing the field to set
2695 * @value: The value to be set
2697 * Sets the value of the field described by @field in the object instance @obj
2698 * to the value passed in @value. This method should only be used for instance
2699 * fields. For static fields, use mono_field_static_set_value.
2701 * The value must be on the native format of the field type.
2704 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2708 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2710 dest = (char*)obj + field->offset;
2711 set_value (field->type, dest, value, FALSE);
2715 * mono_field_static_set_value:
2716 * @field: MonoClassField describing the field to set
2717 * @value: The value to be set
2719 * Sets the value of the static field described by @field
2720 * to the value passed in @value.
2722 * The value must be on the native format of the field type.
2725 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2729 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2730 /* you cant set a constant! */
2731 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2733 if (field->offset == -1) {
2734 /* Special static */
2735 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2736 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2738 dest = (char*)vt->data + field->offset;
2740 set_value (field->type, dest, value, FALSE);
2743 /* Used by the debugger */
2745 mono_vtable_get_static_field_data (MonoVTable *vt)
2751 * mono_field_get_value:
2752 * @obj: Object instance
2753 * @field: MonoClassField describing the field to fetch information from
2754 * @value: pointer to the location where the value will be stored
2756 * Use this routine to get the value of the field @field in the object
2759 * The pointer provided by value must be of the field type, for reference
2760 * types this is a MonoObject*, for value types its the actual pointer to
2765 * mono_field_get_value (obj, int_field, &i);
2768 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2772 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2774 src = (char*)obj + field->offset;
2775 set_value (field->type, value, src, TRUE);
2779 * mono_field_get_value_object:
2780 * @domain: domain where the object will be created (if boxing)
2781 * @field: MonoClassField describing the field to fetch information from
2782 * @obj: The object instance for the field.
2784 * Returns: a new MonoObject with the value from the given field. If the
2785 * field represents a value type, the value is boxed.
2789 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2793 MonoVTable *vtable = NULL;
2795 gboolean is_static = FALSE;
2796 gboolean is_ref = FALSE;
2798 switch (field->type->type) {
2799 case MONO_TYPE_STRING:
2800 case MONO_TYPE_OBJECT:
2801 case MONO_TYPE_CLASS:
2802 case MONO_TYPE_ARRAY:
2803 case MONO_TYPE_SZARRAY:
2808 case MONO_TYPE_BOOLEAN:
2811 case MONO_TYPE_CHAR:
2820 case MONO_TYPE_VALUETYPE:
2821 is_ref = field->type->byref;
2823 case MONO_TYPE_GENERICINST:
2824 is_ref = !field->type->data.generic_class->container_class->valuetype;
2827 g_error ("type 0x%x not handled in "
2828 "mono_field_get_value_object", field->type->type);
2832 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2834 vtable = mono_class_vtable (domain, field->parent);
2835 if (!vtable->initialized)
2836 mono_runtime_class_init (vtable);
2841 mono_field_static_get_value (vtable, field, &o);
2843 mono_field_get_value (obj, field, &o);
2848 /* boxed value type */
2849 klass = mono_class_from_mono_type (field->type);
2850 o = mono_object_new (domain, klass);
2851 v = ((gchar *) o) + sizeof (MonoObject);
2853 mono_field_static_get_value (vtable, field, v);
2855 mono_field_get_value (obj, field, v);
2862 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2865 const char *p = blob;
2866 mono_metadata_decode_blob_size (p, &p);
2869 case MONO_TYPE_BOOLEAN:
2872 *(guint8 *) value = *p;
2874 case MONO_TYPE_CHAR:
2877 *(guint16*) value = read16 (p);
2881 *(guint32*) value = read32 (p);
2885 *(guint64*) value = read64 (p);
2888 readr4 (p, (float*) value);
2891 readr8 (p, (double*) value);
2893 case MONO_TYPE_STRING:
2894 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2896 case MONO_TYPE_CLASS:
2897 *(gpointer*) value = NULL;
2901 g_warning ("type 0x%02x should not be in constant table", type);
2907 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2909 MonoTypeEnum def_type;
2912 data = mono_class_get_field_default_value (field, &def_type);
2913 mono_get_constant_value_from_blob (domain, def_type, data, value);
2917 * mono_field_static_get_value:
2918 * @vt: vtable to the object
2919 * @field: MonoClassField describing the field to fetch information from
2920 * @value: where the value is returned
2922 * Use this routine to get the value of the static field @field value.
2924 * The pointer provided by value must be of the field type, for reference
2925 * types this is a MonoObject*, for value types its the actual pointer to
2930 * mono_field_static_get_value (vt, int_field, &i);
2933 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2937 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2939 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2940 get_default_field_value (vt->domain, field, value);
2944 if (field->offset == -1) {
2945 /* Special static */
2946 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2947 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2949 src = (char*)vt->data + field->offset;
2951 set_value (field->type, value, src, TRUE);
2955 * mono_property_set_value:
2956 * @prop: MonoProperty to set
2957 * @obj: instance object on which to act
2958 * @params: parameters to pass to the propery
2959 * @exc: optional exception
2961 * Invokes the property's set method with the given arguments on the
2962 * object instance obj (or NULL for static properties).
2964 * You can pass NULL as the exc argument if you don't want to
2965 * catch exceptions, otherwise, *exc will be set to the exception
2966 * thrown, if any. if an exception is thrown, you can't use the
2967 * MonoObject* result from the function.
2970 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2972 default_mono_runtime_invoke (prop->set, obj, params, exc);
2976 * mono_property_get_value:
2977 * @prop: MonoProperty to fetch
2978 * @obj: instance object on which to act
2979 * @params: parameters to pass to the propery
2980 * @exc: optional exception
2982 * Invokes the property's get method with the given arguments on the
2983 * object instance obj (or NULL for static properties).
2985 * You can pass NULL as the exc argument if you don't want to
2986 * catch exceptions, otherwise, *exc will be set to the exception
2987 * thrown, if any. if an exception is thrown, you can't use the
2988 * MonoObject* result from the function.
2990 * Returns: the value from invoking the get method on the property.
2993 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2995 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2999 * mono_nullable_init:
3000 * @buf: The nullable structure to initialize.
3001 * @value: the value to initialize from
3002 * @klass: the type for the object
3004 * Initialize the nullable structure pointed to by @buf from @value which
3005 * should be a boxed value type. The size of @buf should be able to hold
3006 * as much data as the @klass->instance_size (which is the number of bytes
3007 * that will be copies).
3009 * Since Nullables have variable structure, we can not define a C
3010 * structure for them.
3013 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3015 MonoClass *param_class = klass->cast_class;
3017 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3018 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3020 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3022 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3024 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3028 * mono_nullable_box:
3029 * @buf: The buffer representing the data to be boxed
3030 * @klass: the type to box it as.
3032 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3036 mono_nullable_box (guint8 *buf, MonoClass *klass)
3038 MonoClass *param_class = klass->cast_class;
3040 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3041 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3043 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3044 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3045 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3053 * mono_get_delegate_invoke:
3054 * @klass: The delegate class
3056 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3059 mono_get_delegate_invoke (MonoClass *klass)
3063 /* This is called at runtime, so avoid the slower search in metadata */
3064 mono_class_setup_methods (klass);
3066 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3073 * mono_runtime_delegate_invoke:
3074 * @delegate: pointer to a delegate object.
3075 * @params: parameters for the delegate.
3076 * @exc: Pointer to the exception result.
3078 * Invokes the delegate method @delegate with the parameters provided.
3080 * You can pass NULL as the exc argument if you don't want to
3081 * catch exceptions, otherwise, *exc will be set to the exception
3082 * thrown, if any. if an exception is thrown, you can't use the
3083 * MonoObject* result from the function.
3086 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3090 im = mono_get_delegate_invoke (delegate->vtable->klass);
3093 return mono_runtime_invoke (im, delegate, params, exc);
3096 static char **main_args = NULL;
3097 static int num_main_args;
3100 * mono_runtime_get_main_args:
3102 * Returns: a MonoArray with the arguments passed to the main program
3105 mono_runtime_get_main_args (void)
3109 MonoDomain *domain = mono_domain_get ();
3114 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3116 for (i = 0; i < num_main_args; ++i)
3117 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3123 fire_process_exit_event (void)
3125 MonoClassField *field;
3126 MonoDomain *domain = mono_domain_get ();
3128 MonoObject *delegate, *exc;
3130 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3133 if (domain != mono_get_root_domain ())
3136 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3137 if (delegate == NULL)
3142 mono_runtime_delegate_invoke (delegate, pa, &exc);
3146 * mono_runtime_run_main:
3147 * @method: the method to start the application with (usually Main)
3148 * @argc: number of arguments from the command line
3149 * @argv: array of strings from the command line
3150 * @exc: excetption results
3152 * Execute a standard Main() method (argc/argv contains the
3153 * executable name). This method also sets the command line argument value
3154 * needed by System.Environment.
3159 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3163 MonoArray *args = NULL;
3164 MonoDomain *domain = mono_domain_get ();
3165 gchar *utf8_fullpath;
3168 g_assert (method != NULL);
3170 mono_thread_set_main (mono_thread_current ());
3172 main_args = g_new0 (char*, argc);
3173 num_main_args = argc;
3175 if (!g_path_is_absolute (argv [0])) {
3176 gchar *basename = g_path_get_basename (argv [0]);
3177 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3181 utf8_fullpath = mono_utf8_from_external (fullpath);
3182 if(utf8_fullpath == NULL) {
3183 /* Printing the arg text will cause glib to
3184 * whinge about "Invalid UTF-8", but at least
3185 * its relevant, and shows the problem text
3188 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3189 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3196 utf8_fullpath = mono_utf8_from_external (argv[0]);
3197 if(utf8_fullpath == NULL) {
3198 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3199 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3204 main_args [0] = utf8_fullpath;
3206 for (i = 1; i < argc; ++i) {
3209 utf8_arg=mono_utf8_from_external (argv[i]);
3210 if(utf8_arg==NULL) {
3211 /* Ditto the comment about Invalid UTF-8 here */
3212 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3213 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3217 main_args [i] = utf8_arg;
3221 if (mono_method_signature (method)->param_count) {
3222 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3223 for (i = 0; i < argc; ++i) {
3224 /* The encodings should all work, given that
3225 * we've checked all these args for the
3228 gchar *str = mono_utf8_from_external (argv [i]);
3229 MonoString *arg = mono_string_new (domain, str);
3230 mono_array_setref (args, i, arg);
3234 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3237 mono_assembly_set_main (method->klass->image->assembly);
3239 result = mono_runtime_exec_main (method, args, exc);
3240 fire_process_exit_event ();
3244 /* Used in call_unhandled_exception_delegate */
3246 create_unhandled_exception_eventargs (MonoObject *exc)
3250 MonoMethod *method = NULL;
3251 MonoBoolean is_terminating = TRUE;
3254 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3257 mono_class_init (klass);
3259 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3260 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3264 args [1] = &is_terminating;
3266 obj = mono_object_new (mono_domain_get (), klass);
3267 mono_runtime_invoke (method, obj, args, NULL);
3272 /* Used in mono_unhandled_exception */
3274 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3275 MonoObject *e = NULL;
3278 pa [0] = domain->domain;
3279 pa [1] = create_unhandled_exception_eventargs (exc);
3280 mono_runtime_delegate_invoke (delegate, pa, &e);
3283 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3284 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3289 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3292 * mono_runtime_unhandled_exception_policy_set:
3293 * @policy: the new policy
3295 * This is a VM internal routine.
3297 * Sets the runtime policy for handling unhandled exceptions.
3300 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3301 runtime_unhandled_exception_policy = policy;
3305 * mono_runtime_unhandled_exception_policy_get:
3307 * This is a VM internal routine.
3309 * Gets the runtime policy for handling unhandled exceptions.
3311 MonoRuntimeUnhandledExceptionPolicy
3312 mono_runtime_unhandled_exception_policy_get (void) {
3313 return runtime_unhandled_exception_policy;
3317 * mono_unhandled_exception:
3318 * @exc: exception thrown
3320 * This is a VM internal routine.
3322 * We call this function when we detect an unhandled exception
3323 * in the default domain.
3325 * It invokes the * UnhandledException event in AppDomain or prints
3326 * a warning to the console
3329 mono_unhandled_exception (MonoObject *exc)
3331 MonoDomain *current_domain = mono_domain_get ();
3332 MonoDomain *root_domain = mono_get_root_domain ();
3333 MonoClassField *field;
3334 MonoObject *current_appdomain_delegate;
3335 MonoObject *root_appdomain_delegate;
3337 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3338 "UnhandledException");
3341 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3342 gboolean abort_process = (mono_thread_current () == main_thread) ||
3343 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3344 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3345 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3346 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3348 current_appdomain_delegate = NULL;
3351 /* set exitcode only if we will abort the process */
3353 mono_environment_exitcode_set (1);
3354 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3355 mono_print_unhandled_exception (exc);
3357 if (root_appdomain_delegate) {
3358 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3360 if (current_appdomain_delegate) {
3361 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3368 * Launch a new thread to execute a function
3370 * main_func is called back from the thread with main_args as the
3371 * parameter. The callback function is expected to start Main()
3372 * eventually. This function then waits for all managed threads to
3374 * It is not necesseray anymore to execute managed code in a subthread,
3375 * so this function should not be used anymore by default: just
3376 * execute the code and then call mono_thread_manage ().
3379 mono_runtime_exec_managed_code (MonoDomain *domain,
3380 MonoMainThreadFunc main_func,
3383 mono_thread_create (domain, main_func, main_args);
3385 mono_thread_manage ();
3389 * Execute a standard Main() method (args doesn't contain the
3393 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3398 MonoCustomAttrInfo* cinfo;
3399 gboolean has_stathread_attribute;
3400 MonoThread* thread = mono_thread_current ();
3406 domain = mono_object_domain (args);
3407 if (!domain->entry_assembly) {
3409 MonoAssembly *assembly;
3411 assembly = method->klass->image->assembly;
3412 domain->entry_assembly = assembly;
3413 /* Domains created from another domain already have application_base and configuration_file set */
3414 if (domain->setup->application_base == NULL) {
3415 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3418 if (domain->setup->configuration_file == NULL) {
3419 str = g_strconcat (assembly->image->name, ".config", NULL);
3420 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3422 mono_set_private_bin_path_from_config (domain);
3426 cinfo = mono_custom_attrs_from_method (method);
3428 static MonoClass *stathread_attribute = NULL;
3429 if (!stathread_attribute)
3430 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3431 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3433 mono_custom_attrs_free (cinfo);
3435 has_stathread_attribute = FALSE;
3437 if (has_stathread_attribute) {
3438 thread->apartment_state = ThreadApartmentState_STA;
3439 } else if (mono_framework_version () == 1) {
3440 thread->apartment_state = ThreadApartmentState_Unknown;
3442 thread->apartment_state = ThreadApartmentState_MTA;
3444 mono_thread_init_apartment_state ();
3446 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3448 /* FIXME: check signature of method */
3449 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3451 res = mono_runtime_invoke (method, NULL, pa, exc);
3453 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3457 mono_environment_exitcode_set (rval);
3459 mono_runtime_invoke (method, NULL, pa, exc);
3463 /* If the return type of Main is void, only
3464 * set the exitcode if an exception was thrown
3465 * (we don't want to blow away an
3466 * explicitly-set exit code)
3469 mono_environment_exitcode_set (rval);
3473 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3479 * mono_install_runtime_invoke:
3480 * @func: Function to install
3482 * This is a VM internal routine
3485 mono_install_runtime_invoke (MonoInvokeFunc func)
3487 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3492 * mono_runtime_invoke_array:
3493 * @method: method to invoke
3494 * @obJ: object instance
3495 * @params: arguments to the method
3496 * @exc: exception information.
3498 * Invokes the method represented by @method on the object @obj.
3500 * obj is the 'this' pointer, it should be NULL for static
3501 * methods, a MonoObject* for object instances and a pointer to
3502 * the value type for value types.
3504 * The params array contains the arguments to the method with the
3505 * same convention: MonoObject* pointers for object instances and
3506 * pointers to the value type otherwise. The _invoke_array
3507 * variant takes a C# object[] as the params argument (MonoArray
3508 * *params): in this case the value types are boxed inside the
3509 * respective reference representation.
3511 * From unmanaged code you'll usually use the
3512 * mono_runtime_invoke() variant.
3514 * Note that this function doesn't handle virtual methods for
3515 * you, it will exec the exact method you pass: we still need to
3516 * expose a function to lookup the derived class implementation
3517 * of a virtual method (there are examples of this in the code,
3520 * You can pass NULL as the exc argument if you don't want to
3521 * catch exceptions, otherwise, *exc will be set to the exception
3522 * thrown, if any. if an exception is thrown, you can't use the
3523 * MonoObject* result from the function.
3525 * If the method returns a value type, it is boxed in an object
3529 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3532 MonoMethodSignature *sig = mono_method_signature (method);
3533 gpointer *pa = NULL;
3536 gboolean has_byref_nullables = FALSE;
3538 if (NULL != params) {
3539 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3540 for (i = 0; i < mono_array_length (params); i++) {
3541 MonoType *t = sig->params [i];
3547 case MONO_TYPE_BOOLEAN:
3550 case MONO_TYPE_CHAR:
3559 case MONO_TYPE_VALUETYPE:
3560 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3561 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3562 pa [i] = mono_array_get (params, MonoObject*, i);
3564 has_byref_nullables = TRUE;
3566 /* MS seems to create the objects if a null is passed in */
3567 if (!mono_array_get (params, MonoObject*, i))
3568 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3572 * We can't pass the unboxed vtype byref to the callee, since
3573 * that would mean the callee would be able to modify boxed
3574 * primitive types. So we (and MS) make a copy of the boxed
3575 * object, pass that to the callee, and replace the original
3576 * boxed object in the arg array with the copy.
3578 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3579 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3580 mono_array_setref (params, i, copy);
3583 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3586 case MONO_TYPE_STRING:
3587 case MONO_TYPE_OBJECT:
3588 case MONO_TYPE_CLASS:
3589 case MONO_TYPE_ARRAY:
3590 case MONO_TYPE_SZARRAY:
3592 pa [i] = mono_array_addr (params, MonoObject*, i);
3593 // FIXME: I need to check this code path
3595 pa [i] = mono_array_get (params, MonoObject*, i);
3597 case MONO_TYPE_GENERICINST:
3599 t = &t->data.generic_class->container_class->this_arg;
3601 t = &t->data.generic_class->container_class->byval_arg;
3603 case MONO_TYPE_PTR: {
3606 /* The argument should be an IntPtr */
3607 arg = mono_array_get (params, MonoObject*, i);
3611 g_assert (arg->vtable->klass == mono_defaults.int_class);
3612 pa [i] = ((MonoIntPtr*)arg)->m_value;
3617 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3622 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3625 if (mono_class_is_nullable (method->klass)) {
3626 /* Need to create a boxed vtype instead */
3632 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3636 obj = mono_object_new (mono_domain_get (), method->klass);
3637 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3638 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3640 if (method->klass->valuetype)
3641 o = mono_object_unbox (obj);
3644 } else if (method->klass->valuetype) {
3645 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3648 mono_runtime_invoke (method, o, pa, exc);
3651 if (mono_class_is_nullable (method->klass)) {
3652 MonoObject *nullable;
3654 /* Convert the unboxed vtype into a Nullable structure */
3655 nullable = mono_object_new (mono_domain_get (), method->klass);
3657 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3658 obj = mono_object_unbox (nullable);
3661 /* obj must be already unboxed if needed */
3662 res = mono_runtime_invoke (method, obj, pa, exc);
3664 if (sig->ret->type == MONO_TYPE_PTR) {
3665 MonoClass *pointer_class;
3666 static MonoMethod *box_method;
3668 MonoObject *box_exc;
3671 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3672 * convert it to a Pointer object.
3674 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3676 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3678 g_assert (res->vtable->klass == mono_defaults.int_class);
3679 box_args [0] = ((MonoIntPtr*)res)->m_value;
3680 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3681 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3682 g_assert (!box_exc);
3685 if (has_byref_nullables) {
3687 * The runtime invoke wrapper already converted byref nullables back,
3688 * and stored them in pa, we just need to copy them back to the
3691 for (i = 0; i < mono_array_length (params); i++) {
3692 MonoType *t = sig->params [i];
3694 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3695 mono_array_setref (params, i, pa [i]);
3704 arith_overflow (void)
3706 mono_raise_exception (mono_get_exception_overflow ());
3710 * mono_object_allocate:
3711 * @size: number of bytes to allocate
3713 * This is a very simplistic routine until we have our GC-aware
3716 * Returns: an allocated object of size @size, or NULL on failure.
3718 static inline void *
3719 mono_object_allocate (size_t size, MonoVTable *vtable)
3722 mono_stats.new_object_count++;
3723 ALLOC_OBJECT (o, vtable, size);
3729 * mono_object_allocate_ptrfree:
3730 * @size: number of bytes to allocate
3732 * Note that the memory allocated is not zeroed.
3733 * Returns: an allocated object of size @size, or NULL on failure.
3735 static inline void *
3736 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3739 mono_stats.new_object_count++;
3740 ALLOC_PTRFREE (o, vtable, size);
3744 static inline void *
3745 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3748 ALLOC_TYPED (o, size, vtable);
3749 mono_stats.new_object_count++;
3756 * @klass: the class of the object that we want to create
3758 * Returns: a newly created object whose definition is
3759 * looked up using @klass. This will not invoke any constructors,
3760 * so the consumer of this routine has to invoke any constructors on
3761 * its own to initialize the object.
3764 mono_object_new (MonoDomain *domain, MonoClass *klass)
3766 MONO_ARCH_SAVE_REGS;
3767 return mono_object_new_specific (mono_class_vtable (domain, klass));
3771 * mono_object_new_specific:
3772 * @vtable: the vtable of the object that we want to create
3774 * Returns: A newly created object with class and domain specified
3778 mono_object_new_specific (MonoVTable *vtable)
3782 MONO_ARCH_SAVE_REGS;
3784 /* check for is_com_object for COM Interop */
3785 if (vtable->remote || vtable->klass->is_com_object)
3788 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3791 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3794 mono_class_init (klass);
3796 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3798 vtable->domain->create_proxy_for_type_method = im;
3801 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3803 o = mono_runtime_invoke (im, NULL, pa, NULL);
3804 if (o != NULL) return o;
3807 return mono_object_new_alloc_specific (vtable);
3811 mono_object_new_alloc_specific (MonoVTable *vtable)
3815 if (!vtable->klass->has_references) {
3816 o = mono_object_new_ptrfree (vtable);
3817 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3818 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3820 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3821 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3823 if (G_UNLIKELY (vtable->klass->has_finalize))
3824 mono_object_register_finalizer (o);
3826 if (G_UNLIKELY (profile_allocs))
3827 mono_profiler_allocation (o, vtable->klass);
3832 mono_object_new_fast (MonoVTable *vtable)
3835 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3840 mono_object_new_ptrfree (MonoVTable *vtable)
3843 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3844 #if NEED_TO_ZERO_PTRFREE
3845 /* an inline memset is much faster for the common vcase of small objects
3846 * note we assume the allocated size is a multiple of sizeof (void*).
3848 if (vtable->klass->instance_size < 128) {
3850 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3851 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3857 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3864 mono_object_new_ptrfree_box (MonoVTable *vtable)
3867 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3868 /* the object will be boxed right away, no need to memzero it */
3873 * mono_class_get_allocation_ftn:
3875 * @for_box: the object will be used for boxing
3876 * @pass_size_in_words:
3878 * Return the allocation function appropriate for the given class.
3882 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3884 *pass_size_in_words = FALSE;
3886 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3887 profile_allocs = FALSE;
3889 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3890 return mono_object_new_specific;
3892 if (!vtable->klass->has_references) {
3893 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3895 return mono_object_new_ptrfree_box;
3896 return mono_object_new_ptrfree;
3899 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3901 return mono_object_new_fast;
3904 * FIXME: This is actually slower than mono_object_new_fast, because
3905 * of the overhead of parameter passing.
3908 *pass_size_in_words = TRUE;
3909 #ifdef GC_REDIRECT_TO_LOCAL
3910 return GC_local_gcj_fast_malloc;
3912 return GC_gcj_fast_malloc;
3917 return mono_object_new_specific;
3921 * mono_object_new_from_token:
3922 * @image: Context where the type_token is hosted
3923 * @token: a token of the type that we want to create
3925 * Returns: A newly created object whose definition is
3926 * looked up using @token in the @image image
3929 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3933 class = mono_class_get (image, token);
3935 return mono_object_new (domain, class);
3940 * mono_object_clone:
3941 * @obj: the object to clone
3943 * Returns: A newly created object who is a shallow copy of @obj
3946 mono_object_clone (MonoObject *obj)
3951 size = obj->vtable->klass->instance_size;
3952 o = mono_object_allocate (size, obj->vtable);
3953 /* do not copy the sync state */
3954 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3957 if (obj->vtable->klass->has_references)
3958 mono_gc_wbarrier_object (o);
3960 if (G_UNLIKELY (profile_allocs))
3961 mono_profiler_allocation (o, obj->vtable->klass);
3963 if (obj->vtable->klass->has_finalize)
3964 mono_object_register_finalizer (o);
3969 * mono_array_full_copy:
3970 * @src: source array to copy
3971 * @dest: destination array
3973 * Copies the content of one array to another with exactly the same type and size.
3976 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3978 mono_array_size_t size;
3979 MonoClass *klass = src->obj.vtable->klass;
3981 MONO_ARCH_SAVE_REGS;
3983 g_assert (klass == dest->obj.vtable->klass);
3985 size = mono_array_length (src);
3986 g_assert (size == mono_array_length (dest));
3987 size *= mono_array_element_size (klass);
3989 if (klass->element_class->valuetype) {
3990 if (klass->element_class->has_references)
3991 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3993 memcpy (&dest->vector, &src->vector, size);
3995 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3998 memcpy (&dest->vector, &src->vector, size);
4003 * mono_array_clone_in_domain:
4004 * @domain: the domain in which the array will be cloned into
4005 * @array: the array to clone
4007 * This routine returns a copy of the array that is hosted on the
4008 * specified MonoDomain.
4011 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4014 mono_array_size_t size, i;
4015 mono_array_size_t *sizes;
4016 MonoClass *klass = array->obj.vtable->klass;
4018 MONO_ARCH_SAVE_REGS;
4020 if (array->bounds == NULL) {
4021 size = mono_array_length (array);
4022 o = mono_array_new_full (domain, klass, &size, NULL);
4024 size *= mono_array_element_size (klass);
4026 if (klass->element_class->valuetype) {
4027 if (klass->element_class->has_references)
4028 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4030 memcpy (&o->vector, &array->vector, size);
4032 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4035 memcpy (&o->vector, &array->vector, size);
4040 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4041 size = mono_array_element_size (klass);
4042 for (i = 0; i < klass->rank; ++i) {
4043 sizes [i] = array->bounds [i].length;
4044 size *= array->bounds [i].length;
4045 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4047 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4049 if (klass->element_class->valuetype) {
4050 if (klass->element_class->has_references)
4051 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4053 memcpy (&o->vector, &array->vector, size);
4055 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4058 memcpy (&o->vector, &array->vector, size);
4066 * @array: the array to clone
4068 * Returns: A newly created array who is a shallow copy of @array
4071 mono_array_clone (MonoArray *array)
4073 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4076 /* helper macros to check for overflow when calculating the size of arrays */
4077 #ifdef MONO_BIG_ARRAYS
4078 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4079 #define MYGUINT_MAX MYGUINT64_MAX
4080 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4081 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4082 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4083 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4084 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4086 #define MYGUINT32_MAX 4294967295U
4087 #define MYGUINT_MAX MYGUINT32_MAX
4088 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4089 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4090 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4091 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4092 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4096 * mono_array_new_full:
4097 * @domain: domain where the object is created
4098 * @array_class: array class
4099 * @lengths: lengths for each dimension in the array
4100 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4102 * This routine creates a new array objects with the given dimensions,
4103 * lower bounds and type.
4106 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4108 mono_array_size_t byte_len, len, bounds_size;
4114 if (!array_class->inited)
4115 mono_class_init (array_class);
4117 byte_len = mono_array_element_size (array_class);
4120 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4121 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4123 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4127 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4129 for (i = 0; i < array_class->rank; ++i) {
4130 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4132 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4133 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4138 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4139 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4141 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4142 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4143 byte_len += sizeof (MonoArray);
4146 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4147 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4148 byte_len = (byte_len + 3) & ~3;
4149 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4150 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4151 byte_len += bounds_size;
4154 * Following three lines almost taken from mono_object_new ():
4155 * they need to be kept in sync.
4157 vtable = mono_class_vtable (domain, array_class);
4158 if (!array_class->has_references) {
4159 o = mono_object_allocate_ptrfree (byte_len, vtable);
4160 #if NEED_TO_ZERO_PTRFREE
4161 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4163 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4164 o = mono_object_allocate_spec (byte_len, vtable);
4166 o = mono_object_allocate (byte_len, vtable);
4169 array = (MonoArray*)o;
4170 array->max_length = len;
4173 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4174 array->bounds = bounds;
4175 for (i = 0; i < array_class->rank; ++i) {
4176 bounds [i].length = lengths [i];
4178 bounds [i].lower_bound = lower_bounds [i];
4182 if (G_UNLIKELY (profile_allocs))
4183 mono_profiler_allocation (o, array_class);
4190 * @domain: domain where the object is created
4191 * @eclass: element class
4192 * @n: number of array elements
4194 * This routine creates a new szarray with @n elements of type @eclass.
4197 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4201 MONO_ARCH_SAVE_REGS;
4203 ac = mono_array_class_get (eclass, 1);
4206 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4210 * mono_array_new_specific:
4211 * @vtable: a vtable in the appropriate domain for an initialized class
4212 * @n: number of array elements
4214 * This routine is a fast alternative to mono_array_new() for code which
4215 * can be sure about the domain it operates in.
4218 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4222 guint32 byte_len, elem_size;
4224 MONO_ARCH_SAVE_REGS;
4226 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4231 elem_size = mono_array_element_size (vtable->klass);
4232 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4233 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4236 byte_len = n * elem_size;
4237 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4238 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4241 byte_len += sizeof (MonoArray);
4242 if (!vtable->klass->has_references) {
4243 o = mono_object_allocate_ptrfree (byte_len, vtable);
4244 #if NEED_TO_ZERO_PTRFREE
4245 ((MonoArray*)o)->bounds = NULL;
4246 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4248 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4249 o = mono_object_allocate_spec (byte_len, vtable);
4251 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4252 o = mono_object_allocate (byte_len, vtable);
4255 ao = (MonoArray *)o;
4257 if (G_UNLIKELY (profile_allocs))
4258 mono_profiler_allocation (o, vtable->klass);
4264 * mono_string_new_utf16:
4265 * @text: a pointer to an utf16 string
4266 * @len: the length of the string
4268 * Returns: A newly created string object which contains @text.
4271 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4275 s = mono_string_new_size (domain, len);
4276 g_assert (s != NULL);
4278 memcpy (mono_string_chars (s), text, len * 2);
4284 * mono_string_new_size:
4285 * @text: a pointer to an utf16 string
4286 * @len: the length of the string
4288 * Returns: A newly created string object of @len
4291 mono_string_new_size (MonoDomain *domain, gint32 len)
4295 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4297 /* overflow ? can't fit it, can't allocate it! */
4299 mono_gc_out_of_memory (-1);
4301 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4303 s = mono_object_allocate_ptrfree (size, vtable);
4306 #if NEED_TO_ZERO_PTRFREE
4309 if (G_UNLIKELY (profile_allocs))
4310 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4316 * mono_string_new_len:
4317 * @text: a pointer to an utf8 string
4318 * @length: number of bytes in @text to consider
4320 * Returns: A newly created string object which contains @text.
4323 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4325 GError *error = NULL;
4326 MonoString *o = NULL;
4328 glong items_written;
4330 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4333 o = mono_string_new_utf16 (domain, ut, items_written);
4335 g_error_free (error);
4344 * @text: a pointer to an utf8 string
4346 * Returns: A newly created string object which contains @text.
4349 mono_string_new (MonoDomain *domain, const char *text)
4351 GError *error = NULL;
4352 MonoString *o = NULL;
4354 glong items_written;
4359 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4362 o = mono_string_new_utf16 (domain, ut, items_written);
4364 g_error_free (error);
4367 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4372 MonoString *o = NULL;
4374 if (!g_utf8_validate (text, -1, &end))
4377 len = g_utf8_strlen (text, -1);
4378 o = mono_string_new_size (domain, len);
4379 str = mono_string_chars (o);
4381 while (text < end) {
4382 *str++ = g_utf8_get_char (text);
4383 text = g_utf8_next_char (text);
4390 * mono_string_new_wrapper:
4391 * @text: pointer to utf8 characters.
4393 * Helper function to create a string object from @text in the current domain.
4396 mono_string_new_wrapper (const char *text)
4398 MonoDomain *domain = mono_domain_get ();
4400 MONO_ARCH_SAVE_REGS;
4403 return mono_string_new (domain, text);
4410 * @class: the class of the value
4411 * @value: a pointer to the unboxed data
4413 * Returns: A newly created object which contains @value.
4416 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4422 g_assert (class->valuetype);
4423 if (mono_class_is_nullable (class))
4424 return mono_nullable_box (value, class);
4426 vtable = mono_class_vtable (domain, class);
4427 size = mono_class_instance_size (class);
4428 res = mono_object_new_alloc_specific (vtable);
4429 if (G_UNLIKELY (profile_allocs))
4430 mono_profiler_allocation (res, class);
4432 size = size - sizeof (MonoObject);
4435 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4438 #if NO_UNALIGNED_ACCESS
4439 memcpy ((char *)res + sizeof (MonoObject), value, size);
4443 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4446 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4449 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4452 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4455 memcpy ((char *)res + sizeof (MonoObject), value, size);
4458 if (class->has_finalize)
4459 mono_object_register_finalizer (res);
4465 * @dest: destination pointer
4466 * @src: source pointer
4467 * @klass: a valuetype class
4469 * Copy a valuetype from @src to @dest. This function must be used
4470 * when @klass contains references fields.
4473 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4475 int size = mono_class_value_size (klass, NULL);
4476 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4477 memcpy (dest, src, size);
4481 * mono_value_copy_array:
4482 * @dest: destination array
4483 * @dest_idx: index in the @dest array
4484 * @src: source pointer
4485 * @count: number of items
4487 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4488 * This function must be used when @klass contains references fields.
4489 * Overlap is handled.
4492 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4494 int size = mono_array_element_size (dest->obj.vtable->klass);
4495 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4496 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4497 memmove (d, src, size * count);
4501 * mono_object_get_domain:
4502 * @obj: object to query
4504 * Returns: the MonoDomain where the object is hosted
4507 mono_object_get_domain (MonoObject *obj)
4509 return mono_object_domain (obj);
4513 * mono_object_get_class:
4514 * @obj: object to query
4516 * Returns: the MonOClass of the object.
4519 mono_object_get_class (MonoObject *obj)
4521 return mono_object_class (obj);
4524 * mono_object_get_size:
4525 * @o: object to query
4527 * Returns: the size, in bytes, of @o
4530 mono_object_get_size (MonoObject* o)
4532 MonoClass* klass = mono_object_class (o);
4533 if (klass == mono_defaults.string_class) {
4534 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4535 } else if (o->vtable->rank) {
4536 MonoArray *array = (MonoArray*)o;
4537 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4538 if (array->bounds) {
4541 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4545 return mono_class_instance_size (klass);
4550 * mono_object_unbox:
4551 * @obj: object to unbox
4553 * Returns: a pointer to the start of the valuetype boxed in this
4556 * This method will assert if the object passed is not a valuetype.
4559 mono_object_unbox (MonoObject *obj)
4561 /* add assert for valuetypes? */
4562 g_assert (obj->vtable->klass->valuetype);
4563 return ((char*)obj) + sizeof (MonoObject);
4567 * mono_object_isinst:
4569 * @klass: a pointer to a class
4571 * Returns: @obj if @obj is derived from @klass
4574 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4577 mono_class_init (klass);
4579 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4580 return mono_object_isinst_mbyref (obj, klass);
4585 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4589 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4598 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4599 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4603 MonoClass *oklass = vt->klass;
4604 if ((oklass == mono_defaults.transparent_proxy_class))
4605 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4607 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4611 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4613 MonoDomain *domain = mono_domain_get ();
4615 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4616 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4617 MonoMethod *im = NULL;
4620 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4621 im = mono_object_get_virtual_method (rp, im);
4624 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4627 res = mono_runtime_invoke (im, rp, pa, NULL);
4629 if (*(MonoBoolean *) mono_object_unbox(res)) {
4630 /* Update the vtable of the remote type, so it can safely cast to this new type */
4631 mono_upgrade_remote_class (domain, obj, klass);
4640 * mono_object_castclass_mbyref:
4642 * @klass: a pointer to a class
4644 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4647 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4649 if (!obj) return NULL;
4650 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4652 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4654 "InvalidCastException"));
4659 MonoDomain *orig_domain;
4665 str_lookup (MonoDomain *domain, gpointer user_data)
4667 LDStrInfo *info = user_data;
4668 if (info->res || domain == info->orig_domain)
4670 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4676 mono_string_get_pinned (MonoString *str)
4680 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4681 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4682 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4683 news->length = mono_string_length (str);
4688 #define mono_string_get_pinned(str) (str)
4692 mono_string_is_interned_lookup (MonoString *str, int insert)
4694 MonoGHashTable *ldstr_table;
4698 domain = ((MonoObject *)str)->vtable->domain;
4699 ldstr_table = domain->ldstr_table;
4701 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4706 str = mono_string_get_pinned (str);
4707 mono_g_hash_table_insert (ldstr_table, str, str);
4711 LDStrInfo ldstr_info;
4712 ldstr_info.orig_domain = domain;
4713 ldstr_info.ins = str;
4714 ldstr_info.res = NULL;
4716 mono_domain_foreach (str_lookup, &ldstr_info);
4717 if (ldstr_info.res) {
4719 * the string was already interned in some other domain:
4720 * intern it in the current one as well.
4722 mono_g_hash_table_insert (ldstr_table, str, str);
4732 * mono_string_is_interned:
4733 * @o: String to probe
4735 * Returns whether the string has been interned.
4738 mono_string_is_interned (MonoString *o)
4740 return mono_string_is_interned_lookup (o, FALSE);
4744 * mono_string_intern:
4745 * @o: String to intern
4747 * Interns the string passed.
4748 * Returns: The interned string.
4751 mono_string_intern (MonoString *str)
4753 return mono_string_is_interned_lookup (str, TRUE);
4758 * @domain: the domain where the string will be used.
4759 * @image: a metadata context
4760 * @idx: index into the user string table.
4762 * Implementation for the ldstr opcode.
4763 * Returns: a loaded string from the @image/@idx combination.
4766 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4768 MONO_ARCH_SAVE_REGS;
4771 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4773 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4777 * mono_ldstr_metadata_sig
4778 * @domain: the domain for the string
4779 * @sig: the signature of a metadata string
4781 * Returns: a MonoString for a string stored in the metadata
4784 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4786 const char *str = sig;
4787 MonoString *o, *interned;
4790 len2 = mono_metadata_decode_blob_size (str, &str);
4793 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4794 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4797 guint16 *p2 = (guint16*)mono_string_chars (o);
4798 for (i = 0; i < len2; ++i) {
4799 *p2 = GUINT16_FROM_LE (*p2);
4805 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4807 /* o will get garbage collected */
4811 o = mono_string_get_pinned (o);
4812 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4819 * mono_string_to_utf8:
4820 * @s: a System.String
4822 * Return the UTF8 representation for @s.
4823 * the resulting buffer nedds to be freed with g_free().
4826 mono_string_to_utf8 (MonoString *s)
4830 GError *error = NULL;
4836 return g_strdup ("");
4838 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4840 MonoException *exc = mono_get_exception_argument ("string", error->message);
4841 g_error_free (error);
4842 mono_raise_exception(exc);
4844 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4845 if (s->length > written) {
4846 /* allocate the total length and copy the part of the string that has been converted */
4847 char *as2 = g_malloc0 (s->length);
4848 memcpy (as2, as, written);
4857 * mono_string_to_utf16:
4860 * Return an null-terminated array of the utf-16 chars
4861 * contained in @s. The result must be freed with g_free().
4862 * This is a temporary helper until our string implementation
4863 * is reworked to always include the null terminating char.
4866 mono_string_to_utf16 (MonoString *s)
4873 as = g_malloc ((s->length * 2) + 2);
4874 as [(s->length * 2)] = '\0';
4875 as [(s->length * 2) + 1] = '\0';
4878 return (gunichar2 *)(as);
4881 memcpy (as, mono_string_chars(s), s->length * 2);
4882 return (gunichar2 *)(as);
4886 * mono_string_from_utf16:
4887 * @data: the UTF16 string (LPWSTR) to convert
4889 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4891 * Returns: a MonoString.
4894 mono_string_from_utf16 (gunichar2 *data)
4896 MonoDomain *domain = mono_domain_get ();
4902 while (data [len]) len++;
4904 return mono_string_new_utf16 (domain, data, len);
4909 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4916 return mono_string_to_utf8 (s);
4918 r = mono_string_to_utf8 (s);
4922 len = strlen (r) + 1;
4924 mp_s = mono_mempool_alloc (mp, len);
4926 mp_s = mono_image_alloc (image, len);
4928 memcpy (mp_s, r, len);
4936 * mono_string_to_utf8_image:
4937 * @s: a System.String
4939 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4942 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4944 return mono_string_to_utf8_internal (NULL, image, s);
4948 * mono_string_to_utf8_mp:
4949 * @s: a System.String
4951 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4954 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4956 return mono_string_to_utf8_internal (mp, NULL, s);
4960 default_ex_handler (MonoException *ex)
4962 MonoObject *o = (MonoObject*)ex;
4963 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4967 static MonoExceptionFunc ex_handler = default_ex_handler;
4970 * mono_install_handler:
4971 * @func: exception handler
4973 * This is an internal JIT routine used to install the handler for exceptions
4977 mono_install_handler (MonoExceptionFunc func)
4979 ex_handler = func? func: default_ex_handler;
4983 * mono_raise_exception:
4984 * @ex: exception object
4986 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4989 mono_raise_exception (MonoException *ex)
4992 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4993 * that will cause gcc to omit the function epilog, causing problems when
4994 * the JIT tries to walk the stack, since the return address on the stack
4995 * will point into the next function in the executable, not this one.
4998 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
4999 MonoThread *thread = mono_thread_current ();
5000 g_assert (ex->object.vtable->domain == mono_domain_get ());
5001 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5008 * mono_wait_handle_new:
5009 * @domain: Domain where the object will be created
5010 * @handle: Handle for the wait handle
5012 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5015 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5017 MonoWaitHandle *res;
5018 gpointer params [1];
5019 static MonoMethod *handle_set;
5021 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
5023 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5025 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
5027 params [0] = &handle;
5028 mono_runtime_invoke (handle_set, res, params, NULL);
5034 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5036 static MonoClassField *f_os_handle;
5037 static MonoClassField *f_safe_handle;
5039 if (!f_os_handle && !f_safe_handle) {
5040 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
5041 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
5046 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5050 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5057 mono_runtime_capture_context (MonoDomain *domain)
5059 RuntimeInvokeFunction runtime_invoke;
5061 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5062 MonoMethod *method = mono_get_context_capture_method ();
5063 MonoMethod *wrapper;
5066 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5067 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5068 domain->capture_context_method = mono_compile_method (method);
5071 runtime_invoke = domain->capture_context_runtime_invoke;
5073 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5076 * mono_async_result_new:
5077 * @domain:domain where the object will be created.
5078 * @handle: wait handle.
5079 * @state: state to pass to AsyncResult
5080 * @data: C closure data.
5082 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5083 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5087 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5089 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5090 MonoObject *context = mono_runtime_capture_context (domain);
5091 /* we must capture the execution context from the original thread */
5093 MONO_OBJECT_SETREF (res, execution_context, context);
5094 /* note: result may be null if the flow is suppressed */
5098 MONO_OBJECT_SETREF (res, object_data, object_data);
5099 MONO_OBJECT_SETREF (res, async_state, state);
5101 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5103 res->sync_completed = FALSE;
5104 res->completed = FALSE;
5110 mono_message_init (MonoDomain *domain,
5111 MonoMethodMessage *this,
5112 MonoReflectionMethod *method,
5113 MonoArray *out_args)
5115 static MonoClass *object_array_klass;
5116 static MonoClass *byte_array_klass;
5117 static MonoClass *string_array_klass;
5118 MonoMethodSignature *sig = mono_method_signature (method->method);
5124 if (!object_array_klass) {
5127 klass = mono_array_class_get (mono_defaults.object_class, 1);
5130 mono_memory_barrier ();
5131 object_array_klass = klass;
5133 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5136 mono_memory_barrier ();
5137 byte_array_klass = klass;
5139 klass = mono_array_class_get (mono_defaults.string_class, 1);
5142 mono_memory_barrier ();
5143 string_array_klass = klass;
5146 MONO_OBJECT_SETREF (this, method, method);
5148 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5149 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5150 this->async_result = NULL;
5151 this->call_type = CallType_Sync;
5153 names = g_new (char *, sig->param_count);
5154 mono_method_get_param_names (method->method, (const char **) names);
5155 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5157 for (i = 0; i < sig->param_count; i++) {
5158 name = mono_string_new (domain, names [i]);
5159 mono_array_setref (this->names, i, name);
5163 for (i = 0, j = 0; i < sig->param_count; i++) {
5164 if (sig->params [i]->byref) {
5166 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5167 mono_array_setref (this->args, i, arg);
5171 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5175 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5178 mono_array_set (this->arg_types, guint8, i, arg_type);
5183 * mono_remoting_invoke:
5184 * @real_proxy: pointer to a RealProxy object
5185 * @msg: The MonoMethodMessage to execute
5186 * @exc: used to store exceptions
5187 * @out_args: used to store output arguments
5189 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5190 * IMessage interface and it is not trivial to extract results from there. So
5191 * we call an helper method PrivateInvoke instead of calling
5192 * RealProxy::Invoke() directly.
5194 * Returns: the result object.
5197 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5198 MonoObject **exc, MonoArray **out_args)
5200 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5203 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5206 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5208 real_proxy->vtable->domain->private_invoke_method = im;
5211 pa [0] = real_proxy;
5216 return mono_runtime_invoke (im, NULL, pa, exc);
5220 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5221 MonoObject **exc, MonoArray **out_args)
5223 static MonoClass *object_array_klass;
5226 MonoMethodSignature *sig;
5228 int i, j, outarg_count = 0;
5230 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5232 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5233 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5234 target = tp->rp->unwrapped_server;
5236 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5240 domain = mono_domain_get ();
5241 method = msg->method->method;
5242 sig = mono_method_signature (method);
5244 for (i = 0; i < sig->param_count; i++) {
5245 if (sig->params [i]->byref)
5249 if (!object_array_klass) {
5252 klass = mono_array_class_get (mono_defaults.object_class, 1);
5255 mono_memory_barrier ();
5256 object_array_klass = klass;
5259 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5260 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5263 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5265 for (i = 0, j = 0; i < sig->param_count; i++) {
5266 if (sig->params [i]->byref) {
5268 arg = mono_array_get (msg->args, gpointer, i);
5269 mono_array_setref (*out_args, j, arg);
5278 * mono_print_unhandled_exception:
5279 * @exc: The exception
5281 * Prints the unhandled exception.
5284 mono_print_unhandled_exception (MonoObject *exc)
5286 char *message = (char *) "";
5290 gboolean free_message = FALSE;
5292 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5293 klass = exc->vtable->klass;
5295 while (klass && method == NULL) {
5296 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5298 klass = klass->parent;
5303 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5305 message = mono_string_to_utf8 (str);
5306 free_message = TRUE;
5311 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5312 * exc->vtable->klass->name, message);
5314 g_printerr ("\nUnhandled Exception: %s\n", message);
5321 * mono_delegate_ctor:
5322 * @this: pointer to an uninitialized delegate object
5323 * @target: target object
5324 * @addr: pointer to native code
5327 * Initialize a delegate and sets a specific method, not the one
5328 * associated with addr. This is useful when sharing generic code.
5329 * In that case addr will most probably not be associated with the
5330 * correct instantiation of the method.
5333 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5335 MonoDelegate *delegate = (MonoDelegate *)this;
5342 delegate->method = method;
5344 class = this->vtable->klass;
5345 mono_stats.delegate_creations++;
5347 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5349 method = mono_marshal_get_remoting_invoke (method);
5350 delegate->method_ptr = mono_compile_method (method);
5351 MONO_OBJECT_SETREF (delegate, target, target);
5352 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5353 method = mono_marshal_get_unbox_wrapper (method);
5354 delegate->method_ptr = mono_compile_method (method);
5355 MONO_OBJECT_SETREF (delegate, target, target);
5357 delegate->method_ptr = addr;
5358 MONO_OBJECT_SETREF (delegate, target, target);
5361 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5365 * mono_delegate_ctor:
5366 * @this: pointer to an uninitialized delegate object
5367 * @target: target object
5368 * @addr: pointer to native code
5370 * This is used to initialize a delegate.
5373 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5375 MonoDomain *domain = mono_domain_get ();
5377 MonoMethod *method = NULL;
5381 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5382 method = ji->method;
5383 g_assert (!method->klass->generic_container);
5386 mono_delegate_ctor_with_method (this, target, addr, method);
5390 * mono_method_call_message_new:
5391 * @method: method to encapsulate
5392 * @params: parameters to the method
5393 * @invoke: optional, delegate invoke.
5394 * @cb: async callback delegate.
5395 * @state: state passed to the async callback.
5397 * Translates arguments pointers into a MonoMethodMessage.
5400 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5401 MonoDelegate **cb, MonoObject **state)
5403 MonoDomain *domain = mono_domain_get ();
5404 MonoMethodSignature *sig = mono_method_signature (method);
5405 MonoMethodMessage *msg;
5408 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5411 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5412 count = sig->param_count - 2;
5414 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5415 count = sig->param_count;
5418 for (i = 0; i < count; i++) {
5423 if (sig->params [i]->byref)
5424 vpos = *((gpointer *)params [i]);
5428 type = sig->params [i]->type;
5429 class = mono_class_from_mono_type (sig->params [i]);
5431 if (class->valuetype)
5432 arg = mono_value_box (domain, class, vpos);
5434 arg = *((MonoObject **)vpos);
5436 mono_array_setref (msg->args, i, arg);
5439 if (cb != NULL && state != NULL) {
5440 *cb = *((MonoDelegate **)params [i]);
5442 *state = *((MonoObject **)params [i]);
5449 * mono_method_return_message_restore:
5451 * Restore results from message based processing back to arguments pointers
5454 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5456 MonoMethodSignature *sig = mono_method_signature (method);
5457 int i, j, type, size, out_len;
5459 if (out_args == NULL)
5461 out_len = mono_array_length (out_args);
5465 for (i = 0, j = 0; i < sig->param_count; i++) {
5466 MonoType *pt = sig->params [i];
5471 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5473 arg = mono_array_get (out_args, gpointer, j);
5477 case MONO_TYPE_VOID:
5478 g_assert_not_reached ();
5482 case MONO_TYPE_BOOLEAN:
5485 case MONO_TYPE_CHAR:
5492 case MONO_TYPE_VALUETYPE: {
5494 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5495 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5498 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5499 memset (*((gpointer *)params [i]), 0, size);
5503 case MONO_TYPE_STRING:
5504 case MONO_TYPE_CLASS:
5505 case MONO_TYPE_ARRAY:
5506 case MONO_TYPE_SZARRAY:
5507 case MONO_TYPE_OBJECT:
5508 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5511 g_assert_not_reached ();
5520 * mono_load_remote_field:
5521 * @this: pointer to an object
5522 * @klass: klass of the object containing @field
5523 * @field: the field to load
5524 * @res: a storage to store the result
5526 * This method is called by the runtime on attempts to load fields of
5527 * transparent proxy objects. @this points to such TP, @klass is the class of
5528 * the object containing @field. @res is a storage location which can be
5529 * used to store the result.
5531 * Returns: an address pointing to the value of field.
5534 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5536 static MonoMethod *getter = NULL;
5537 MonoDomain *domain = mono_domain_get ();
5538 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5539 MonoClass *field_class;
5540 MonoMethodMessage *msg;
5541 MonoArray *out_args;
5545 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5546 g_assert (res != NULL);
5548 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5549 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5554 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5558 field_class = mono_class_from_mono_type (field->type);
5560 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5561 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5562 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5564 full_name = mono_type_get_full_name (klass);
5565 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5566 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5569 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5571 if (exc) mono_raise_exception ((MonoException *)exc);
5573 if (mono_array_length (out_args) == 0)
5576 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5578 if (field_class->valuetype) {
5579 return ((char *)*res) + sizeof (MonoObject);
5585 * mono_load_remote_field_new:
5590 * Missing documentation.
5593 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5595 static MonoMethod *getter = NULL;
5596 MonoDomain *domain = mono_domain_get ();
5597 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5598 MonoClass *field_class;
5599 MonoMethodMessage *msg;
5600 MonoArray *out_args;
5601 MonoObject *exc, *res;
5604 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5606 field_class = mono_class_from_mono_type (field->type);
5608 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5610 if (field_class->valuetype) {
5611 res = mono_object_new (domain, field_class);
5612 val = ((gchar *) res) + sizeof (MonoObject);
5616 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5621 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5625 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5626 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5628 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5630 full_name = mono_type_get_full_name (klass);
5631 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5632 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5635 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5637 if (exc) mono_raise_exception ((MonoException *)exc);
5639 if (mono_array_length (out_args) == 0)
5642 res = mono_array_get (out_args, MonoObject *, 0);
5648 * mono_store_remote_field:
5649 * @this: pointer to an object
5650 * @klass: klass of the object containing @field
5651 * @field: the field to load
5652 * @val: the value/object to store
5654 * This method is called by the runtime on attempts to store fields of
5655 * transparent proxy objects. @this points to such TP, @klass is the class of
5656 * the object containing @field. @val is the new value to store in @field.
5659 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5661 static MonoMethod *setter = NULL;
5662 MonoDomain *domain = mono_domain_get ();
5663 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5664 MonoClass *field_class;
5665 MonoMethodMessage *msg;
5666 MonoArray *out_args;
5671 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5673 field_class = mono_class_from_mono_type (field->type);
5675 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5676 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5677 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5682 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5686 if (field_class->valuetype)
5687 arg = mono_value_box (domain, field_class, val);
5689 arg = *((MonoObject **)val);
5692 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5693 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5695 full_name = mono_type_get_full_name (klass);
5696 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5697 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5698 mono_array_setref (msg->args, 2, arg);
5701 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5703 if (exc) mono_raise_exception ((MonoException *)exc);
5707 * mono_store_remote_field_new:
5713 * Missing documentation
5716 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5718 static MonoMethod *setter = NULL;
5719 MonoDomain *domain = mono_domain_get ();
5720 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5721 MonoClass *field_class;
5722 MonoMethodMessage *msg;
5723 MonoArray *out_args;
5727 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5729 field_class = mono_class_from_mono_type (field->type);
5731 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5732 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5733 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5738 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5742 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5743 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5745 full_name = mono_type_get_full_name (klass);
5746 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5747 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5748 mono_array_setref (msg->args, 2, arg);
5751 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5753 if (exc) mono_raise_exception ((MonoException *)exc);
5757 * mono_create_ftnptr:
5759 * Given a function address, create a function descriptor for it.
5760 * This is only needed on some platforms.
5763 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5765 return callbacks.create_ftnptr (domain, addr);
5769 * mono_get_addr_from_ftnptr:
5771 * Given a pointer to a function descriptor, return the function address.
5772 * This is only needed on some platforms.
5775 mono_get_addr_from_ftnptr (gpointer descr)
5777 return callbacks.get_addr_from_ftnptr (descr);
5782 * mono_string_chars:
5785 * Returns a pointer to the UCS16 characters stored in the MonoString
5788 mono_string_chars(MonoString *s)
5790 /* This method is here only for documentation extraction, this is a macro */
5794 * mono_string_length:
5797 * Returns the lenght in characters of the string
5800 mono_string_length (MonoString *s)
5802 /* This method is here only for documentation extraction, this is a macro */