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;
145 * mono_thread_set_main:
146 * @thread: thread to set as the main thread
148 * This function can be used to instruct the runtime to treat @thread
149 * as the main thread, ie, the thread that would normally execute the Main()
150 * method. This basically means that at the end of @thread, the runtime will
151 * wait for the existing foreground threads to quit and other such details.
154 mono_thread_set_main (MonoThread *thread)
156 main_thread = thread;
160 mono_thread_get_main (void)
166 mono_type_initialization_init (void)
168 InitializeCriticalSection (&type_initialization_section);
169 type_initialization_hash = g_hash_table_new (NULL, NULL);
170 blocked_thread_hash = g_hash_table_new (NULL, NULL);
171 InitializeCriticalSection (&ldstr_section);
175 mono_type_initialization_cleanup (void)
178 /* This is causing race conditions with
179 * mono_release_type_locks
181 DeleteCriticalSection (&type_initialization_section);
183 DeleteCriticalSection (&ldstr_section);
187 * get_type_init_exception_for_vtable:
189 * Return the stored type initialization exception for VTABLE.
191 static MonoException*
192 get_type_init_exception_for_vtable (MonoVTable *vtable)
194 MonoDomain *domain = vtable->domain;
195 MonoClass *klass = vtable->klass;
199 g_assert (vtable->init_failed);
202 * If the initializing thread was rudely aborted, the exception is not stored
206 mono_domain_lock (domain);
207 if (domain->type_init_exception_hash)
208 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
209 mono_domain_unlock (domain);
212 if (klass->name_space && *klass->name_space)
213 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
215 full_name = g_strdup (klass->name);
216 ex = mono_get_exception_type_initialization (full_name, NULL);
223 * mono_runtime_class_init:
224 * @vtable: vtable that needs to be initialized
226 * This routine calls the class constructor for @vtable.
229 mono_runtime_class_init (MonoVTable *vtable)
231 mono_runtime_class_init_full (vtable, TRUE);
235 * mono_runtime_class_init_full:
236 * @vtable that neeeds to be initialized
237 * @raise_exception is TRUE, exceptions are raised intead of returned
241 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
244 MonoException *exc_to_throw;
245 MonoMethod *method = NULL;
251 if (vtable->initialized)
255 klass = vtable->klass;
257 if (!klass->image->checked_module_cctor) {
258 mono_image_check_for_module_cctor (klass->image);
259 if (klass->image->has_module_cctor) {
260 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
261 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
264 method = mono_class_get_cctor (klass);
267 MonoDomain *domain = vtable->domain;
268 TypeInitializationLock *lock;
269 guint32 tid = GetCurrentThreadId();
270 int do_initialization = 0;
271 MonoDomain *last_domain = NULL;
273 mono_type_initialization_lock ();
274 /* double check... */
275 if (vtable->initialized) {
276 mono_type_initialization_unlock ();
279 if (vtable->init_failed) {
280 mono_type_initialization_unlock ();
282 /* The type initialization already failed once, rethrow the same exception */
284 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
285 return get_type_init_exception_for_vtable (vtable);
287 lock = g_hash_table_lookup (type_initialization_hash, vtable);
289 /* This thread will get to do the initialization */
290 if (mono_domain_get () != domain) {
291 /* Transfer into the target domain */
292 last_domain = mono_domain_get ();
293 if (!mono_domain_set (domain, FALSE)) {
294 vtable->initialized = 1;
295 mono_type_initialization_unlock ();
297 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
298 return mono_get_exception_appdomain_unloaded ();
301 lock = g_malloc (sizeof(TypeInitializationLock));
302 InitializeCriticalSection (&lock->initialization_section);
303 lock->initializing_tid = tid;
304 lock->waiting_count = 1;
306 /* grab the vtable lock while this thread still owns type_initialization_section */
307 EnterCriticalSection (&lock->initialization_section);
308 g_hash_table_insert (type_initialization_hash, vtable, lock);
309 do_initialization = 1;
312 TypeInitializationLock *pending_lock;
314 if (lock->initializing_tid == tid || lock->done) {
315 mono_type_initialization_unlock ();
318 /* see if the thread doing the initialization is already blocked on this thread */
319 blocked = GUINT_TO_POINTER (lock->initializing_tid);
320 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
321 if (pending_lock->initializing_tid == tid) {
322 if (!pending_lock->done) {
323 mono_type_initialization_unlock ();
326 /* the thread doing the initialization is blocked on this thread,
327 but on a lock that has already been freed. It just hasn't got
332 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
334 ++lock->waiting_count;
335 /* record the fact that we are waiting on the initializing thread */
336 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
338 mono_type_initialization_unlock ();
340 if (do_initialization) {
341 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
343 /* If the initialization failed, mark the class as unusable. */
344 /* Avoid infinite loops */
346 (klass->image == mono_defaults.corlib &&
347 !strcmp (klass->name_space, "System") &&
348 !strcmp (klass->name, "TypeInitializationException")))) {
349 vtable->init_failed = 1;
351 if (klass->name_space && *klass->name_space)
352 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
354 full_name = g_strdup (klass->name);
355 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
359 * Store the exception object so it could be thrown on subsequent
362 mono_domain_lock (domain);
363 if (!domain->type_init_exception_hash)
364 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
365 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
366 mono_domain_unlock (domain);
370 mono_domain_set (last_domain, TRUE);
372 LeaveCriticalSection (&lock->initialization_section);
374 /* this just blocks until the initializing thread is done */
375 EnterCriticalSection (&lock->initialization_section);
376 LeaveCriticalSection (&lock->initialization_section);
379 mono_type_initialization_lock ();
380 if (lock->initializing_tid != tid)
381 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
382 --lock->waiting_count;
383 if (lock->waiting_count == 0) {
384 DeleteCriticalSection (&lock->initialization_section);
385 g_hash_table_remove (type_initialization_hash, vtable);
388 if (!vtable->init_failed)
389 vtable->initialized = 1;
390 mono_type_initialization_unlock ();
392 if (vtable->init_failed) {
393 /* Either we were the initializing thread or we waited for the initialization */
395 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
396 return get_type_init_exception_for_vtable (vtable);
399 vtable->initialized = 1;
406 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
408 MonoVTable *vtable = (MonoVTable*)key;
410 TypeInitializationLock *lock = (TypeInitializationLock*) value;
411 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
414 * Have to set this since it cannot be set by the normal code in
415 * mono_runtime_class_init (). In this case, the exception object is not stored,
416 * and get_type_init_exception_for_class () needs to be aware of this.
418 vtable->init_failed = 1;
419 LeaveCriticalSection (&lock->initialization_section);
420 --lock->waiting_count;
421 if (lock->waiting_count == 0) {
422 DeleteCriticalSection (&lock->initialization_section);
431 mono_release_type_locks (MonoThread *thread)
433 mono_type_initialization_lock ();
434 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
435 mono_type_initialization_unlock ();
439 default_trampoline (MonoMethod *method)
445 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
447 g_assert_not_reached ();
453 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
455 g_error ("remoting not installed");
460 default_delegate_trampoline (MonoClass *klass)
462 g_assert_not_reached ();
466 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
467 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
468 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
469 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
470 static MonoImtThunkBuilder imt_thunk_builder = NULL;
471 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
472 #if (MONO_IMT_SIZE > 32)
473 #error "MONO_IMT_SIZE cannot be larger than 32"
477 mono_install_trampoline (MonoTrampoline func)
479 arch_create_jit_trampoline = func? func: default_trampoline;
483 mono_install_jump_trampoline (MonoJumpTrampoline func)
485 arch_create_jump_trampoline = func? func: default_jump_trampoline;
489 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
491 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
495 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
497 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
501 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
502 imt_thunk_builder = func;
505 static MonoCompileFunc default_mono_compile_method = NULL;
508 * mono_install_compile_method:
509 * @func: function to install
511 * This is a VM internal routine
514 mono_install_compile_method (MonoCompileFunc func)
516 default_mono_compile_method = func;
520 * mono_compile_method:
521 * @method: The method to compile.
523 * This JIT-compiles the method, and returns the pointer to the native code
527 mono_compile_method (MonoMethod *method)
529 if (!default_mono_compile_method) {
530 g_error ("compile method called on uninitialized runtime");
533 return default_mono_compile_method (method);
537 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
539 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
543 mono_runtime_create_delegate_trampoline (MonoClass *klass)
545 return arch_create_delegate_trampoline (klass);
548 static MonoFreeMethodFunc default_mono_free_method = NULL;
551 * mono_install_free_method:
552 * @func: pointer to the MonoFreeMethodFunc used to release a method
554 * This is an internal VM routine, it is used for the engines to
555 * register a handler to release the resources associated with a method.
557 * Methods are freed when no more references to the delegate that holds
561 mono_install_free_method (MonoFreeMethodFunc func)
563 default_mono_free_method = func;
567 * mono_runtime_free_method:
568 * @domain; domain where the method is hosted
569 * @method: method to release
571 * This routine is invoked to free the resources associated with
572 * a method that has been JIT compiled. This is used to discard
573 * methods that were used only temporarily (for example, used in marshalling)
577 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
579 if (default_mono_free_method != NULL)
580 default_mono_free_method (domain, method);
582 mono_method_clear_object (domain, method);
584 mono_free_method (method);
588 * The vtables in the root appdomain are assumed to be reachable by other
589 * roots, and we don't use typed allocation in the other domains.
592 /* The sync block is no longer a GC pointer */
593 #define GC_HEADER_BITMAP (0)
595 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
598 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
600 MonoClassField *field;
606 max_size = mono_class_data_size (class) / sizeof (gpointer);
608 max_size = class->instance_size / sizeof (gpointer);
609 if (max_size >= size) {
610 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
613 for (p = class; p != NULL; p = p->parent) {
614 gpointer iter = NULL;
615 while ((field = mono_class_get_fields (p, &iter))) {
619 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
621 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
624 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
627 /* FIXME: should not happen, flag as type load error */
628 if (field->type->byref)
631 pos = field->offset / sizeof (gpointer);
634 type = mono_type_get_underlying_type (field->type);
635 switch (type->type) {
638 case MONO_TYPE_FNPTR:
640 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
645 if (class->image != mono_defaults.corlib)
648 case MONO_TYPE_STRING:
649 case MONO_TYPE_SZARRAY:
650 case MONO_TYPE_CLASS:
651 case MONO_TYPE_OBJECT:
652 case MONO_TYPE_ARRAY:
653 g_assert ((field->offset % sizeof(gpointer)) == 0);
655 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
656 *max_set = MAX (*max_set, pos);
658 case MONO_TYPE_GENERICINST:
659 if (!mono_type_generic_inst_is_valuetype (type)) {
660 g_assert ((field->offset % sizeof(gpointer)) == 0);
662 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
663 *max_set = MAX (*max_set, pos);
668 case MONO_TYPE_VALUETYPE: {
669 MonoClass *fclass = mono_class_from_mono_type (field->type);
670 if (fclass->has_references) {
671 /* remove the object header */
672 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
686 case MONO_TYPE_BOOLEAN:
690 g_assert_not_reached ();
702 * similar to the above, but sets the bits in the bitmap for any non-ref field
703 * and ignores static fields
706 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
708 MonoClassField *field;
713 max_size = class->instance_size / sizeof (gpointer);
714 if (max_size >= size) {
715 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
718 for (p = class; p != NULL; p = p->parent) {
719 gpointer iter = NULL;
720 while ((field = mono_class_get_fields (p, &iter))) {
723 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
725 /* FIXME: should not happen, flag as type load error */
726 if (field->type->byref)
729 pos = field->offset / sizeof (gpointer);
732 type = mono_type_get_underlying_type (field->type);
733 switch (type->type) {
734 #if SIZEOF_VOID_P == 8
738 case MONO_TYPE_FNPTR:
743 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
744 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
745 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
748 #if SIZEOF_VOID_P == 4
752 case MONO_TYPE_FNPTR:
757 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
758 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
759 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
765 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
766 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
767 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
770 case MONO_TYPE_BOOLEAN:
773 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
775 case MONO_TYPE_STRING:
776 case MONO_TYPE_SZARRAY:
777 case MONO_TYPE_CLASS:
778 case MONO_TYPE_OBJECT:
779 case MONO_TYPE_ARRAY:
781 case MONO_TYPE_GENERICINST:
782 if (!mono_type_generic_inst_is_valuetype (type)) {
787 case MONO_TYPE_VALUETYPE: {
788 MonoClass *fclass = mono_class_from_mono_type (field->type);
789 /* remove the object header */
790 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
794 g_assert_not_reached ();
803 * mono_class_insecure_overlapping:
804 * check if a class with explicit layout has references and non-references
805 * fields overlapping.
807 * Returns: TRUE if it is insecure to load the type.
810 mono_class_insecure_overlapping (MonoClass *klass)
814 gsize default_bitmap [4] = {0};
816 gsize default_nrbitmap [4] = {0};
817 int i, insecure = FALSE;
820 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
821 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
823 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
824 int idx = i % (sizeof (bitmap [0]) * 8);
825 if (bitmap [idx] & nrbitmap [idx]) {
830 if (bitmap != default_bitmap)
832 if (nrbitmap != default_nrbitmap)
835 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
843 mono_string_alloc (int length)
845 return mono_string_new_size (mono_domain_get (), length);
849 mono_class_compute_gc_descriptor (MonoClass *class)
853 gsize default_bitmap [4] = {0};
854 static gboolean gcj_inited = FALSE;
859 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
860 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
861 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
862 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
864 #ifdef HAVE_GC_GCJ_MALLOC
866 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
870 #ifdef GC_REDIRECT_TO_LOCAL
871 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
872 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
874 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
875 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
880 mono_loader_unlock ();
884 mono_class_init (class);
886 if (class->gc_descr_inited)
889 class->gc_descr_inited = TRUE;
890 class->gc_descr = GC_NO_DESCRIPTOR;
892 bitmap = default_bitmap;
893 if (class == mono_defaults.string_class) {
894 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
895 } else if (class->rank) {
896 mono_class_compute_gc_descriptor (class->element_class);
897 if (!class->element_class->valuetype) {
899 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
900 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
901 class->name_space, class->name);*/
903 /* remove the object header */
904 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
905 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
906 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
907 class->name_space, class->name);*/
908 if (bitmap != default_bitmap)
912 /*static int count = 0;
915 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
916 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
918 if (class->gc_descr == GC_NO_DESCRIPTOR)
919 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
921 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
922 if (bitmap != default_bitmap)
928 * field_is_special_static:
929 * @fklass: The MonoClass to look up.
930 * @field: The MonoClassField describing the field.
932 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
933 * SPECIAL_STATIC_NONE otherwise.
936 field_is_special_static (MonoClass *fklass, MonoClassField *field)
938 MonoCustomAttrInfo *ainfo;
940 ainfo = mono_custom_attrs_from_field (fklass, field);
943 for (i = 0; i < ainfo->num_attrs; ++i) {
944 MonoClass *klass = ainfo->attrs [i].ctor->klass;
945 if (klass->image == mono_defaults.corlib) {
946 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
947 mono_custom_attrs_free (ainfo);
948 return SPECIAL_STATIC_THREAD;
950 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
951 mono_custom_attrs_free (ainfo);
952 return SPECIAL_STATIC_CONTEXT;
956 mono_custom_attrs_free (ainfo);
957 return SPECIAL_STATIC_NONE;
960 static gpointer imt_trampoline = NULL;
963 mono_install_imt_trampoline (gpointer tramp_code)
965 imt_trampoline = tramp_code;
968 static gpointer vtable_trampoline = NULL;
971 mono_install_vtable_trampoline (gpointer tramp_code)
973 vtable_trampoline = tramp_code;
976 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
977 #define mix(a,b,c) { \
978 a -= c; a ^= rot(c, 4); c += b; \
979 b -= a; b ^= rot(a, 6); a += c; \
980 c -= b; c ^= rot(b, 8); b += a; \
981 a -= c; a ^= rot(c,16); c += b; \
982 b -= a; b ^= rot(a,19); a += c; \
983 c -= b; c ^= rot(b, 4); b += a; \
985 #define final(a,b,c) { \
986 c ^= b; c -= rot(b,14); \
987 a ^= c; a -= rot(c,11); \
988 b ^= a; b -= rot(a,25); \
989 c ^= b; c -= rot(b,16); \
990 a ^= c; a -= rot(c,4); \
991 b ^= a; b -= rot(a,14); \
992 c ^= b; c -= rot(b,24); \
996 mono_method_get_imt_slot (MonoMethod *method)
998 MonoMethodSignature *sig;
1000 guint32 *hashes_start, *hashes;
1004 /* This can be used to stress tests the collision code */
1008 * We do this to simplify generic sharing. It will hurt
1009 * performance in cases where a class implements two different
1010 * instantiations of the same generic interface.
1011 * The code in build_imt_slots () depends on this.
1013 if (method->is_inflated)
1014 method = ((MonoMethodInflated*)method)->declaring;
1016 sig = mono_method_signature (method);
1017 hashes_count = sig->param_count + 4;
1018 hashes_start = malloc (hashes_count * sizeof (guint32));
1019 hashes = hashes_start;
1021 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1022 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1023 method->klass->name_space, method->klass->name, method->name);
1024 g_assert_not_reached ();
1027 /* Initialize hashes */
1028 hashes [0] = g_str_hash (method->klass->name);
1029 hashes [1] = g_str_hash (method->klass->name_space);
1030 hashes [2] = g_str_hash (method->name);
1031 hashes [3] = mono_metadata_type_hash (sig->ret);
1032 for (i = 0; i < sig->param_count; i++) {
1033 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1036 /* Setup internal state */
1037 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1039 /* Handle most of the hashes */
1040 while (hashes_count > 3) {
1049 /* Handle the last 3 hashes (all the case statements fall through) */
1050 switch (hashes_count) {
1051 case 3 : c += hashes [2];
1052 case 2 : b += hashes [1];
1053 case 1 : a += hashes [0];
1055 case 0: /* nothing left to add */
1059 free (hashes_start);
1060 /* Report the result */
1061 return c % MONO_IMT_SIZE;
1070 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1071 guint32 imt_slot = mono_method_get_imt_slot (method);
1072 MonoImtBuilderEntry *entry;
1074 if (slot_num >= 0 && imt_slot != slot_num) {
1075 /* we build just a single imt slot and this is not it */
1079 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1080 entry->key = method;
1081 entry->value.vtable_slot = vtable_slot;
1082 entry->next = imt_builder [imt_slot];
1083 if (imt_builder [imt_slot] != NULL) {
1084 entry->children = imt_builder [imt_slot]->children + 1;
1085 if (entry->children == 1) {
1086 mono_stats.imt_slots_with_collisions++;
1087 *imt_collisions_bitmap |= (1 << imt_slot);
1090 entry->children = 0;
1091 mono_stats.imt_used_slots++;
1093 imt_builder [imt_slot] = entry;
1095 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1096 method, method->klass->name_space, method->klass->name,
1097 method->name, imt_slot, vtable_slot, entry->children);
1103 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1105 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1109 e->method->klass->name_space,
1110 e->method->klass->name,
1113 printf (" * %s: NULL\n", message);
1119 compare_imt_builder_entries (const void *p1, const void *p2) {
1120 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1121 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1123 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1127 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1129 int count = end - start;
1130 int chunk_start = out_array->len;
1133 for (i = start; i < end; ++i) {
1134 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1135 item->key = sorted_array [i]->key;
1136 item->value = sorted_array [i]->value;
1137 item->has_target_code = sorted_array [i]->has_target_code;
1138 item->is_equals = TRUE;
1140 item->check_target_idx = out_array->len + 1;
1142 item->check_target_idx = 0;
1143 g_ptr_array_add (out_array, item);
1146 int middle = start + count / 2;
1147 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1149 item->key = sorted_array [middle]->key;
1150 item->is_equals = FALSE;
1151 g_ptr_array_add (out_array, item);
1152 imt_emit_ir (sorted_array, start, middle, out_array);
1153 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1159 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1160 int number_of_entries = entries->children + 1;
1161 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1162 GPtrArray *result = g_ptr_array_new ();
1163 MonoImtBuilderEntry *current_entry;
1166 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1167 sorted_array [i] = current_entry;
1169 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1171 /*for (i = 0; i < number_of_entries; i++) {
1172 print_imt_entry (" sorted array:", sorted_array [i], i);
1175 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1177 free (sorted_array);
1182 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1184 if (imt_builder_entry != NULL) {
1185 if (imt_builder_entry->children == 0 && !fail_tramp) {
1186 /* No collision, return the vtable slot contents */
1187 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1189 /* Collision, build the thunk */
1190 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1193 result = imt_thunk_builder (vtable, domain,
1194 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1195 for (i = 0; i < imt_ir->len; ++i)
1196 g_free (g_ptr_array_index (imt_ir, i));
1197 g_ptr_array_free (imt_ir, TRUE);
1209 static MonoImtBuilderEntry*
1210 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1213 * LOCKING: requires the loader and domain locks.
1217 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1221 guint32 imt_collisions_bitmap = 0;
1222 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1223 int method_count = 0;
1224 gboolean record_method_count_for_max_collisions = FALSE;
1225 gboolean has_generic_virtual = FALSE;
1228 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1230 for (i = 0; i < klass->interface_offsets_count; ++i) {
1231 MonoClass *iface = klass->interfaces_packed [i];
1232 int interface_offset = klass->interface_offsets_packed [i];
1233 int method_slot_in_interface;
1234 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1237 if (slot_num >= 0 && iface->is_inflated) {
1239 * The imt slot of the method is the same as for its declaring method,
1240 * see the comment in mono_method_get_imt_slot (), so we can
1241 * avoid inflating methods which will be discarded by
1242 * add_imt_builder_entry anyway.
1244 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1245 if (mono_method_get_imt_slot (method) != slot_num)
1248 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1249 if (method->is_generic) {
1250 has_generic_virtual = TRUE;
1253 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1256 if (extra_interfaces) {
1257 int interface_offset = klass->vtable_size;
1259 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1260 MonoClass* iface = list_item->data;
1261 int method_slot_in_interface;
1262 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1263 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1264 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1266 interface_offset += iface->method.count;
1269 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1270 /* overwrite the imt slot only if we're building all the entries or if
1271 * we're building this specific one
1273 if (slot_num < 0 || i == slot_num) {
1274 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1277 if (imt_builder [i]) {
1278 MonoImtBuilderEntry *entry;
1280 /* Link entries with imt_builder [i] */
1281 for (entry = entries; entry->next; entry = entry->next)
1283 entry->next = imt_builder [i];
1284 entries->children += imt_builder [i]->children + 1;
1286 imt_builder [i] = entries;
1289 if (has_generic_virtual) {
1291 * There might be collisions later when the the thunk is expanded.
1293 imt_collisions_bitmap |= (1 << i);
1296 * The IMT thunk might be called with an instance of one of the
1297 * generic virtual methods, so has to fallback to the IMT trampoline.
1299 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1301 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1305 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1307 if (imt_builder [i] != NULL) {
1308 int methods_in_slot = imt_builder [i]->children + 1;
1309 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1310 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1311 record_method_count_for_max_collisions = TRUE;
1313 method_count += methods_in_slot;
1317 mono_stats.imt_number_of_methods += method_count;
1318 if (record_method_count_for_max_collisions) {
1319 mono_stats.imt_method_count_when_max_collisions = method_count;
1322 for (i = 0; i < MONO_IMT_SIZE; i++) {
1323 MonoImtBuilderEntry* entry = imt_builder [i];
1324 while (entry != NULL) {
1325 MonoImtBuilderEntry* next = entry->next;
1331 /* we OR the bitmap since we may build just a single imt slot at a time */
1332 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1336 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1337 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1341 * mono_vtable_build_imt_slot:
1342 * @vtable: virtual object table struct
1343 * @imt_slot: slot in the IMT table
1345 * Fill the given @imt_slot in the IMT table of @vtable with
1346 * a trampoline or a thunk for the case of collisions.
1347 * This is part of the internal mono API.
1349 * LOCKING: Take the domain lock.
1352 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1354 gpointer *imt = (gpointer*)vtable;
1355 imt -= MONO_IMT_SIZE;
1356 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1358 /* no support for extra interfaces: the proxy objects will need
1359 * to build the complete IMT
1360 * Update and heck needs to ahppen inside the proper domain lock, as all
1361 * the changes made to a MonoVTable.
1363 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1364 mono_domain_lock (vtable->domain);
1365 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1366 if (imt [imt_slot] == imt_trampoline)
1367 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1368 mono_domain_unlock (vtable->domain);
1369 mono_loader_unlock ();
1374 * The first two free list entries both belong to the wait list: The
1375 * first entry is the pointer to the head of the list and the second
1376 * entry points to the last element. That way appending and removing
1377 * the first element are both O(1) operations.
1379 #define NUM_FREE_LISTS 12
1380 #define FIRST_FREE_LIST_SIZE 64
1381 #define MAX_WAIT_LENGTH 50
1382 #define THUNK_THRESHOLD 10
1385 * LOCKING: The domain lock must be held.
1388 init_thunk_free_lists (MonoDomain *domain)
1390 if (domain->thunk_free_lists)
1392 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1396 list_index_for_size (int item_size)
1399 int size = FIRST_FREE_LIST_SIZE;
1401 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1410 * mono_method_alloc_generic_virtual_thunk:
1412 * @size: size in bytes
1414 * Allocs size bytes to be used for the code of a generic virtual
1415 * thunk. It's either allocated from the domain's code manager or
1416 * reused from a previously invalidated piece.
1418 * LOCKING: The domain lock must be held.
1421 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1423 static gboolean inited = FALSE;
1424 static int generic_virtual_thunks_size = 0;
1428 MonoThunkFreeList **l;
1430 init_thunk_free_lists (domain);
1432 size += sizeof (guint32);
1433 if (size < sizeof (MonoThunkFreeList))
1434 size = sizeof (MonoThunkFreeList);
1436 i = list_index_for_size (size);
1437 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1438 if ((*l)->size >= size) {
1439 MonoThunkFreeList *item = *l;
1441 return ((guint32*)item) + 1;
1445 /* no suitable item found - search lists of larger sizes */
1446 while (++i < NUM_FREE_LISTS) {
1447 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1450 g_assert (item->size > size);
1451 domain->thunk_free_lists [i] = item->next;
1452 return ((guint32*)item) + 1;
1455 /* still nothing found - allocate it */
1457 mono_counters_register ("Generic virtual thunk bytes",
1458 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1461 generic_virtual_thunks_size += size;
1463 p = mono_domain_code_reserve (domain, size);
1470 * LOCKING: The domain lock must be held.
1473 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1476 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1478 init_thunk_free_lists (domain);
1480 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1481 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1482 int length = item->length;
1485 /* unlink the first item from the wait list */
1486 domain->thunk_free_lists [0] = item->next;
1487 domain->thunk_free_lists [0]->length = length - 1;
1489 i = list_index_for_size (item->size);
1491 /* put it in the free list */
1492 item->next = domain->thunk_free_lists [i];
1493 domain->thunk_free_lists [i] = item;
1497 if (domain->thunk_free_lists [1]) {
1498 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1499 domain->thunk_free_lists [0]->length++;
1501 g_assert (!domain->thunk_free_lists [0]);
1503 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1504 domain->thunk_free_lists [0]->length = 1;
1508 typedef struct _GenericVirtualCase {
1512 struct _GenericVirtualCase *next;
1513 } GenericVirtualCase;
1516 * get_generic_virtual_entries:
1518 * Return IMT entries for the generic virtual method instances for vtable slot
1521 static MonoImtBuilderEntry*
1522 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1524 GenericVirtualCase *list;
1525 MonoImtBuilderEntry *entries;
1527 mono_domain_lock (domain);
1528 if (!domain->generic_virtual_cases)
1529 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1531 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1534 for (; list; list = list->next) {
1535 MonoImtBuilderEntry *entry;
1537 if (list->count < THUNK_THRESHOLD)
1540 entry = g_new0 (MonoImtBuilderEntry, 1);
1541 entry->key = list->method;
1542 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1543 entry->has_target_code = 1;
1545 entry->children = entries->children + 1;
1546 entry->next = entries;
1550 mono_domain_unlock (domain);
1552 /* FIXME: Leaking memory ? */
1557 * mono_method_add_generic_virtual_invocation:
1559 * @vtable_slot: pointer to the vtable slot
1560 * @method: the inflated generic virtual method
1561 * @code: the method's code
1563 * Registers a call via unmanaged code to a generic virtual method
1564 * instantiation. If the number of calls reaches a threshold
1565 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1566 * virtual method thunk.
1569 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1570 gpointer *vtable_slot,
1571 MonoMethod *method, gpointer code)
1573 static gboolean inited = FALSE;
1574 static int num_added = 0;
1576 GenericVirtualCase *gvc, *list;
1577 MonoImtBuilderEntry *entries;
1581 mono_domain_lock (domain);
1582 if (!domain->generic_virtual_cases)
1583 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1585 /* Check whether the case was already added */
1586 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1589 if (gvc->method == method)
1594 /* If not found, make a new one */
1596 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1597 gvc->method = method;
1600 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1605 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1611 if (++gvc->count == THUNK_THRESHOLD) {
1612 gpointer *old_thunk = *vtable_slot;
1614 if ((gpointer)vtable_slot < (gpointer)vtable)
1615 /* Force the rebuild of the thunk at the next call */
1616 *vtable_slot = imt_trampoline;
1618 entries = get_generic_virtual_entries (domain, vtable_slot);
1620 sorted = imt_sort_slot_entries (entries);
1622 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1626 MonoImtBuilderEntry *next = entries->next;
1631 for (i = 0; i < sorted->len; ++i)
1632 g_free (g_ptr_array_index (sorted, i));
1633 g_ptr_array_free (sorted, TRUE);
1636 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1637 invalidate_generic_virtual_thunk (domain, old_thunk);
1640 mono_domain_unlock (domain);
1643 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1646 * mono_class_vtable:
1647 * @domain: the application domain
1648 * @class: the class to initialize
1650 * VTables are domain specific because we create domain specific code, and
1651 * they contain the domain specific static class data.
1652 * On failure, NULL is returned, and class->exception_type is set.
1655 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1657 MonoClassRuntimeInfo *runtime_info;
1661 /* this check can be inlined in jitted code, too */
1662 runtime_info = class->runtime_info;
1663 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1664 return runtime_info->domain_vtables [domain->domain_id];
1665 if (class->exception_type)
1667 return mono_class_create_runtime_vtable (domain, class);
1671 * mono_class_try_get_vtable:
1672 * @domain: the application domain
1673 * @class: the class to initialize
1675 * This function tries to get the associated vtable from @class if
1676 * it was already created.
1679 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1681 MonoClassRuntimeInfo *runtime_info;
1685 runtime_info = class->runtime_info;
1686 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1687 return runtime_info->domain_vtables [domain->domain_id];
1692 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1695 MonoClassRuntimeInfo *runtime_info, *old_info;
1696 MonoClassField *field;
1699 int imt_table_bytes = 0;
1700 guint32 vtable_size, class_size;
1703 gpointer *interface_offsets;
1705 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1706 mono_domain_lock (domain);
1707 runtime_info = class->runtime_info;
1708 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1709 mono_domain_unlock (domain);
1710 mono_loader_unlock ();
1711 return runtime_info->domain_vtables [domain->domain_id];
1713 if (!class->inited || class->exception_type) {
1714 if (!mono_class_init (class) || class->exception_type){
1716 mono_domain_unlock (domain);
1717 mono_loader_unlock ();
1718 exc = mono_class_get_exception_for_failure (class);
1720 mono_raise_exception (exc);
1724 mono_class_init (class);
1727 * For some classes, mono_class_init () already computed class->vtable_size, and
1728 * that is all that is needed because of the vtable trampolines.
1730 if (!class->vtable_size)
1731 mono_class_setup_vtable (class);
1733 if (class->exception_type) {
1734 mono_domain_unlock (domain);
1735 mono_loader_unlock ();
1740 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1741 if (class->interface_offsets_count) {
1742 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1743 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1744 mono_stats.imt_number_of_tables++;
1745 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1748 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1749 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1752 mono_stats.used_class_count++;
1753 mono_stats.class_vtable_size += vtable_size;
1754 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1757 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1759 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1761 vt->rank = class->rank;
1762 vt->domain = domain;
1764 mono_class_compute_gc_descriptor (class);
1766 * We can't use typed allocation in the non-root domains, since the
1767 * collector needs the GC descriptor stored in the vtable even after
1768 * the mempool containing the vtable is destroyed when the domain is
1769 * unloaded. An alternative might be to allocate vtables in the GC
1770 * heap, but this does not seem to work (it leads to crashes inside
1771 * libgc). If that approach is tried, two gc descriptors need to be
1772 * allocated for each class: one for the root domain, and one for all
1773 * other domains. The second descriptor should contain a bit for the
1774 * vtable field in MonoObject, since we can no longer assume the
1775 * vtable is reachable by other roots after the appdomain is unloaded.
1777 #ifdef HAVE_BOEHM_GC
1778 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1779 vt->gc_descr = GC_NO_DESCRIPTOR;
1782 vt->gc_descr = class->gc_descr;
1784 if ((class_size = mono_class_data_size (class))) {
1785 if (class->has_static_refs) {
1786 gpointer statics_gc_descr;
1788 gsize default_bitmap [4] = {0};
1791 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1792 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1793 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1794 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1795 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1796 if (bitmap != default_bitmap)
1799 vt->data = mono_domain_alloc0 (domain, class_size);
1801 mono_stats.class_static_data_size += class_size;
1806 while ((field = mono_class_get_fields (class, &iter))) {
1807 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1809 if (mono_field_is_deleted (field))
1811 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1812 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1813 if (special_static != SPECIAL_STATIC_NONE) {
1814 guint32 size, offset;
1816 size = mono_type_size (field->type, &align);
1817 offset = mono_alloc_special_static_data (special_static, size, align);
1818 if (!domain->special_static_fields)
1819 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1820 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1824 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1825 MonoClass *fklass = mono_class_from_mono_type (field->type);
1826 const char *data = mono_field_get_data (field);
1828 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1829 t = (char*)vt->data + field->offset;
1830 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1833 if (fklass->valuetype) {
1834 memcpy (t, data, mono_class_value_size (fklass, NULL));
1836 /* it's a pointer type: add check */
1837 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1844 vt->max_interface_id = class->max_interface_id;
1845 vt->interface_bitmap = class->interface_bitmap;
1847 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1848 // class->name, class->interface_offsets_count);
1850 if (! ARCH_USE_IMT) {
1851 /* initialize interface offsets */
1852 for (i = 0; i < class->interface_offsets_count; ++i) {
1853 int interface_id = class->interfaces_packed [i]->interface_id;
1854 int slot = class->interface_offsets_packed [i];
1855 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1859 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1860 * as we change the code in appdomain.c to invalidate vtables by
1861 * looking at the possible MonoClasses created for the domain.
1863 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1864 /* class->runtime_info is protected by the loader lock, both when
1865 * it it enlarged and when it is stored info.
1868 old_info = class->runtime_info;
1869 if (old_info && old_info->max_domain >= domain->domain_id) {
1870 /* someone already created a large enough runtime info */
1871 mono_memory_barrier ();
1872 old_info->domain_vtables [domain->domain_id] = vt;
1874 int new_size = domain->domain_id;
1876 new_size = MAX (new_size, old_info->max_domain);
1878 /* make the new size a power of two */
1880 while (new_size > i)
1883 /* this is a bounded memory retention issue: may want to
1884 * handle it differently when we'll have a rcu-like system.
1886 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1887 runtime_info->max_domain = new_size - 1;
1888 /* copy the stuff from the older info */
1890 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1892 runtime_info->domain_vtables [domain->domain_id] = vt;
1894 mono_memory_barrier ();
1895 class->runtime_info = runtime_info;
1898 /* Initialize vtable */
1899 if (vtable_trampoline) {
1900 // This also covers the AOT case
1901 for (i = 0; i < class->vtable_size; ++i) {
1902 vt->vtable [i] = vtable_trampoline;
1905 mono_class_setup_vtable (class);
1907 for (i = 0; i < class->vtable_size; ++i) {
1910 if ((cm = class->vtable [i]))
1911 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1915 if (ARCH_USE_IMT && imt_table_bytes) {
1916 /* Now that the vtable is full, we can actually fill up the IMT */
1917 if (imt_trampoline) {
1918 /* lazy construction of the IMT entries enabled */
1919 for (i = 0; i < MONO_IMT_SIZE; ++i)
1920 interface_offsets [i] = imt_trampoline;
1922 build_imt (class, vt, domain, interface_offsets, NULL);
1926 mono_domain_unlock (domain);
1927 mono_loader_unlock ();
1929 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1930 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1931 MonoException *exc = mono_class_get_exception_for_failure (class);
1933 mono_raise_exception (exc);
1936 /* make sure the parent is initialized */
1938 mono_class_vtable (domain, class->parent);
1940 vt->type = mono_type_get_object (domain, &class->byval_arg);
1941 if (class->contextbound)
1950 * mono_class_proxy_vtable:
1951 * @domain: the application domain
1952 * @remove_class: the remote class
1954 * Creates a vtable for transparent proxies. It is basically
1955 * a copy of the real vtable of the class wrapped in @remote_class,
1956 * but all function pointers invoke the remoting functions, and
1957 * vtable->klass points to the transparent proxy class, and not to @class.
1960 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1962 MonoVTable *vt, *pvt;
1963 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1965 GSList *extra_interfaces = NULL;
1966 MonoClass *class = remote_class->proxy_class;
1967 gpointer *interface_offsets;
1969 vt = mono_class_vtable (domain, class);
1970 max_interface_id = vt->max_interface_id;
1972 /* Calculate vtable space for extra interfaces */
1973 for (j = 0; j < remote_class->interface_count; j++) {
1974 MonoClass* iclass = remote_class->interfaces[j];
1978 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1979 continue; /* interface implemented by the class */
1980 if (g_slist_find (extra_interfaces, iclass))
1983 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1985 method_count = mono_class_num_methods (iclass);
1987 ifaces = mono_class_get_implemented_interfaces (iclass);
1989 for (i = 0; i < ifaces->len; ++i) {
1990 MonoClass *ic = g_ptr_array_index (ifaces, i);
1991 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1992 continue; /* interface implemented by the class */
1993 if (g_slist_find (extra_interfaces, ic))
1995 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1996 method_count += mono_class_num_methods (ic);
1998 g_ptr_array_free (ifaces, TRUE);
2001 extra_interface_vtsize += method_count * sizeof (gpointer);
2002 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2006 mono_stats.imt_number_of_tables++;
2007 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2008 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2009 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2011 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2012 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
2015 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2017 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2019 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2021 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2022 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
2024 pvt->klass = mono_defaults.transparent_proxy_class;
2025 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2026 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2028 /* initialize vtable */
2029 mono_class_setup_vtable (class);
2030 for (i = 0; i < class->vtable_size; ++i) {
2033 if ((cm = class->vtable [i]))
2034 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2036 pvt->vtable [i] = NULL;
2039 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2040 /* create trampolines for abstract methods */
2041 for (k = class; k; k = k->parent) {
2043 gpointer iter = NULL;
2044 while ((m = mono_class_get_methods (k, &iter)))
2045 if (!pvt->vtable [m->slot])
2046 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2050 pvt->max_interface_id = max_interface_id;
2051 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2053 if (! ARCH_USE_IMT) {
2054 /* initialize interface offsets */
2055 for (i = 0; i < class->interface_offsets_count; ++i) {
2056 int interface_id = class->interfaces_packed [i]->interface_id;
2057 int slot = class->interface_offsets_packed [i];
2058 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2061 for (i = 0; i < class->interface_offsets_count; ++i) {
2062 int interface_id = class->interfaces_packed [i]->interface_id;
2063 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2066 if (extra_interfaces) {
2067 int slot = class->vtable_size;
2073 /* Create trampolines for the methods of the interfaces */
2074 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2075 interf = list_item->data;
2077 if (! ARCH_USE_IMT) {
2078 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2080 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2084 while ((cm = mono_class_get_methods (interf, &iter)))
2085 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2087 slot += mono_class_num_methods (interf);
2089 if (! ARCH_USE_IMT) {
2090 g_slist_free (extra_interfaces);
2095 /* Now that the vtable is full, we can actually fill up the IMT */
2096 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2097 if (extra_interfaces) {
2098 g_slist_free (extra_interfaces);
2106 * mono_class_field_is_special_static:
2108 * Returns whether @field is a thread/context static field.
2111 mono_class_field_is_special_static (MonoClassField *field)
2113 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2115 if (mono_field_is_deleted (field))
2117 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2118 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2125 * mono_class_has_special_static_fields:
2127 * Returns whenever @klass has any thread/context static fields.
2130 mono_class_has_special_static_fields (MonoClass *klass)
2132 MonoClassField *field;
2136 while ((field = mono_class_get_fields (klass, &iter))) {
2137 g_assert (field->parent == klass);
2138 if (mono_class_field_is_special_static (field))
2146 * create_remote_class_key:
2147 * Creates an array of pointers that can be used as a hash key for a remote class.
2148 * The first element of the array is the number of pointers.
2151 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2156 if (remote_class == NULL) {
2157 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2158 key = g_malloc (sizeof(gpointer) * 3);
2159 key [0] = GINT_TO_POINTER (2);
2160 key [1] = mono_defaults.marshalbyrefobject_class;
2161 key [2] = extra_class;
2163 key = g_malloc (sizeof(gpointer) * 2);
2164 key [0] = GINT_TO_POINTER (1);
2165 key [1] = extra_class;
2168 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2169 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2170 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2171 key [1] = remote_class->proxy_class;
2173 // Keep the list of interfaces sorted
2174 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2175 if (extra_class && remote_class->interfaces [i] > extra_class) {
2176 key [j++] = extra_class;
2179 key [j] = remote_class->interfaces [i];
2182 key [j] = extra_class;
2184 // Replace the old class. The interface list is the same
2185 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2186 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2187 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2188 for (i = 0; i < remote_class->interface_count; i++)
2189 key [2 + i] = remote_class->interfaces [i];
2197 * copy_remote_class_key:
2199 * Make a copy of KEY in the domain and return the copy.
2202 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2204 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2205 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2207 memcpy (mp_key, key, key_size);
2213 * mono_remote_class:
2214 * @domain: the application domain
2215 * @class_name: name of the remote class
2217 * Creates and initializes a MonoRemoteClass object for a remote type.
2221 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2223 MonoRemoteClass *rc;
2224 gpointer* key, *mp_key;
2226 key = create_remote_class_key (NULL, proxy_class);
2228 mono_domain_lock (domain);
2229 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2233 mono_domain_unlock (domain);
2237 mp_key = copy_remote_class_key (domain, key);
2241 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2242 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2243 rc->interface_count = 1;
2244 rc->interfaces [0] = proxy_class;
2245 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2247 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2248 rc->interface_count = 0;
2249 rc->proxy_class = proxy_class;
2252 rc->default_vtable = NULL;
2253 rc->xdomain_vtable = NULL;
2254 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2255 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2257 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2259 mono_domain_unlock (domain);
2264 * clone_remote_class:
2265 * Creates a copy of the remote_class, adding the provided class or interface
2267 static MonoRemoteClass*
2268 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2270 MonoRemoteClass *rc;
2271 gpointer* key, *mp_key;
2273 key = create_remote_class_key (remote_class, extra_class);
2274 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2280 mp_key = copy_remote_class_key (domain, key);
2284 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2286 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2287 rc->proxy_class = remote_class->proxy_class;
2288 rc->interface_count = remote_class->interface_count + 1;
2290 // Keep the list of interfaces sorted, since the hash key of
2291 // the remote class depends on this
2292 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2293 if (remote_class->interfaces [i] > extra_class && i == j)
2294 rc->interfaces [j++] = extra_class;
2295 rc->interfaces [j] = remote_class->interfaces [i];
2298 rc->interfaces [j] = extra_class;
2300 // Replace the old class. The interface array is the same
2301 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2302 rc->proxy_class = extra_class;
2303 rc->interface_count = remote_class->interface_count;
2304 if (rc->interface_count > 0)
2305 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2308 rc->default_vtable = NULL;
2309 rc->xdomain_vtable = NULL;
2310 rc->proxy_class_name = remote_class->proxy_class_name;
2312 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2318 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2320 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2321 mono_domain_lock (domain);
2322 if (rp->target_domain_id != -1) {
2323 if (remote_class->xdomain_vtable == NULL)
2324 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2325 mono_domain_unlock (domain);
2326 mono_loader_unlock ();
2327 return remote_class->xdomain_vtable;
2329 if (remote_class->default_vtable == NULL) {
2332 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2333 klass = mono_class_from_mono_type (type);
2334 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2335 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2337 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2340 mono_domain_unlock (domain);
2341 mono_loader_unlock ();
2342 return remote_class->default_vtable;
2346 * mono_upgrade_remote_class:
2347 * @domain: the application domain
2348 * @tproxy: the proxy whose remote class has to be upgraded.
2349 * @klass: class to which the remote class can be casted.
2351 * Updates the vtable of the remote class by adding the necessary method slots
2352 * and interface offsets so it can be safely casted to klass. klass can be a
2353 * class or an interface.
2356 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2358 MonoTransparentProxy *tproxy;
2359 MonoRemoteClass *remote_class;
2360 gboolean redo_vtable;
2362 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2363 mono_domain_lock (domain);
2365 tproxy = (MonoTransparentProxy*) proxy_object;
2366 remote_class = tproxy->remote_class;
2368 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2371 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2372 if (remote_class->interfaces [i] == klass)
2373 redo_vtable = FALSE;
2376 redo_vtable = (remote_class->proxy_class != klass);
2380 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2381 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2384 mono_domain_unlock (domain);
2385 mono_loader_unlock ();
2390 * mono_object_get_virtual_method:
2391 * @obj: object to operate on.
2394 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2395 * the instance of a callvirt of method.
2398 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2401 MonoMethod **vtable;
2403 MonoMethod *res = NULL;
2405 klass = mono_object_class (obj);
2406 if (klass == mono_defaults.transparent_proxy_class) {
2407 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2413 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2416 mono_class_setup_vtable (klass);
2417 vtable = klass->vtable;
2419 if (method->slot == -1) {
2420 /* method->slot might not be set for instances of generic methods */
2421 if (method->is_inflated) {
2422 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2423 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2426 g_assert_not_reached ();
2430 /* check method->slot is a valid index: perform isinstance? */
2431 if (method->slot != -1) {
2432 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2434 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2436 res = vtable [method->slot];
2441 /* It may be an interface, abstract class method or generic method */
2442 if (!res || mono_method_signature (res)->generic_param_count)
2445 /* generic methods demand invoke_with_check */
2446 if (mono_method_signature (res)->generic_param_count)
2447 res = mono_marshal_get_remoting_invoke_with_check (res);
2449 res = mono_marshal_get_remoting_invoke (res);
2451 if (method->is_inflated) {
2452 /* Have to inflate the result */
2453 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2463 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2465 g_error ("runtime invoke called on uninitialized runtime");
2469 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2472 * mono_runtime_invoke:
2473 * @method: method to invoke
2474 * @obJ: object instance
2475 * @params: arguments to the method
2476 * @exc: exception information.
2478 * Invokes the method represented by @method on the object @obj.
2480 * obj is the 'this' pointer, it should be NULL for static
2481 * methods, a MonoObject* for object instances and a pointer to
2482 * the value type for value types.
2484 * The params array contains the arguments to the method with the
2485 * same convention: MonoObject* pointers for object instances and
2486 * pointers to the value type otherwise.
2488 * From unmanaged code you'll usually use the
2489 * mono_runtime_invoke() variant.
2491 * Note that this function doesn't handle virtual methods for
2492 * you, it will exec the exact method you pass: we still need to
2493 * expose a function to lookup the derived class implementation
2494 * of a virtual method (there are examples of this in the code,
2497 * You can pass NULL as the exc argument if you don't want to
2498 * catch exceptions, otherwise, *exc will be set to the exception
2499 * thrown, if any. if an exception is thrown, you can't use the
2500 * MonoObject* result from the function.
2502 * If the method returns a value type, it is boxed in an object
2506 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2508 if (mono_runtime_get_no_exec ())
2509 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2511 return default_mono_runtime_invoke (method, obj, params, exc);
2515 * mono_method_get_unmanaged_thunk:
2516 * @method: method to generate a thunk for.
2518 * Returns an unmanaged->managed thunk that can be used to call
2519 * a managed method directly from C.
2521 * The thunk's C signature closely matches the managed signature:
2523 * C#: public bool Equals (object obj);
2524 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2525 * MonoObject*, MonoException**);
2527 * The 1st ("this") parameter must not be used with static methods:
2529 * C#: public static bool ReferenceEquals (object a, object b);
2530 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2533 * The last argument must be a non-null pointer of a MonoException* pointer.
2534 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2535 * exception has been thrown in managed code. Otherwise it will point
2536 * to the MonoException* caught by the thunk. In this case, the result of
2537 * the thunk is undefined:
2539 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2540 * MonoException *ex = NULL;
2541 * Equals func = mono_method_get_unmanaged_thunk (method);
2542 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2544 * // handle exception
2547 * The calling convention of the thunk matches the platform's default
2548 * convention. This means that under Windows, C declarations must
2549 * contain the __stdcall attribute:
2551 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2552 * MonoObject*, MonoException**);
2556 * Value type arguments and return values are treated as they were objects:
2558 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2559 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2561 * Arguments must be properly boxed upon trunk's invocation, while return
2562 * values must be unboxed.
2565 mono_method_get_unmanaged_thunk (MonoMethod *method)
2567 method = mono_marshal_get_thunk_invoke_wrapper (method);
2568 return mono_compile_method (method);
2572 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2576 gpointer *p = (gpointer*)dest;
2583 case MONO_TYPE_BOOLEAN:
2585 case MONO_TYPE_U1: {
2586 guint8 *p = (guint8*)dest;
2587 *p = value ? *(guint8*)value : 0;
2592 case MONO_TYPE_CHAR: {
2593 guint16 *p = (guint16*)dest;
2594 *p = value ? *(guint16*)value : 0;
2597 #if SIZEOF_VOID_P == 4
2602 case MONO_TYPE_U4: {
2603 gint32 *p = (gint32*)dest;
2604 *p = value ? *(gint32*)value : 0;
2607 #if SIZEOF_VOID_P == 8
2612 case MONO_TYPE_U8: {
2613 gint64 *p = (gint64*)dest;
2614 *p = value ? *(gint64*)value : 0;
2617 case MONO_TYPE_R4: {
2618 float *p = (float*)dest;
2619 *p = value ? *(float*)value : 0;
2622 case MONO_TYPE_R8: {
2623 double *p = (double*)dest;
2624 *p = value ? *(double*)value : 0;
2627 case MONO_TYPE_STRING:
2628 case MONO_TYPE_SZARRAY:
2629 case MONO_TYPE_CLASS:
2630 case MONO_TYPE_OBJECT:
2631 case MONO_TYPE_ARRAY:
2632 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2634 case MONO_TYPE_FNPTR:
2635 case MONO_TYPE_PTR: {
2636 gpointer *p = (gpointer*)dest;
2637 *p = deref_pointer? *(gpointer*)value: value;
2640 case MONO_TYPE_VALUETYPE:
2641 /* note that 't' and 'type->type' can be different */
2642 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2643 t = mono_class_enum_basetype (type->data.klass)->type;
2647 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2649 memset (dest, 0, size);
2651 memcpy (dest, value, size);
2654 case MONO_TYPE_GENERICINST:
2655 t = type->data.generic_class->container_class->byval_arg.type;
2658 g_warning ("got type %x", type->type);
2659 g_assert_not_reached ();
2664 * mono_field_set_value:
2665 * @obj: Instance object
2666 * @field: MonoClassField describing the field to set
2667 * @value: The value to be set
2669 * Sets the value of the field described by @field in the object instance @obj
2670 * to the value passed in @value. This method should only be used for instance
2671 * fields. For static fields, use mono_field_static_set_value.
2673 * The value must be on the native format of the field type.
2676 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2680 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2682 dest = (char*)obj + field->offset;
2683 set_value (field->type, dest, value, FALSE);
2687 * mono_field_static_set_value:
2688 * @field: MonoClassField describing the field to set
2689 * @value: The value to be set
2691 * Sets the value of the static field described by @field
2692 * to the value passed in @value.
2694 * The value must be on the native format of the field type.
2697 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2701 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2702 /* you cant set a constant! */
2703 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2705 dest = (char*)vt->data + field->offset;
2706 set_value (field->type, dest, value, FALSE);
2709 /* Used by the debugger */
2711 mono_vtable_get_static_field_data (MonoVTable *vt)
2717 * mono_field_get_value:
2718 * @obj: Object instance
2719 * @field: MonoClassField describing the field to fetch information from
2720 * @value: pointer to the location where the value will be stored
2722 * Use this routine to get the value of the field @field in the object
2725 * The pointer provided by value must be of the field type, for reference
2726 * types this is a MonoObject*, for value types its the actual pointer to
2731 * mono_field_get_value (obj, int_field, &i);
2734 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2738 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2740 src = (char*)obj + field->offset;
2741 set_value (field->type, value, src, TRUE);
2745 * mono_field_get_value_object:
2746 * @domain: domain where the object will be created (if boxing)
2747 * @field: MonoClassField describing the field to fetch information from
2748 * @obj: The object instance for the field.
2750 * Returns: a new MonoObject with the value from the given field. If the
2751 * field represents a value type, the value is boxed.
2755 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2759 MonoVTable *vtable = NULL;
2761 gboolean is_static = FALSE;
2762 gboolean is_ref = FALSE;
2764 switch (field->type->type) {
2765 case MONO_TYPE_STRING:
2766 case MONO_TYPE_OBJECT:
2767 case MONO_TYPE_CLASS:
2768 case MONO_TYPE_ARRAY:
2769 case MONO_TYPE_SZARRAY:
2774 case MONO_TYPE_BOOLEAN:
2777 case MONO_TYPE_CHAR:
2786 case MONO_TYPE_VALUETYPE:
2787 is_ref = field->type->byref;
2789 case MONO_TYPE_GENERICINST:
2790 is_ref = !field->type->data.generic_class->container_class->valuetype;
2793 g_error ("type 0x%x not handled in "
2794 "mono_field_get_value_object", field->type->type);
2798 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2800 vtable = mono_class_vtable (domain, field->parent);
2801 if (!vtable->initialized)
2802 mono_runtime_class_init (vtable);
2807 mono_field_static_get_value (vtable, field, &o);
2809 mono_field_get_value (obj, field, &o);
2814 /* boxed value type */
2815 klass = mono_class_from_mono_type (field->type);
2816 o = mono_object_new (domain, klass);
2817 v = ((gchar *) o) + sizeof (MonoObject);
2819 mono_field_static_get_value (vtable, field, v);
2821 mono_field_get_value (obj, field, v);
2828 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2831 const char *p = blob;
2832 mono_metadata_decode_blob_size (p, &p);
2835 case MONO_TYPE_BOOLEAN:
2838 *(guint8 *) value = *p;
2840 case MONO_TYPE_CHAR:
2843 *(guint16*) value = read16 (p);
2847 *(guint32*) value = read32 (p);
2851 *(guint64*) value = read64 (p);
2854 readr4 (p, (float*) value);
2857 readr8 (p, (double*) value);
2859 case MONO_TYPE_STRING:
2860 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2862 case MONO_TYPE_CLASS:
2863 *(gpointer*) value = NULL;
2867 g_warning ("type 0x%02x should not be in constant table", type);
2873 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2875 MonoTypeEnum def_type;
2878 data = mono_class_get_field_default_value (field, &def_type);
2879 mono_get_constant_value_from_blob (domain, def_type, data, value);
2883 * mono_field_static_get_value:
2884 * @vt: vtable to the object
2885 * @field: MonoClassField describing the field to fetch information from
2886 * @value: where the value is returned
2888 * Use this routine to get the value of the static field @field value.
2890 * The pointer provided by value must be of the field type, for reference
2891 * types this is a MonoObject*, for value types its the actual pointer to
2896 * mono_field_static_get_value (vt, int_field, &i);
2899 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2903 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2905 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2906 get_default_field_value (vt->domain, field, value);
2910 src = (char*)vt->data + field->offset;
2911 set_value (field->type, value, src, TRUE);
2915 * mono_property_set_value:
2916 * @prop: MonoProperty to set
2917 * @obj: instance object on which to act
2918 * @params: parameters to pass to the propery
2919 * @exc: optional exception
2921 * Invokes the property's set method with the given arguments on the
2922 * object instance obj (or NULL for static properties).
2924 * You can pass NULL as the exc argument if you don't want to
2925 * catch exceptions, otherwise, *exc will be set to the exception
2926 * thrown, if any. if an exception is thrown, you can't use the
2927 * MonoObject* result from the function.
2930 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2932 default_mono_runtime_invoke (prop->set, obj, params, exc);
2936 * mono_property_get_value:
2937 * @prop: MonoProperty to fetch
2938 * @obj: instance object on which to act
2939 * @params: parameters to pass to the propery
2940 * @exc: optional exception
2942 * Invokes the property's get method with the given arguments on the
2943 * object instance obj (or NULL for static properties).
2945 * You can pass NULL as the exc argument if you don't want to
2946 * catch exceptions, otherwise, *exc will be set to the exception
2947 * thrown, if any. if an exception is thrown, you can't use the
2948 * MonoObject* result from the function.
2950 * Returns: the value from invoking the get method on the property.
2953 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2955 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2959 * mono_nullable_init:
2960 * @buf: The nullable structure to initialize.
2961 * @value: the value to initialize from
2962 * @klass: the type for the object
2964 * Initialize the nullable structure pointed to by @buf from @value which
2965 * should be a boxed value type. The size of @buf should be able to hold
2966 * as much data as the @klass->instance_size (which is the number of bytes
2967 * that will be copies).
2969 * Since Nullables have variable structure, we can not define a C
2970 * structure for them.
2973 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2975 MonoClass *param_class = klass->cast_class;
2977 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2978 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2980 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2982 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2984 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2988 * mono_nullable_box:
2989 * @buf: The buffer representing the data to be boxed
2990 * @klass: the type to box it as.
2992 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2996 mono_nullable_box (guint8 *buf, MonoClass *klass)
2998 MonoClass *param_class = klass->cast_class;
3000 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3001 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3003 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3004 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3005 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3013 * mono_get_delegate_invoke:
3014 * @klass: The delegate class
3016 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3019 mono_get_delegate_invoke (MonoClass *klass)
3023 /* This is called at runtime, so avoid the slower search in metadata */
3024 mono_class_setup_methods (klass);
3026 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3033 * mono_runtime_delegate_invoke:
3034 * @delegate: pointer to a delegate object.
3035 * @params: parameters for the delegate.
3036 * @exc: Pointer to the exception result.
3038 * Invokes the delegate method @delegate with the parameters provided.
3040 * You can pass NULL as the exc argument if you don't want to
3041 * catch exceptions, otherwise, *exc will be set to the exception
3042 * thrown, if any. if an exception is thrown, you can't use the
3043 * MonoObject* result from the function.
3046 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3050 im = mono_get_delegate_invoke (delegate->vtable->klass);
3053 return mono_runtime_invoke (im, delegate, params, exc);
3056 static char **main_args = NULL;
3057 static int num_main_args;
3060 * mono_runtime_get_main_args:
3062 * Returns: a MonoArray with the arguments passed to the main program
3065 mono_runtime_get_main_args (void)
3069 MonoDomain *domain = mono_domain_get ();
3074 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3076 for (i = 0; i < num_main_args; ++i)
3077 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3083 fire_process_exit_event (void)
3085 MonoClassField *field;
3086 MonoDomain *domain = mono_domain_get ();
3088 MonoObject *delegate, *exc;
3090 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3093 if (domain != mono_get_root_domain ())
3096 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3097 if (delegate == NULL)
3102 mono_runtime_delegate_invoke (delegate, pa, &exc);
3106 * mono_runtime_run_main:
3107 * @method: the method to start the application with (usually Main)
3108 * @argc: number of arguments from the command line
3109 * @argv: array of strings from the command line
3110 * @exc: excetption results
3112 * Execute a standard Main() method (argc/argv contains the
3113 * executable name). This method also sets the command line argument value
3114 * needed by System.Environment.
3119 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3123 MonoArray *args = NULL;
3124 MonoDomain *domain = mono_domain_get ();
3125 gchar *utf8_fullpath;
3128 g_assert (method != NULL);
3130 mono_thread_set_main (mono_thread_current ());
3132 main_args = g_new0 (char*, argc);
3133 num_main_args = argc;
3135 if (!g_path_is_absolute (argv [0])) {
3136 gchar *basename = g_path_get_basename (argv [0]);
3137 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3141 utf8_fullpath = mono_utf8_from_external (fullpath);
3142 if(utf8_fullpath == NULL) {
3143 /* Printing the arg text will cause glib to
3144 * whinge about "Invalid UTF-8", but at least
3145 * its relevant, and shows the problem text
3148 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3149 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3156 utf8_fullpath = mono_utf8_from_external (argv[0]);
3157 if(utf8_fullpath == NULL) {
3158 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3159 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3164 main_args [0] = utf8_fullpath;
3166 for (i = 1; i < argc; ++i) {
3169 utf8_arg=mono_utf8_from_external (argv[i]);
3170 if(utf8_arg==NULL) {
3171 /* Ditto the comment about Invalid UTF-8 here */
3172 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3173 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3177 main_args [i] = utf8_arg;
3181 if (mono_method_signature (method)->param_count) {
3182 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3183 for (i = 0; i < argc; ++i) {
3184 /* The encodings should all work, given that
3185 * we've checked all these args for the
3188 gchar *str = mono_utf8_from_external (argv [i]);
3189 MonoString *arg = mono_string_new (domain, str);
3190 mono_array_setref (args, i, arg);
3194 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3197 mono_assembly_set_main (method->klass->image->assembly);
3199 result = mono_runtime_exec_main (method, args, exc);
3200 fire_process_exit_event ();
3204 /* Used in call_unhandled_exception_delegate */
3206 create_unhandled_exception_eventargs (MonoObject *exc)
3210 MonoMethod *method = NULL;
3211 MonoBoolean is_terminating = TRUE;
3214 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3217 mono_class_init (klass);
3219 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3220 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3224 args [1] = &is_terminating;
3226 obj = mono_object_new (mono_domain_get (), klass);
3227 mono_runtime_invoke (method, obj, args, NULL);
3232 /* Used in mono_unhandled_exception */
3234 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3235 MonoObject *e = NULL;
3238 pa [0] = domain->domain;
3239 pa [1] = create_unhandled_exception_eventargs (exc);
3240 mono_runtime_delegate_invoke (delegate, pa, &e);
3243 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3244 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3249 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3252 * mono_runtime_unhandled_exception_policy_set:
3253 * @policy: the new policy
3255 * This is a VM internal routine.
3257 * Sets the runtime policy for handling unhandled exceptions.
3260 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3261 runtime_unhandled_exception_policy = policy;
3265 * mono_runtime_unhandled_exception_policy_get:
3267 * This is a VM internal routine.
3269 * Gets the runtime policy for handling unhandled exceptions.
3271 MonoRuntimeUnhandledExceptionPolicy
3272 mono_runtime_unhandled_exception_policy_get (void) {
3273 return runtime_unhandled_exception_policy;
3277 * mono_unhandled_exception:
3278 * @exc: exception thrown
3280 * This is a VM internal routine.
3282 * We call this function when we detect an unhandled exception
3283 * in the default domain.
3285 * It invokes the * UnhandledException event in AppDomain or prints
3286 * a warning to the console
3289 mono_unhandled_exception (MonoObject *exc)
3291 MonoDomain *current_domain = mono_domain_get ();
3292 MonoDomain *root_domain = mono_get_root_domain ();
3293 MonoClassField *field;
3294 MonoObject *current_appdomain_delegate;
3295 MonoObject *root_appdomain_delegate;
3297 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3298 "UnhandledException");
3301 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3302 gboolean abort_process = (mono_thread_current () == main_thread) ||
3303 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3304 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3305 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3306 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3308 current_appdomain_delegate = NULL;
3311 /* set exitcode only if we will abort the process */
3313 mono_environment_exitcode_set (1);
3314 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3315 mono_print_unhandled_exception (exc);
3317 if (root_appdomain_delegate) {
3318 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3320 if (current_appdomain_delegate) {
3321 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3328 * Launch a new thread to execute a function
3330 * main_func is called back from the thread with main_args as the
3331 * parameter. The callback function is expected to start Main()
3332 * eventually. This function then waits for all managed threads to
3334 * It is not necesseray anymore to execute managed code in a subthread,
3335 * so this function should not be used anymore by default: just
3336 * execute the code and then call mono_thread_manage ().
3339 mono_runtime_exec_managed_code (MonoDomain *domain,
3340 MonoMainThreadFunc main_func,
3343 mono_thread_create (domain, main_func, main_args);
3345 mono_thread_manage ();
3349 * Execute a standard Main() method (args doesn't contain the
3353 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3358 MonoCustomAttrInfo* cinfo;
3359 gboolean has_stathread_attribute;
3360 MonoThread* thread = mono_thread_current ();
3366 domain = mono_object_domain (args);
3367 if (!domain->entry_assembly) {
3369 MonoAssembly *assembly;
3371 assembly = method->klass->image->assembly;
3372 domain->entry_assembly = assembly;
3373 /* Domains created from another domain already have application_base and configuration_file set */
3374 if (domain->setup->application_base == NULL) {
3375 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3378 if (domain->setup->configuration_file == NULL) {
3379 str = g_strconcat (assembly->image->name, ".config", NULL);
3380 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3382 mono_set_private_bin_path_from_config (domain);
3386 cinfo = mono_custom_attrs_from_method (method);
3388 static MonoClass *stathread_attribute = NULL;
3389 if (!stathread_attribute)
3390 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3391 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3393 mono_custom_attrs_free (cinfo);
3395 has_stathread_attribute = FALSE;
3397 if (has_stathread_attribute) {
3398 thread->apartment_state = ThreadApartmentState_STA;
3399 } else if (mono_framework_version () == 1) {
3400 thread->apartment_state = ThreadApartmentState_Unknown;
3402 thread->apartment_state = ThreadApartmentState_MTA;
3404 mono_thread_init_apartment_state ();
3406 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3408 /* FIXME: check signature of method */
3409 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3411 res = mono_runtime_invoke (method, NULL, pa, exc);
3413 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3417 mono_environment_exitcode_set (rval);
3419 mono_runtime_invoke (method, NULL, pa, exc);
3423 /* If the return type of Main is void, only
3424 * set the exitcode if an exception was thrown
3425 * (we don't want to blow away an
3426 * explicitly-set exit code)
3429 mono_environment_exitcode_set (rval);
3433 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3439 * mono_install_runtime_invoke:
3440 * @func: Function to install
3442 * This is a VM internal routine
3445 mono_install_runtime_invoke (MonoInvokeFunc func)
3447 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3452 * mono_runtime_invoke_array:
3453 * @method: method to invoke
3454 * @obJ: object instance
3455 * @params: arguments to the method
3456 * @exc: exception information.
3458 * Invokes the method represented by @method on the object @obj.
3460 * obj is the 'this' pointer, it should be NULL for static
3461 * methods, a MonoObject* for object instances and a pointer to
3462 * the value type for value types.
3464 * The params array contains the arguments to the method with the
3465 * same convention: MonoObject* pointers for object instances and
3466 * pointers to the value type otherwise. The _invoke_array
3467 * variant takes a C# object[] as the params argument (MonoArray
3468 * *params): in this case the value types are boxed inside the
3469 * respective reference representation.
3471 * From unmanaged code you'll usually use the
3472 * mono_runtime_invoke() variant.
3474 * Note that this function doesn't handle virtual methods for
3475 * you, it will exec the exact method you pass: we still need to
3476 * expose a function to lookup the derived class implementation
3477 * of a virtual method (there are examples of this in the code,
3480 * You can pass NULL as the exc argument if you don't want to
3481 * catch exceptions, otherwise, *exc will be set to the exception
3482 * thrown, if any. if an exception is thrown, you can't use the
3483 * MonoObject* result from the function.
3485 * If the method returns a value type, it is boxed in an object
3489 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3492 MonoMethodSignature *sig = mono_method_signature (method);
3493 gpointer *pa = NULL;
3496 gboolean has_byref_nullables = FALSE;
3498 if (NULL != params) {
3499 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3500 for (i = 0; i < mono_array_length (params); i++) {
3501 MonoType *t = sig->params [i];
3507 case MONO_TYPE_BOOLEAN:
3510 case MONO_TYPE_CHAR:
3519 case MONO_TYPE_VALUETYPE:
3520 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3521 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3522 pa [i] = mono_array_get (params, MonoObject*, i);
3524 has_byref_nullables = TRUE;
3526 /* MS seems to create the objects if a null is passed in */
3527 if (!mono_array_get (params, MonoObject*, i))
3528 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3532 * We can't pass the unboxed vtype byref to the callee, since
3533 * that would mean the callee would be able to modify boxed
3534 * primitive types. So we (and MS) make a copy of the boxed
3535 * object, pass that to the callee, and replace the original
3536 * boxed object in the arg array with the copy.
3538 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3539 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3540 mono_array_setref (params, i, copy);
3543 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3546 case MONO_TYPE_STRING:
3547 case MONO_TYPE_OBJECT:
3548 case MONO_TYPE_CLASS:
3549 case MONO_TYPE_ARRAY:
3550 case MONO_TYPE_SZARRAY:
3552 pa [i] = mono_array_addr (params, MonoObject*, i);
3553 // FIXME: I need to check this code path
3555 pa [i] = mono_array_get (params, MonoObject*, i);
3557 case MONO_TYPE_GENERICINST:
3559 t = &t->data.generic_class->container_class->this_arg;
3561 t = &t->data.generic_class->container_class->byval_arg;
3564 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3569 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3572 if (mono_class_is_nullable (method->klass)) {
3573 /* Need to create a boxed vtype instead */
3579 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3583 obj = mono_object_new (mono_domain_get (), method->klass);
3584 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3585 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3587 if (method->klass->valuetype)
3588 o = mono_object_unbox (obj);
3591 } else if (method->klass->valuetype) {
3592 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3595 mono_runtime_invoke (method, o, pa, exc);
3598 if (mono_class_is_nullable (method->klass)) {
3599 MonoObject *nullable;
3601 /* Convert the unboxed vtype into a Nullable structure */
3602 nullable = mono_object_new (mono_domain_get (), method->klass);
3604 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3605 obj = mono_object_unbox (nullable);
3608 /* obj must be already unboxed if needed */
3609 res = mono_runtime_invoke (method, obj, pa, exc);
3611 if (has_byref_nullables) {
3613 * The runtime invoke wrapper already converted byref nullables back,
3614 * and stored them in pa, we just need to copy them back to the
3617 for (i = 0; i < mono_array_length (params); i++) {
3618 MonoType *t = sig->params [i];
3620 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3621 mono_array_setref (params, i, pa [i]);
3630 arith_overflow (void)
3632 mono_raise_exception (mono_get_exception_overflow ());
3636 * mono_object_allocate:
3637 * @size: number of bytes to allocate
3639 * This is a very simplistic routine until we have our GC-aware
3642 * Returns: an allocated object of size @size, or NULL on failure.
3644 static inline void *
3645 mono_object_allocate (size_t size, MonoVTable *vtable)
3648 mono_stats.new_object_count++;
3649 ALLOC_OBJECT (o, vtable, size);
3655 * mono_object_allocate_ptrfree:
3656 * @size: number of bytes to allocate
3658 * Note that the memory allocated is not zeroed.
3659 * Returns: an allocated object of size @size, or NULL on failure.
3661 static inline void *
3662 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3665 mono_stats.new_object_count++;
3666 ALLOC_PTRFREE (o, vtable, size);
3670 static inline void *
3671 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3674 ALLOC_TYPED (o, size, vtable);
3675 mono_stats.new_object_count++;
3682 * @klass: the class of the object that we want to create
3684 * Returns: a newly created object whose definition is
3685 * looked up using @klass. This will not invoke any constructors,
3686 * so the consumer of this routine has to invoke any constructors on
3687 * its own to initialize the object.
3690 mono_object_new (MonoDomain *domain, MonoClass *klass)
3692 MONO_ARCH_SAVE_REGS;
3693 return mono_object_new_specific (mono_class_vtable (domain, klass));
3697 * mono_object_new_specific:
3698 * @vtable: the vtable of the object that we want to create
3700 * Returns: A newly created object with class and domain specified
3704 mono_object_new_specific (MonoVTable *vtable)
3708 MONO_ARCH_SAVE_REGS;
3710 /* check for is_com_object for COM Interop */
3711 if (vtable->remote || vtable->klass->is_com_object)
3714 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3717 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3720 mono_class_init (klass);
3722 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3724 vtable->domain->create_proxy_for_type_method = im;
3727 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3729 o = mono_runtime_invoke (im, NULL, pa, NULL);
3730 if (o != NULL) return o;
3733 return mono_object_new_alloc_specific (vtable);
3737 mono_object_new_alloc_specific (MonoVTable *vtable)
3741 if (!vtable->klass->has_references) {
3742 o = mono_object_new_ptrfree (vtable);
3743 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3744 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3746 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3747 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3749 if (G_UNLIKELY (vtable->klass->has_finalize))
3750 mono_object_register_finalizer (o);
3752 if (G_UNLIKELY (profile_allocs))
3753 mono_profiler_allocation (o, vtable->klass);
3758 mono_object_new_fast (MonoVTable *vtable)
3761 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3766 mono_object_new_ptrfree (MonoVTable *vtable)
3769 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3770 #if NEED_TO_ZERO_PTRFREE
3771 /* an inline memset is much faster for the common vcase of small objects
3772 * note we assume the allocated size is a multiple of sizeof (void*).
3774 if (vtable->klass->instance_size < 128) {
3776 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3777 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3783 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3790 mono_object_new_ptrfree_box (MonoVTable *vtable)
3793 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3794 /* the object will be boxed right away, no need to memzero it */
3799 * mono_class_get_allocation_ftn:
3801 * @for_box: the object will be used for boxing
3802 * @pass_size_in_words:
3804 * Return the allocation function appropriate for the given class.
3808 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3810 *pass_size_in_words = FALSE;
3812 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3813 profile_allocs = FALSE;
3815 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3816 return mono_object_new_specific;
3818 if (!vtable->klass->has_references) {
3819 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3821 return mono_object_new_ptrfree_box;
3822 return mono_object_new_ptrfree;
3825 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3827 return mono_object_new_fast;
3830 * FIXME: This is actually slower than mono_object_new_fast, because
3831 * of the overhead of parameter passing.
3834 *pass_size_in_words = TRUE;
3835 #ifdef GC_REDIRECT_TO_LOCAL
3836 return GC_local_gcj_fast_malloc;
3838 return GC_gcj_fast_malloc;
3843 return mono_object_new_specific;
3847 * mono_object_new_from_token:
3848 * @image: Context where the type_token is hosted
3849 * @token: a token of the type that we want to create
3851 * Returns: A newly created object whose definition is
3852 * looked up using @token in the @image image
3855 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3859 class = mono_class_get (image, token);
3861 return mono_object_new (domain, class);
3866 * mono_object_clone:
3867 * @obj: the object to clone
3869 * Returns: A newly created object who is a shallow copy of @obj
3872 mono_object_clone (MonoObject *obj)
3877 size = obj->vtable->klass->instance_size;
3878 o = mono_object_allocate (size, obj->vtable);
3879 /* do not copy the sync state */
3880 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3883 if (obj->vtable->klass->has_references)
3884 mono_gc_wbarrier_object (o);
3886 if (G_UNLIKELY (profile_allocs))
3887 mono_profiler_allocation (o, obj->vtable->klass);
3889 if (obj->vtable->klass->has_finalize)
3890 mono_object_register_finalizer (o);
3895 * mono_array_full_copy:
3896 * @src: source array to copy
3897 * @dest: destination array
3899 * Copies the content of one array to another with exactly the same type and size.
3902 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3904 mono_array_size_t size;
3905 MonoClass *klass = src->obj.vtable->klass;
3907 MONO_ARCH_SAVE_REGS;
3909 g_assert (klass == dest->obj.vtable->klass);
3911 size = mono_array_length (src);
3912 g_assert (size == mono_array_length (dest));
3913 size *= mono_array_element_size (klass);
3915 if (klass->element_class->valuetype) {
3916 if (klass->element_class->has_references)
3917 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3919 memcpy (&dest->vector, &src->vector, size);
3921 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3924 memcpy (&dest->vector, &src->vector, size);
3929 * mono_array_clone_in_domain:
3930 * @domain: the domain in which the array will be cloned into
3931 * @array: the array to clone
3933 * This routine returns a copy of the array that is hosted on the
3934 * specified MonoDomain.
3937 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3940 mono_array_size_t size, i;
3941 mono_array_size_t *sizes;
3942 MonoClass *klass = array->obj.vtable->klass;
3944 MONO_ARCH_SAVE_REGS;
3946 if (array->bounds == NULL) {
3947 size = mono_array_length (array);
3948 o = mono_array_new_full (domain, klass, &size, NULL);
3950 size *= mono_array_element_size (klass);
3952 if (klass->element_class->valuetype) {
3953 if (klass->element_class->has_references)
3954 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3956 memcpy (&o->vector, &array->vector, size);
3958 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3961 memcpy (&o->vector, &array->vector, size);
3966 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3967 size = mono_array_element_size (klass);
3968 for (i = 0; i < klass->rank; ++i) {
3969 sizes [i] = array->bounds [i].length;
3970 size *= array->bounds [i].length;
3971 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3973 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3975 if (klass->element_class->valuetype) {
3976 if (klass->element_class->has_references)
3977 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3979 memcpy (&o->vector, &array->vector, size);
3981 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3984 memcpy (&o->vector, &array->vector, size);
3992 * @array: the array to clone
3994 * Returns: A newly created array who is a shallow copy of @array
3997 mono_array_clone (MonoArray *array)
3999 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4002 /* helper macros to check for overflow when calculating the size of arrays */
4003 #ifdef MONO_BIG_ARRAYS
4004 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4005 #define MYGUINT_MAX MYGUINT64_MAX
4006 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4007 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4008 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4009 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4010 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4012 #define MYGUINT32_MAX 4294967295U
4013 #define MYGUINT_MAX MYGUINT32_MAX
4014 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4015 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4016 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4017 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4018 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4022 * mono_array_new_full:
4023 * @domain: domain where the object is created
4024 * @array_class: array class
4025 * @lengths: lengths for each dimension in the array
4026 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4028 * This routine creates a new array objects with the given dimensions,
4029 * lower bounds and type.
4032 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4034 mono_array_size_t byte_len, len, bounds_size;
4040 if (!array_class->inited)
4041 mono_class_init (array_class);
4043 byte_len = mono_array_element_size (array_class);
4046 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4047 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4049 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4053 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4055 for (i = 0; i < array_class->rank; ++i) {
4056 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4058 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4059 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4064 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4065 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4067 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4068 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4069 byte_len += sizeof (MonoArray);
4072 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4073 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4074 byte_len = (byte_len + 3) & ~3;
4075 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4076 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4077 byte_len += bounds_size;
4080 * Following three lines almost taken from mono_object_new ():
4081 * they need to be kept in sync.
4083 vtable = mono_class_vtable (domain, array_class);
4084 if (!array_class->has_references) {
4085 o = mono_object_allocate_ptrfree (byte_len, vtable);
4086 #if NEED_TO_ZERO_PTRFREE
4087 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4089 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4090 o = mono_object_allocate_spec (byte_len, vtable);
4092 o = mono_object_allocate (byte_len, vtable);
4095 array = (MonoArray*)o;
4096 array->max_length = len;
4099 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4100 array->bounds = bounds;
4101 for (i = 0; i < array_class->rank; ++i) {
4102 bounds [i].length = lengths [i];
4104 bounds [i].lower_bound = lower_bounds [i];
4108 if (G_UNLIKELY (profile_allocs))
4109 mono_profiler_allocation (o, array_class);
4116 * @domain: domain where the object is created
4117 * @eclass: element class
4118 * @n: number of array elements
4120 * This routine creates a new szarray with @n elements of type @eclass.
4123 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4127 MONO_ARCH_SAVE_REGS;
4129 ac = mono_array_class_get (eclass, 1);
4132 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4136 * mono_array_new_specific:
4137 * @vtable: a vtable in the appropriate domain for an initialized class
4138 * @n: number of array elements
4140 * This routine is a fast alternative to mono_array_new() for code which
4141 * can be sure about the domain it operates in.
4144 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4148 guint32 byte_len, elem_size;
4150 MONO_ARCH_SAVE_REGS;
4152 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4157 elem_size = mono_array_element_size (vtable->klass);
4158 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4159 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4162 byte_len = n * elem_size;
4163 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4164 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4167 byte_len += sizeof (MonoArray);
4168 if (!vtable->klass->has_references) {
4169 o = mono_object_allocate_ptrfree (byte_len, vtable);
4170 #if NEED_TO_ZERO_PTRFREE
4171 ((MonoArray*)o)->bounds = NULL;
4172 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4174 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4175 o = mono_object_allocate_spec (byte_len, vtable);
4177 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4178 o = mono_object_allocate (byte_len, vtable);
4181 ao = (MonoArray *)o;
4183 if (G_UNLIKELY (profile_allocs))
4184 mono_profiler_allocation (o, vtable->klass);
4190 * mono_string_new_utf16:
4191 * @text: a pointer to an utf16 string
4192 * @len: the length of the string
4194 * Returns: A newly created string object which contains @text.
4197 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4201 s = mono_string_new_size (domain, len);
4202 g_assert (s != NULL);
4204 memcpy (mono_string_chars (s), text, len * 2);
4210 * mono_string_new_size:
4211 * @text: a pointer to an utf16 string
4212 * @len: the length of the string
4214 * Returns: A newly created string object of @len
4217 mono_string_new_size (MonoDomain *domain, gint32 len)
4221 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4223 /* overflow ? can't fit it, can't allocate it! */
4225 mono_gc_out_of_memory (-1);
4227 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4229 s = mono_object_allocate_ptrfree (size, vtable);
4232 #if NEED_TO_ZERO_PTRFREE
4235 if (G_UNLIKELY (profile_allocs))
4236 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4242 * mono_string_new_len:
4243 * @text: a pointer to an utf8 string
4244 * @length: number of bytes in @text to consider
4246 * Returns: A newly created string object which contains @text.
4249 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4251 GError *error = NULL;
4252 MonoString *o = NULL;
4254 glong items_written;
4256 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4259 o = mono_string_new_utf16 (domain, ut, items_written);
4261 g_error_free (error);
4270 * @text: a pointer to an utf8 string
4272 * Returns: A newly created string object which contains @text.
4275 mono_string_new (MonoDomain *domain, const char *text)
4277 GError *error = NULL;
4278 MonoString *o = NULL;
4280 glong items_written;
4285 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4288 o = mono_string_new_utf16 (domain, ut, items_written);
4290 g_error_free (error);
4293 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4298 MonoString *o = NULL;
4300 if (!g_utf8_validate (text, -1, &end))
4303 len = g_utf8_strlen (text, -1);
4304 o = mono_string_new_size (domain, len);
4305 str = mono_string_chars (o);
4307 while (text < end) {
4308 *str++ = g_utf8_get_char (text);
4309 text = g_utf8_next_char (text);
4316 * mono_string_new_wrapper:
4317 * @text: pointer to utf8 characters.
4319 * Helper function to create a string object from @text in the current domain.
4322 mono_string_new_wrapper (const char *text)
4324 MonoDomain *domain = mono_domain_get ();
4326 MONO_ARCH_SAVE_REGS;
4329 return mono_string_new (domain, text);
4336 * @class: the class of the value
4337 * @value: a pointer to the unboxed data
4339 * Returns: A newly created object which contains @value.
4342 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4348 g_assert (class->valuetype);
4349 if (mono_class_is_nullable (class))
4350 return mono_nullable_box (value, class);
4352 vtable = mono_class_vtable (domain, class);
4353 size = mono_class_instance_size (class);
4354 res = mono_object_new_alloc_specific (vtable);
4355 if (G_UNLIKELY (profile_allocs))
4356 mono_profiler_allocation (res, class);
4358 size = size - sizeof (MonoObject);
4361 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4364 #if NO_UNALIGNED_ACCESS
4365 memcpy ((char *)res + sizeof (MonoObject), value, size);
4369 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4372 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4375 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4378 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4381 memcpy ((char *)res + sizeof (MonoObject), value, size);
4384 if (class->has_finalize)
4385 mono_object_register_finalizer (res);
4391 * @dest: destination pointer
4392 * @src: source pointer
4393 * @klass: a valuetype class
4395 * Copy a valuetype from @src to @dest. This function must be used
4396 * when @klass contains references fields.
4399 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4401 int size = mono_class_value_size (klass, NULL);
4402 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4403 memcpy (dest, src, size);
4407 * mono_value_copy_array:
4408 * @dest: destination array
4409 * @dest_idx: index in the @dest array
4410 * @src: source pointer
4411 * @count: number of items
4413 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4414 * This function must be used when @klass contains references fields.
4415 * Overlap is handled.
4418 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4420 int size = mono_array_element_size (dest->obj.vtable->klass);
4421 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4422 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4423 memmove (d, src, size * count);
4427 * mono_object_get_domain:
4428 * @obj: object to query
4430 * Returns: the MonoDomain where the object is hosted
4433 mono_object_get_domain (MonoObject *obj)
4435 return mono_object_domain (obj);
4439 * mono_object_get_class:
4440 * @obj: object to query
4442 * Returns: the MonOClass of the object.
4445 mono_object_get_class (MonoObject *obj)
4447 return mono_object_class (obj);
4450 * mono_object_get_size:
4451 * @o: object to query
4453 * Returns: the size, in bytes, of @o
4456 mono_object_get_size (MonoObject* o)
4458 MonoClass* klass = mono_object_class (o);
4459 if (klass == mono_defaults.string_class) {
4460 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4461 } else if (o->vtable->rank) {
4462 MonoArray *array = (MonoArray*)o;
4463 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4464 if (array->bounds) {
4467 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4471 return mono_class_instance_size (klass);
4476 * mono_object_unbox:
4477 * @obj: object to unbox
4479 * Returns: a pointer to the start of the valuetype boxed in this
4482 * This method will assert if the object passed is not a valuetype.
4485 mono_object_unbox (MonoObject *obj)
4487 /* add assert for valuetypes? */
4488 g_assert (obj->vtable->klass->valuetype);
4489 return ((char*)obj) + sizeof (MonoObject);
4493 * mono_object_isinst:
4495 * @klass: a pointer to a class
4497 * Returns: @obj if @obj is derived from @klass
4500 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4503 mono_class_init (klass);
4505 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4506 return mono_object_isinst_mbyref (obj, klass);
4511 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4515 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4524 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4525 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4529 MonoClass *oklass = vt->klass;
4530 if ((oklass == mono_defaults.transparent_proxy_class))
4531 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4533 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4537 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4539 MonoDomain *domain = mono_domain_get ();
4541 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4542 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4543 MonoMethod *im = NULL;
4546 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4547 im = mono_object_get_virtual_method (rp, im);
4550 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4553 res = mono_runtime_invoke (im, rp, pa, NULL);
4555 if (*(MonoBoolean *) mono_object_unbox(res)) {
4556 /* Update the vtable of the remote type, so it can safely cast to this new type */
4557 mono_upgrade_remote_class (domain, obj, klass);
4566 * mono_object_castclass_mbyref:
4568 * @klass: a pointer to a class
4570 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4573 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4575 if (!obj) return NULL;
4576 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4578 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4580 "InvalidCastException"));
4585 MonoDomain *orig_domain;
4591 str_lookup (MonoDomain *domain, gpointer user_data)
4593 LDStrInfo *info = user_data;
4594 if (info->res || domain == info->orig_domain)
4596 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4602 mono_string_get_pinned (MonoString *str)
4606 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4607 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4608 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4609 news->length = mono_string_length (str);
4614 #define mono_string_get_pinned(str) (str)
4618 mono_string_is_interned_lookup (MonoString *str, int insert)
4620 MonoGHashTable *ldstr_table;
4624 domain = ((MonoObject *)str)->vtable->domain;
4625 ldstr_table = domain->ldstr_table;
4627 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4632 str = mono_string_get_pinned (str);
4633 mono_g_hash_table_insert (ldstr_table, str, str);
4637 LDStrInfo ldstr_info;
4638 ldstr_info.orig_domain = domain;
4639 ldstr_info.ins = str;
4640 ldstr_info.res = NULL;
4642 mono_domain_foreach (str_lookup, &ldstr_info);
4643 if (ldstr_info.res) {
4645 * the string was already interned in some other domain:
4646 * intern it in the current one as well.
4648 mono_g_hash_table_insert (ldstr_table, str, str);
4658 * mono_string_is_interned:
4659 * @o: String to probe
4661 * Returns whether the string has been interned.
4664 mono_string_is_interned (MonoString *o)
4666 return mono_string_is_interned_lookup (o, FALSE);
4670 * mono_string_intern:
4671 * @o: String to intern
4673 * Interns the string passed.
4674 * Returns: The interned string.
4677 mono_string_intern (MonoString *str)
4679 return mono_string_is_interned_lookup (str, TRUE);
4684 * @domain: the domain where the string will be used.
4685 * @image: a metadata context
4686 * @idx: index into the user string table.
4688 * Implementation for the ldstr opcode.
4689 * Returns: a loaded string from the @image/@idx combination.
4692 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4694 MONO_ARCH_SAVE_REGS;
4697 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4699 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4703 * mono_ldstr_metadata_sig
4704 * @domain: the domain for the string
4705 * @sig: the signature of a metadata string
4707 * Returns: a MonoString for a string stored in the metadata
4710 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4712 const char *str = sig;
4713 MonoString *o, *interned;
4716 len2 = mono_metadata_decode_blob_size (str, &str);
4719 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4720 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4723 guint16 *p2 = (guint16*)mono_string_chars (o);
4724 for (i = 0; i < len2; ++i) {
4725 *p2 = GUINT16_FROM_LE (*p2);
4731 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4733 /* o will get garbage collected */
4737 o = mono_string_get_pinned (o);
4738 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4745 * mono_string_to_utf8:
4746 * @s: a System.String
4748 * Return the UTF8 representation for @s.
4749 * the resulting buffer nedds to be freed with g_free().
4752 mono_string_to_utf8 (MonoString *s)
4756 GError *error = NULL;
4762 return g_strdup ("");
4764 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4766 MonoException *exc = mono_get_exception_argument ("string", error->message);
4767 g_error_free (error);
4768 mono_raise_exception(exc);
4770 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4771 if (s->length > written) {
4772 /* allocate the total length and copy the part of the string that has been converted */
4773 char *as2 = g_malloc0 (s->length);
4774 memcpy (as2, as, written);
4783 * mono_string_to_utf16:
4786 * Return an null-terminated array of the utf-16 chars
4787 * contained in @s. The result must be freed with g_free().
4788 * This is a temporary helper until our string implementation
4789 * is reworked to always include the null terminating char.
4792 mono_string_to_utf16 (MonoString *s)
4799 as = g_malloc ((s->length * 2) + 2);
4800 as [(s->length * 2)] = '\0';
4801 as [(s->length * 2) + 1] = '\0';
4804 return (gunichar2 *)(as);
4807 memcpy (as, mono_string_chars(s), s->length * 2);
4808 return (gunichar2 *)(as);
4812 * mono_string_from_utf16:
4813 * @data: the UTF16 string (LPWSTR) to convert
4815 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4817 * Returns: a MonoString.
4820 mono_string_from_utf16 (gunichar2 *data)
4822 MonoDomain *domain = mono_domain_get ();
4828 while (data [len]) len++;
4830 return mono_string_new_utf16 (domain, data, len);
4835 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4842 return mono_string_to_utf8 (s);
4844 r = mono_string_to_utf8 (s);
4848 len = strlen (r) + 1;
4850 mp_s = mono_mempool_alloc (mp, len);
4852 mp_s = mono_image_alloc (image, len);
4854 memcpy (mp_s, r, len);
4862 * mono_string_to_utf8_image:
4863 * @s: a System.String
4865 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4868 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4870 return mono_string_to_utf8_internal (NULL, image, s);
4874 * mono_string_to_utf8_mp:
4875 * @s: a System.String
4877 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4880 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4882 return mono_string_to_utf8_internal (mp, NULL, s);
4886 default_ex_handler (MonoException *ex)
4888 MonoObject *o = (MonoObject*)ex;
4889 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4893 static MonoExceptionFunc ex_handler = default_ex_handler;
4896 * mono_install_handler:
4897 * @func: exception handler
4899 * This is an internal JIT routine used to install the handler for exceptions
4903 mono_install_handler (MonoExceptionFunc func)
4905 ex_handler = func? func: default_ex_handler;
4909 * mono_raise_exception:
4910 * @ex: exception object
4912 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4915 mono_raise_exception (MonoException *ex)
4918 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4919 * that will cause gcc to omit the function epilog, causing problems when
4920 * the JIT tries to walk the stack, since the return address on the stack
4921 * will point into the next function in the executable, not this one.
4924 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4925 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4931 * mono_wait_handle_new:
4932 * @domain: Domain where the object will be created
4933 * @handle: Handle for the wait handle
4935 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4938 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4940 MonoWaitHandle *res;
4941 gpointer params [1];
4942 static MonoMethod *handle_set;
4944 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4946 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4948 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4950 params [0] = &handle;
4951 mono_runtime_invoke (handle_set, res, params, NULL);
4957 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4959 static MonoClassField *f_os_handle;
4960 static MonoClassField *f_safe_handle;
4962 if (!f_os_handle && !f_safe_handle) {
4963 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4964 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4969 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4973 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4980 mono_runtime_capture_context (MonoDomain *domain)
4982 RuntimeInvokeFunction runtime_invoke;
4984 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
4985 MonoMethod *method = mono_get_context_capture_method ();
4986 MonoMethod *wrapper;
4989 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
4990 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
4991 domain->capture_context_method = mono_compile_method (method);
4994 runtime_invoke = domain->capture_context_runtime_invoke;
4996 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
4999 * mono_async_result_new:
5000 * @domain:domain where the object will be created.
5001 * @handle: wait handle.
5002 * @state: state to pass to AsyncResult
5003 * @data: C closure data.
5005 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5006 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5010 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5012 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5013 MonoObject *context = mono_runtime_capture_context (domain);
5014 /* we must capture the execution context from the original thread */
5016 MONO_OBJECT_SETREF (res, execution_context, context);
5017 /* note: result may be null if the flow is suppressed */
5021 MONO_OBJECT_SETREF (res, object_data, object_data);
5022 MONO_OBJECT_SETREF (res, async_state, state);
5024 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5026 res->sync_completed = FALSE;
5027 res->completed = FALSE;
5033 mono_message_init (MonoDomain *domain,
5034 MonoMethodMessage *this,
5035 MonoReflectionMethod *method,
5036 MonoArray *out_args)
5038 static MonoClass *object_array_klass;
5039 static MonoClass *byte_array_klass;
5040 static MonoClass *string_array_klass;
5041 MonoMethodSignature *sig = mono_method_signature (method->method);
5047 if (!object_array_klass) {
5050 klass = mono_array_class_get (mono_defaults.object_class, 1);
5053 mono_memory_barrier ();
5054 object_array_klass = klass;
5056 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5059 mono_memory_barrier ();
5060 byte_array_klass = klass;
5062 klass = mono_array_class_get (mono_defaults.string_class, 1);
5065 mono_memory_barrier ();
5066 string_array_klass = klass;
5069 MONO_OBJECT_SETREF (this, method, method);
5071 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5072 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5073 this->async_result = NULL;
5074 this->call_type = CallType_Sync;
5076 names = g_new (char *, sig->param_count);
5077 mono_method_get_param_names (method->method, (const char **) names);
5078 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5080 for (i = 0; i < sig->param_count; i++) {
5081 name = mono_string_new (domain, names [i]);
5082 mono_array_setref (this->names, i, name);
5086 for (i = 0, j = 0; i < sig->param_count; i++) {
5087 if (sig->params [i]->byref) {
5089 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5090 mono_array_setref (this->args, i, arg);
5094 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5098 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5101 mono_array_set (this->arg_types, guint8, i, arg_type);
5106 * mono_remoting_invoke:
5107 * @real_proxy: pointer to a RealProxy object
5108 * @msg: The MonoMethodMessage to execute
5109 * @exc: used to store exceptions
5110 * @out_args: used to store output arguments
5112 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5113 * IMessage interface and it is not trivial to extract results from there. So
5114 * we call an helper method PrivateInvoke instead of calling
5115 * RealProxy::Invoke() directly.
5117 * Returns: the result object.
5120 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5121 MonoObject **exc, MonoArray **out_args)
5123 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5126 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5129 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5131 real_proxy->vtable->domain->private_invoke_method = im;
5134 pa [0] = real_proxy;
5139 return mono_runtime_invoke (im, NULL, pa, exc);
5143 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5144 MonoObject **exc, MonoArray **out_args)
5146 static MonoClass *object_array_klass;
5149 MonoMethodSignature *sig;
5151 int i, j, outarg_count = 0;
5153 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5155 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5156 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5157 target = tp->rp->unwrapped_server;
5159 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5163 domain = mono_domain_get ();
5164 method = msg->method->method;
5165 sig = mono_method_signature (method);
5167 for (i = 0; i < sig->param_count; i++) {
5168 if (sig->params [i]->byref)
5172 if (!object_array_klass) {
5175 klass = mono_array_class_get (mono_defaults.object_class, 1);
5178 mono_memory_barrier ();
5179 object_array_klass = klass;
5182 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5183 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5186 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5188 for (i = 0, j = 0; i < sig->param_count; i++) {
5189 if (sig->params [i]->byref) {
5191 arg = mono_array_get (msg->args, gpointer, i);
5192 mono_array_setref (*out_args, j, arg);
5201 * mono_print_unhandled_exception:
5202 * @exc: The exception
5204 * Prints the unhandled exception.
5207 mono_print_unhandled_exception (MonoObject *exc)
5209 char *message = (char *) "";
5213 gboolean free_message = FALSE;
5215 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5216 klass = exc->vtable->klass;
5218 while (klass && method == NULL) {
5219 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5221 klass = klass->parent;
5226 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5228 message = mono_string_to_utf8 (str);
5229 free_message = TRUE;
5234 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5235 * exc->vtable->klass->name, message);
5237 g_printerr ("\nUnhandled Exception: %s\n", message);
5244 * mono_delegate_ctor:
5245 * @this: pointer to an uninitialized delegate object
5246 * @target: target object
5247 * @addr: pointer to native code
5250 * Initialize a delegate and sets a specific method, not the one
5251 * associated with addr. This is useful when sharing generic code.
5252 * In that case addr will most probably not be associated with the
5253 * correct instantiation of the method.
5256 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5258 MonoDelegate *delegate = (MonoDelegate *)this;
5265 delegate->method = method;
5267 class = this->vtable->klass;
5268 mono_stats.delegate_creations++;
5270 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5272 method = mono_marshal_get_remoting_invoke (method);
5273 delegate->method_ptr = mono_compile_method (method);
5274 MONO_OBJECT_SETREF (delegate, target, target);
5275 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5276 method = mono_marshal_get_unbox_wrapper (method);
5277 delegate->method_ptr = mono_compile_method (method);
5278 MONO_OBJECT_SETREF (delegate, target, target);
5280 delegate->method_ptr = addr;
5281 MONO_OBJECT_SETREF (delegate, target, target);
5284 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5288 * mono_delegate_ctor:
5289 * @this: pointer to an uninitialized delegate object
5290 * @target: target object
5291 * @addr: pointer to native code
5293 * This is used to initialize a delegate.
5296 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5298 MonoDomain *domain = mono_domain_get ();
5300 MonoMethod *method = NULL;
5304 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5305 method = ji->method;
5306 g_assert (!method->klass->generic_container);
5309 mono_delegate_ctor_with_method (this, target, addr, method);
5313 * mono_method_call_message_new:
5314 * @method: method to encapsulate
5315 * @params: parameters to the method
5316 * @invoke: optional, delegate invoke.
5317 * @cb: async callback delegate.
5318 * @state: state passed to the async callback.
5320 * Translates arguments pointers into a MonoMethodMessage.
5323 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5324 MonoDelegate **cb, MonoObject **state)
5326 MonoDomain *domain = mono_domain_get ();
5327 MonoMethodSignature *sig = mono_method_signature (method);
5328 MonoMethodMessage *msg;
5331 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5334 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5335 count = sig->param_count - 2;
5337 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5338 count = sig->param_count;
5341 for (i = 0; i < count; i++) {
5346 if (sig->params [i]->byref)
5347 vpos = *((gpointer *)params [i]);
5351 type = sig->params [i]->type;
5352 class = mono_class_from_mono_type (sig->params [i]);
5354 if (class->valuetype)
5355 arg = mono_value_box (domain, class, vpos);
5357 arg = *((MonoObject **)vpos);
5359 mono_array_setref (msg->args, i, arg);
5362 if (cb != NULL && state != NULL) {
5363 *cb = *((MonoDelegate **)params [i]);
5365 *state = *((MonoObject **)params [i]);
5372 * mono_method_return_message_restore:
5374 * Restore results from message based processing back to arguments pointers
5377 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5379 MonoMethodSignature *sig = mono_method_signature (method);
5380 int i, j, type, size, out_len;
5382 if (out_args == NULL)
5384 out_len = mono_array_length (out_args);
5388 for (i = 0, j = 0; i < sig->param_count; i++) {
5389 MonoType *pt = sig->params [i];
5394 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5396 arg = mono_array_get (out_args, gpointer, j);
5400 case MONO_TYPE_VOID:
5401 g_assert_not_reached ();
5405 case MONO_TYPE_BOOLEAN:
5408 case MONO_TYPE_CHAR:
5415 case MONO_TYPE_VALUETYPE: {
5417 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5418 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5421 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5422 memset (*((gpointer *)params [i]), 0, size);
5426 case MONO_TYPE_STRING:
5427 case MONO_TYPE_CLASS:
5428 case MONO_TYPE_ARRAY:
5429 case MONO_TYPE_SZARRAY:
5430 case MONO_TYPE_OBJECT:
5431 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5434 g_assert_not_reached ();
5443 * mono_load_remote_field:
5444 * @this: pointer to an object
5445 * @klass: klass of the object containing @field
5446 * @field: the field to load
5447 * @res: a storage to store the result
5449 * This method is called by the runtime on attempts to load fields of
5450 * transparent proxy objects. @this points to such TP, @klass is the class of
5451 * the object containing @field. @res is a storage location which can be
5452 * used to store the result.
5454 * Returns: an address pointing to the value of field.
5457 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5459 static MonoMethod *getter = NULL;
5460 MonoDomain *domain = mono_domain_get ();
5461 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5462 MonoClass *field_class;
5463 MonoMethodMessage *msg;
5464 MonoArray *out_args;
5468 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5469 g_assert (res != NULL);
5471 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5472 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5477 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5481 field_class = mono_class_from_mono_type (field->type);
5483 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5484 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5485 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5487 full_name = mono_type_get_full_name (klass);
5488 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5489 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5492 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5494 if (exc) mono_raise_exception ((MonoException *)exc);
5496 if (mono_array_length (out_args) == 0)
5499 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5501 if (field_class->valuetype) {
5502 return ((char *)*res) + sizeof (MonoObject);
5508 * mono_load_remote_field_new:
5513 * Missing documentation.
5516 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5518 static MonoMethod *getter = NULL;
5519 MonoDomain *domain = mono_domain_get ();
5520 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5521 MonoClass *field_class;
5522 MonoMethodMessage *msg;
5523 MonoArray *out_args;
5524 MonoObject *exc, *res;
5527 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5529 field_class = mono_class_from_mono_type (field->type);
5531 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5533 if (field_class->valuetype) {
5534 res = mono_object_new (domain, field_class);
5535 val = ((gchar *) res) + sizeof (MonoObject);
5539 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5544 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5548 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5549 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5551 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5553 full_name = mono_type_get_full_name (klass);
5554 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5555 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5558 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5560 if (exc) mono_raise_exception ((MonoException *)exc);
5562 if (mono_array_length (out_args) == 0)
5565 res = mono_array_get (out_args, MonoObject *, 0);
5571 * mono_store_remote_field:
5572 * @this: pointer to an object
5573 * @klass: klass of the object containing @field
5574 * @field: the field to load
5575 * @val: the value/object to store
5577 * This method is called by the runtime on attempts to store fields of
5578 * transparent proxy objects. @this points to such TP, @klass is the class of
5579 * the object containing @field. @val is the new value to store in @field.
5582 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5584 static MonoMethod *setter = NULL;
5585 MonoDomain *domain = mono_domain_get ();
5586 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5587 MonoClass *field_class;
5588 MonoMethodMessage *msg;
5589 MonoArray *out_args;
5594 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5596 field_class = mono_class_from_mono_type (field->type);
5598 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5599 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5600 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5605 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5609 if (field_class->valuetype)
5610 arg = mono_value_box (domain, field_class, val);
5612 arg = *((MonoObject **)val);
5615 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5616 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5618 full_name = mono_type_get_full_name (klass);
5619 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5620 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5621 mono_array_setref (msg->args, 2, arg);
5624 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5626 if (exc) mono_raise_exception ((MonoException *)exc);
5630 * mono_store_remote_field_new:
5636 * Missing documentation
5639 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5641 static MonoMethod *setter = NULL;
5642 MonoDomain *domain = mono_domain_get ();
5643 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5644 MonoClass *field_class;
5645 MonoMethodMessage *msg;
5646 MonoArray *out_args;
5650 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5652 field_class = mono_class_from_mono_type (field->type);
5654 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5655 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5656 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5661 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5665 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5666 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5668 full_name = mono_type_get_full_name (klass);
5669 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5670 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5671 mono_array_setref (msg->args, 2, arg);
5674 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5676 if (exc) mono_raise_exception ((MonoException *)exc);
5680 * mono_create_ftnptr:
5682 * Given a function address, create a function descriptor for it.
5683 * This is only needed on IA64 and PPC64.
5686 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5691 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
5697 #elif defined(__ppc64__) || defined(__powerpc64__)
5700 desc = mono_domain_code_reserve (domain, 3 * sizeof (gpointer));
5713 * mono_get_addr_from_ftnptr:
5715 * Given a pointer to a function descriptor, return the function address.
5716 * This is only needed on IA64 and PPC64.
5719 mono_get_addr_from_ftnptr (gpointer descr)
5721 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5722 return *(gpointer*)descr;
5730 * mono_string_chars:
5733 * Returns a pointer to the UCS16 characters stored in the MonoString
5736 mono_string_chars(MonoString *s)
5738 /* This method is here only for documentation extraction, this is a macro */
5742 * mono_string_length:
5745 * Returns the lenght in characters of the string
5748 mono_string_length (MonoString *s)
5750 /* This method is here only for documentation extraction, this is a macro */