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 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
961 #define mix(a,b,c) { \
962 a -= c; a ^= rot(c, 4); c += b; \
963 b -= a; b ^= rot(a, 6); a += c; \
964 c -= b; c ^= rot(b, 8); b += a; \
965 a -= c; a ^= rot(c,16); c += b; \
966 b -= a; b ^= rot(a,19); a += c; \
967 c -= b; c ^= rot(b, 4); b += a; \
969 #define final(a,b,c) { \
970 c ^= b; c -= rot(b,14); \
971 a ^= c; a -= rot(c,11); \
972 b ^= a; b -= rot(a,25); \
973 c ^= b; c -= rot(b,16); \
974 a ^= c; a -= rot(c,4); \
975 b ^= a; b -= rot(a,14); \
976 c ^= b; c -= rot(b,24); \
980 mono_method_get_imt_slot (MonoMethod *method) {
981 MonoMethodSignature *sig;
983 guint32 *hashes_start, *hashes;
988 * We do this to simplify generic sharing. It will hurt
989 * performance in cases where a class implements two different
990 * instantiations of the same generic interface.
991 * The code in build_imt_slots () depends on this.
993 if (method->is_inflated)
994 method = ((MonoMethodInflated*)method)->declaring;
996 sig = mono_method_signature (method);
997 hashes_count = sig->param_count + 4;
998 hashes_start = malloc (hashes_count * sizeof (guint32));
999 hashes = hashes_start;
1001 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1002 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1003 method->klass->name_space, method->klass->name, method->name);
1004 g_assert_not_reached ();
1007 /* Initialize hashes */
1008 hashes [0] = g_str_hash (method->klass->name);
1009 hashes [1] = g_str_hash (method->klass->name_space);
1010 hashes [2] = g_str_hash (method->name);
1011 hashes [3] = mono_metadata_type_hash (sig->ret);
1012 for (i = 0; i < sig->param_count; i++) {
1013 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1016 /* Setup internal state */
1017 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1019 /* Handle most of the hashes */
1020 while (hashes_count > 3) {
1029 /* Handle the last 3 hashes (all the case statements fall through) */
1030 switch (hashes_count) {
1031 case 3 : c += hashes [2];
1032 case 2 : b += hashes [1];
1033 case 1 : a += hashes [0];
1035 case 0: /* nothing left to add */
1039 free (hashes_start);
1040 /* Report the result */
1041 return c % MONO_IMT_SIZE;
1050 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1051 guint32 imt_slot = mono_method_get_imt_slot (method);
1052 MonoImtBuilderEntry *entry;
1054 if (slot_num >= 0 && imt_slot != slot_num) {
1055 /* we build just a single imt slot and this is not it */
1059 entry = malloc (sizeof (MonoImtBuilderEntry));
1060 entry->key = method;
1061 entry->value.vtable_slot = vtable_slot;
1062 entry->next = imt_builder [imt_slot];
1063 if (imt_builder [imt_slot] != NULL) {
1064 entry->children = imt_builder [imt_slot]->children + 1;
1065 if (entry->children == 1) {
1066 mono_stats.imt_slots_with_collisions++;
1067 *imt_collisions_bitmap |= (1 << imt_slot);
1070 entry->children = 0;
1071 mono_stats.imt_used_slots++;
1073 imt_builder [imt_slot] = entry;
1075 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1076 method, method->klass->name_space, method->klass->name,
1077 method->name, imt_slot, vtable_slot, entry->children);
1083 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1085 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1089 e->method->klass->name_space,
1090 e->method->klass->name,
1093 printf (" * %s: NULL\n", message);
1099 compare_imt_builder_entries (const void *p1, const void *p2) {
1100 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1101 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1103 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1107 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1109 int count = end - start;
1110 int chunk_start = out_array->len;
1113 for (i = start; i < end; ++i) {
1114 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1115 item->key = sorted_array [i]->key;
1116 item->value = sorted_array [i]->value;
1117 item->is_equals = TRUE;
1119 item->check_target_idx = out_array->len + 1;
1121 item->check_target_idx = 0;
1122 g_ptr_array_add (out_array, item);
1125 int middle = start + count / 2;
1126 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1128 item->key = sorted_array [middle]->key;
1129 item->is_equals = FALSE;
1130 g_ptr_array_add (out_array, item);
1131 imt_emit_ir (sorted_array, start, middle, out_array);
1132 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1138 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1139 int number_of_entries = entries->children + 1;
1140 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1141 GPtrArray *result = g_ptr_array_new ();
1142 MonoImtBuilderEntry *current_entry;
1145 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1146 sorted_array [i] = current_entry;
1148 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1150 /*for (i = 0; i < number_of_entries; i++) {
1151 print_imt_entry (" sorted array:", sorted_array [i], i);
1154 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1156 free (sorted_array);
1161 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1162 if (imt_builder_entry != NULL) {
1163 if (imt_builder_entry->children == 0) {
1164 /* No collision, return the vtable slot contents */
1165 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1167 /* Collision, build the thunk */
1168 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1171 result = imt_thunk_builder (vtable, domain,
1172 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, NULL);
1173 for (i = 0; i < imt_ir->len; ++i)
1174 g_free (g_ptr_array_index (imt_ir, i));
1175 g_ptr_array_free (imt_ir, TRUE);
1185 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1188 guint32 imt_collisions_bitmap = 0;
1189 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1190 int method_count = 0;
1191 gboolean record_method_count_for_max_collisions = FALSE;
1194 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1196 for (i = 0; i < klass->interface_offsets_count; ++i) {
1197 MonoClass *iface = klass->interfaces_packed [i];
1198 int interface_offset = klass->interface_offsets_packed [i];
1199 int method_slot_in_interface;
1200 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1203 if (slot_num >= 0 && iface->is_inflated) {
1205 * The imt slot of the method is the same as for its declaring method,
1206 * see the comment in mono_method_get_imt_slot (), so we can
1207 * avoid inflating methods which will be discarded by
1208 * add_imt_builder_entry anyway.
1210 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1211 if (mono_method_get_imt_slot (method) != slot_num)
1214 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1215 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1218 if (extra_interfaces) {
1219 int interface_offset = klass->vtable_size;
1221 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1222 MonoClass* iface = list_item->data;
1223 int method_slot_in_interface;
1224 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1225 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1226 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1228 interface_offset += iface->method.count;
1231 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1232 /* overwrite the imt slot only if we're building all the entries or if
1233 * we're uilding this specific one
1235 if (slot_num < 0 || i == slot_num)
1236 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1238 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1240 if (imt_builder [i] != NULL) {
1241 int methods_in_slot = imt_builder [i]->children + 1;
1242 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1243 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1244 record_method_count_for_max_collisions = TRUE;
1246 method_count += methods_in_slot;
1250 mono_stats.imt_number_of_methods += method_count;
1251 if (record_method_count_for_max_collisions) {
1252 mono_stats.imt_method_count_when_max_collisions = method_count;
1255 for (i = 0; i < MONO_IMT_SIZE; i++) {
1256 MonoImtBuilderEntry* entry = imt_builder [i];
1257 while (entry != NULL) {
1258 MonoImtBuilderEntry* next = entry->next;
1264 /* we OR the bitmap since we may build just a single imt slot at a time */
1265 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1269 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1270 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1273 static gpointer imt_trampoline = NULL;
1276 mono_install_imt_trampoline (gpointer tramp_code)
1278 imt_trampoline = tramp_code;
1281 static gpointer vtable_trampoline = NULL;
1284 mono_install_vtable_trampoline (gpointer tramp_code)
1286 vtable_trampoline = tramp_code;
1290 * mono_vtable_build_imt_slot:
1291 * @vtable: virtual object table struct
1292 * @imt_slot: slot in the IMT table
1294 * Fill the given @imt_slot in the IMT table of @vtable with
1295 * a trampoline or a thunk for the case of collisions.
1296 * This is part of the internal mono API.
1299 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1301 gpointer *imt = (gpointer*)vtable;
1302 imt -= MONO_IMT_SIZE;
1303 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1305 /* no support for extra interfaces: the proxy objects will need
1306 * to build the complete IMT
1307 * Update and heck needs to ahppen inside the proper domain lock, as all
1308 * the changes made to a MonoVTable.
1310 mono_domain_lock (vtable->domain);
1311 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1312 if (imt [imt_slot] == imt_trampoline)
1313 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1314 mono_domain_unlock (vtable->domain);
1319 * The first two free list entries both belong to the wait list: The
1320 * first entry is the pointer to the head of the list and the second
1321 * entry points to the last element. That way appending and removing
1322 * the first element are both O(1) operations.
1324 #define NUM_FREE_LISTS 12
1325 #define FIRST_FREE_LIST_SIZE 64
1326 #define MAX_WAIT_LENGTH 50
1327 #define THUNK_THRESHOLD 10
1330 * LOCKING: The domain lock must be held.
1333 init_thunk_free_lists (MonoDomain *domain)
1335 if (domain->thunk_free_lists)
1337 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1341 list_index_for_size (int item_size)
1344 int size = FIRST_FREE_LIST_SIZE;
1346 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1355 * mono_method_alloc_generic_virtual_thunk:
1357 * @size: size in bytes
1359 * Allocs size bytes to be used for the code of a generic virtual
1360 * thunk. It's either allocated from the domain's code manager or
1361 * reused from a previously invalidated piece.
1363 * LOCKING: The domain lock must be held.
1366 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1368 static gboolean inited = FALSE;
1369 static int generic_virtual_thunks_size = 0;
1373 MonoThunkFreeList **l;
1375 init_thunk_free_lists (domain);
1377 size += sizeof (guint32);
1378 if (size < sizeof (MonoThunkFreeList))
1379 size = sizeof (MonoThunkFreeList);
1381 i = list_index_for_size (size);
1382 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1383 if ((*l)->size >= size) {
1384 MonoThunkFreeList *item = *l;
1386 return ((guint32*)item) + 1;
1390 /* no suitable item found - search lists of larger sizes */
1391 while (++i < NUM_FREE_LISTS) {
1392 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1395 g_assert (item->size > size);
1396 domain->thunk_free_lists [i] = item->next;
1397 return ((guint32*)item) + 1;
1400 /* still nothing found - allocate it */
1402 mono_counters_register ("Generic virtual thunk bytes",
1403 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1406 generic_virtual_thunks_size += size;
1408 p = mono_code_manager_reserve (domain->code_mp, size);
1415 * LOCKING: The domain lock must be held.
1418 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1421 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1423 init_thunk_free_lists (domain);
1425 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1426 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1427 int length = item->length;
1430 /* unlink the first item from the wait list */
1431 domain->thunk_free_lists [0] = item->next;
1432 domain->thunk_free_lists [0]->length = length - 1;
1434 i = list_index_for_size (item->size);
1436 /* put it in the free list */
1437 item->next = domain->thunk_free_lists [i];
1438 domain->thunk_free_lists [i] = item;
1442 if (domain->thunk_free_lists [1]) {
1443 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1444 domain->thunk_free_lists [0]->length++;
1446 g_assert (!domain->thunk_free_lists [0]);
1448 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1449 domain->thunk_free_lists [0]->length = 1;
1453 typedef struct _GenericVirtualCase {
1454 MonoGenericInst *inst;
1457 struct _GenericVirtualCase *next;
1458 } GenericVirtualCase;
1461 * mono_method_add_generic_virtual_invocation:
1463 * @vtable_slot: pointer to the vtable slot
1464 * @method_inst: the method's method_inst
1465 * @code: the method's code
1467 * Registers a call via unmanaged code to a generic virtual method
1468 * instantiation. If the number of calls reaches a threshold
1469 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1470 * virtual method thunk.
1473 mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable_slot,
1474 MonoGenericInst *method_inst, gpointer code)
1476 static gboolean inited = FALSE;
1477 static int num_added = 0;
1479 GenericVirtualCase *gvc, *list;
1480 MonoImtBuilderEntry *entries;
1484 mono_domain_lock (domain);
1485 if (!domain->generic_virtual_cases)
1486 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1488 /* Check whether the case was already added */
1489 gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1491 if (gvc->inst == method_inst)
1496 /* If not found, make a new one */
1498 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1499 gvc->inst = method_inst;
1502 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1504 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1507 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1513 if (++gvc->count < THUNK_THRESHOLD) {
1514 mono_domain_unlock (domain);
1519 for (list = gvc; list; list = list->next) {
1520 MonoImtBuilderEntry *entry;
1522 if (list->count < THUNK_THRESHOLD)
1525 entry = g_new0 (MonoImtBuilderEntry, 1);
1526 entry->key = list->inst;
1527 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1529 entry->children = entries->children + 1;
1530 entry->next = entries;
1534 sorted = imt_sort_slot_entries (entries);
1536 if (*vtable_slot != vtable_trampoline)
1537 invalidate_generic_virtual_thunk (domain, *vtable_slot);
1539 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1542 mono_domain_unlock (domain);
1545 MonoImtBuilderEntry *next = entries->next;
1550 for (i = 0; i < sorted->len; ++i)
1551 g_free (g_ptr_array_index (sorted, i));
1552 g_ptr_array_free (sorted, TRUE);
1555 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1558 * mono_class_vtable:
1559 * @domain: the application domain
1560 * @class: the class to initialize
1562 * VTables are domain specific because we create domain specific code, and
1563 * they contain the domain specific static class data.
1564 * On failure, NULL is returned, and class->exception_type is set.
1567 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1569 MonoClassRuntimeInfo *runtime_info;
1573 /* this check can be inlined in jitted code, too */
1574 runtime_info = class->runtime_info;
1575 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1576 return runtime_info->domain_vtables [domain->domain_id];
1577 if (class->exception_type)
1579 return mono_class_create_runtime_vtable (domain, class);
1583 * mono_class_try_get_vtable:
1584 * @domain: the application domain
1585 * @class: the class to initialize
1587 * This function tries to get the associated vtable from @class if
1588 * it was already created.
1591 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1593 MonoClassRuntimeInfo *runtime_info;
1597 runtime_info = class->runtime_info;
1598 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1599 return runtime_info->domain_vtables [domain->domain_id];
1604 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1607 MonoClassRuntimeInfo *runtime_info, *old_info;
1608 MonoClassField *field;
1611 int imt_table_bytes = 0;
1612 guint32 vtable_size, class_size;
1615 gpointer *interface_offsets;
1617 mono_domain_lock (domain);
1618 runtime_info = class->runtime_info;
1619 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1620 mono_domain_unlock (domain);
1621 return runtime_info->domain_vtables [domain->domain_id];
1623 if (!class->inited || class->exception_type) {
1624 if (!mono_class_init (class) || class->exception_type){
1626 mono_domain_unlock (domain);
1627 exc = mono_class_get_exception_for_failure (class);
1629 mono_raise_exception (exc);
1633 mono_class_init (class);
1636 * For some classes, mono_class_init () already computed class->vtable_size, and
1637 * that is all that is needed because of the vtable trampolines.
1639 if (!class->vtable_size)
1640 mono_class_setup_vtable (class);
1642 if (class->exception_type) {
1643 mono_domain_unlock (domain);
1648 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1649 if (class->interface_offsets_count) {
1650 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1651 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1652 mono_stats.imt_number_of_tables++;
1653 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1656 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1657 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1660 mono_stats.used_class_count++;
1661 mono_stats.class_vtable_size += vtable_size;
1662 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1665 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1667 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1669 vt->rank = class->rank;
1670 vt->domain = domain;
1672 mono_class_compute_gc_descriptor (class);
1674 * We can't use typed allocation in the non-root domains, since the
1675 * collector needs the GC descriptor stored in the vtable even after
1676 * the mempool containing the vtable is destroyed when the domain is
1677 * unloaded. An alternative might be to allocate vtables in the GC
1678 * heap, but this does not seem to work (it leads to crashes inside
1679 * libgc). If that approach is tried, two gc descriptors need to be
1680 * allocated for each class: one for the root domain, and one for all
1681 * other domains. The second descriptor should contain a bit for the
1682 * vtable field in MonoObject, since we can no longer assume the
1683 * vtable is reachable by other roots after the appdomain is unloaded.
1685 #ifdef HAVE_BOEHM_GC
1686 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1687 vt->gc_descr = GC_NO_DESCRIPTOR;
1690 vt->gc_descr = class->gc_descr;
1692 if ((class_size = mono_class_data_size (class))) {
1693 if (class->has_static_refs) {
1694 gpointer statics_gc_descr;
1696 gsize default_bitmap [4] = {0};
1699 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1700 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1701 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1702 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1703 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1704 if (bitmap != default_bitmap)
1707 vt->data = mono_domain_alloc0 (domain, class_size);
1709 mono_stats.class_static_data_size += class_size;
1714 while ((field = mono_class_get_fields (class, &iter))) {
1715 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1717 if (mono_field_is_deleted (field))
1719 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1720 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1721 if (special_static != SPECIAL_STATIC_NONE) {
1722 guint32 size, offset;
1724 size = mono_type_size (field->type, &align);
1725 offset = mono_alloc_special_static_data (special_static, size, align);
1726 if (!domain->special_static_fields)
1727 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1728 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1732 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1733 MonoClass *fklass = mono_class_from_mono_type (field->type);
1734 const char *data = mono_field_get_data (field);
1736 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1737 t = (char*)vt->data + field->offset;
1738 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1741 if (fklass->valuetype) {
1742 memcpy (t, data, mono_class_value_size (fklass, NULL));
1744 /* it's a pointer type: add check */
1745 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1752 vt->max_interface_id = class->max_interface_id;
1753 vt->interface_bitmap = class->interface_bitmap;
1755 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1756 // class->name, class->interface_offsets_count);
1758 if (! ARCH_USE_IMT) {
1759 /* initialize interface offsets */
1760 for (i = 0; i < class->interface_offsets_count; ++i) {
1761 int interface_id = class->interfaces_packed [i]->interface_id;
1762 int slot = class->interface_offsets_packed [i];
1763 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1767 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1768 * as we change the code in appdomain.c to invalidate vtables by
1769 * looking at the possible MonoClasses created for the domain.
1771 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1772 /* class->runtime_info is protected by the loader lock, both when
1773 * it it enlarged and when it is stored info.
1775 mono_loader_lock ();
1776 old_info = class->runtime_info;
1777 if (old_info && old_info->max_domain >= domain->domain_id) {
1778 /* someone already created a large enough runtime info */
1779 mono_memory_barrier ();
1780 old_info->domain_vtables [domain->domain_id] = vt;
1782 int new_size = domain->domain_id;
1784 new_size = MAX (new_size, old_info->max_domain);
1786 /* make the new size a power of two */
1788 while (new_size > i)
1791 /* this is a bounded memory retention issue: may want to
1792 * handle it differently when we'll have a rcu-like system.
1794 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1795 runtime_info->max_domain = new_size - 1;
1796 /* copy the stuff from the older info */
1798 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1800 runtime_info->domain_vtables [domain->domain_id] = vt;
1802 mono_memory_barrier ();
1803 class->runtime_info = runtime_info;
1805 mono_loader_unlock ();
1807 /* Initialize vtable */
1808 if (vtable_trampoline) {
1809 // This also covers the AOT case
1810 for (i = 0; i < class->vtable_size; ++i) {
1811 vt->vtable [i] = vtable_trampoline;
1814 mono_class_setup_vtable (class);
1816 for (i = 0; i < class->vtable_size; ++i) {
1819 if ((cm = class->vtable [i])) {
1820 if (mono_method_signature (cm)->generic_param_count)
1821 /* FIXME: Why is this needed ? */
1822 vt->vtable [i] = cm;
1824 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1829 if (ARCH_USE_IMT && imt_table_bytes) {
1830 /* Now that the vtable is full, we can actually fill up the IMT */
1831 if (imt_trampoline) {
1832 /* lazy construction of the IMT entries enabled */
1833 for (i = 0; i < MONO_IMT_SIZE; ++i)
1834 interface_offsets [i] = imt_trampoline;
1836 build_imt (class, vt, domain, interface_offsets, NULL);
1840 mono_domain_unlock (domain);
1842 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1843 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1844 MonoException *exc = mono_class_get_exception_for_failure (class);
1846 mono_raise_exception (exc);
1849 /* make sure the parent is initialized */
1851 mono_class_vtable (domain, class->parent);
1853 vt->type = mono_type_get_object (domain, &class->byval_arg);
1854 if (class->contextbound)
1863 * mono_class_proxy_vtable:
1864 * @domain: the application domain
1865 * @remove_class: the remote class
1867 * Creates a vtable for transparent proxies. It is basically
1868 * a copy of the real vtable of the class wrapped in @remote_class,
1869 * but all function pointers invoke the remoting functions, and
1870 * vtable->klass points to the transparent proxy class, and not to @class.
1873 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1875 MonoVTable *vt, *pvt;
1876 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1878 GSList *extra_interfaces = NULL;
1879 MonoClass *class = remote_class->proxy_class;
1880 gpointer *interface_offsets;
1882 vt = mono_class_vtable (domain, class);
1883 max_interface_id = vt->max_interface_id;
1885 /* Calculate vtable space for extra interfaces */
1886 for (j = 0; j < remote_class->interface_count; j++) {
1887 MonoClass* iclass = remote_class->interfaces[j];
1891 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1892 continue; /* interface implemented by the class */
1893 if (g_slist_find (extra_interfaces, iclass))
1896 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1898 method_count = mono_class_num_methods (iclass);
1900 ifaces = mono_class_get_implemented_interfaces (iclass);
1902 for (i = 0; i < ifaces->len; ++i) {
1903 MonoClass *ic = g_ptr_array_index (ifaces, i);
1904 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1905 continue; /* interface implemented by the class */
1906 if (g_slist_find (extra_interfaces, ic))
1908 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1909 method_count += mono_class_num_methods (ic);
1911 g_ptr_array_free (ifaces, TRUE);
1914 extra_interface_vtsize += method_count * sizeof (gpointer);
1915 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1919 mono_stats.imt_number_of_tables++;
1920 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1921 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1922 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1924 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1925 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1928 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1930 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1932 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1934 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1935 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1937 pvt->klass = mono_defaults.transparent_proxy_class;
1938 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1939 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1941 /* initialize vtable */
1942 mono_class_setup_vtable (class);
1943 for (i = 0; i < class->vtable_size; ++i) {
1946 if ((cm = class->vtable [i]))
1947 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
1949 pvt->vtable [i] = NULL;
1952 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1953 /* create trampolines for abstract methods */
1954 for (k = class; k; k = k->parent) {
1956 gpointer iter = NULL;
1957 while ((m = mono_class_get_methods (k, &iter)))
1958 if (!pvt->vtable [m->slot])
1959 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
1963 pvt->max_interface_id = max_interface_id;
1964 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1966 if (! ARCH_USE_IMT) {
1967 /* initialize interface offsets */
1968 for (i = 0; i < class->interface_offsets_count; ++i) {
1969 int interface_id = class->interfaces_packed [i]->interface_id;
1970 int slot = class->interface_offsets_packed [i];
1971 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1974 for (i = 0; i < class->interface_offsets_count; ++i) {
1975 int interface_id = class->interfaces_packed [i]->interface_id;
1976 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1979 if (extra_interfaces) {
1980 int slot = class->vtable_size;
1986 /* Create trampolines for the methods of the interfaces */
1987 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1988 interf = list_item->data;
1990 if (! ARCH_USE_IMT) {
1991 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1993 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1997 while ((cm = mono_class_get_methods (interf, &iter)))
1998 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2000 slot += mono_class_num_methods (interf);
2002 if (! ARCH_USE_IMT) {
2003 g_slist_free (extra_interfaces);
2008 /* Now that the vtable is full, we can actually fill up the IMT */
2009 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2010 if (extra_interfaces) {
2011 g_slist_free (extra_interfaces);
2019 * mono_class_field_is_special_static:
2021 * Returns whether @field is a thread/context static field.
2024 mono_class_field_is_special_static (MonoClassField *field)
2026 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2028 if (mono_field_is_deleted (field))
2030 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2031 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2038 * mono_class_has_special_static_fields:
2040 * Returns whenever @klass has any thread/context static fields.
2043 mono_class_has_special_static_fields (MonoClass *klass)
2045 MonoClassField *field;
2049 while ((field = mono_class_get_fields (klass, &iter))) {
2050 g_assert (field->parent == klass);
2051 if (mono_class_field_is_special_static (field))
2059 * create_remote_class_key:
2060 * Creates an array of pointers that can be used as a hash key for a remote class.
2061 * The first element of the array is the number of pointers.
2064 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2069 if (remote_class == NULL) {
2070 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2071 key = g_malloc (sizeof(gpointer) * 3);
2072 key [0] = GINT_TO_POINTER (2);
2073 key [1] = mono_defaults.marshalbyrefobject_class;
2074 key [2] = extra_class;
2076 key = g_malloc (sizeof(gpointer) * 2);
2077 key [0] = GINT_TO_POINTER (1);
2078 key [1] = extra_class;
2081 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2082 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2083 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2084 key [1] = remote_class->proxy_class;
2086 // Keep the list of interfaces sorted
2087 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2088 if (extra_class && remote_class->interfaces [i] > extra_class) {
2089 key [j++] = extra_class;
2092 key [j] = remote_class->interfaces [i];
2095 key [j] = extra_class;
2097 // Replace the old class. The interface list is the same
2098 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2099 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2100 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2101 for (i = 0; i < remote_class->interface_count; i++)
2102 key [2 + i] = remote_class->interfaces [i];
2110 * copy_remote_class_key:
2112 * Make a copy of KEY in the domain and return the copy.
2115 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2117 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2118 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2120 memcpy (mp_key, key, key_size);
2126 * mono_remote_class:
2127 * @domain: the application domain
2128 * @class_name: name of the remote class
2130 * Creates and initializes a MonoRemoteClass object for a remote type.
2134 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2136 MonoRemoteClass *rc;
2137 gpointer* key, *mp_key;
2139 key = create_remote_class_key (NULL, proxy_class);
2141 mono_domain_lock (domain);
2142 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2146 mono_domain_unlock (domain);
2150 mp_key = copy_remote_class_key (domain, key);
2154 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2155 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2156 rc->interface_count = 1;
2157 rc->interfaces [0] = proxy_class;
2158 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2160 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2161 rc->interface_count = 0;
2162 rc->proxy_class = proxy_class;
2165 rc->default_vtable = NULL;
2166 rc->xdomain_vtable = NULL;
2167 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2168 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2170 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2172 mono_domain_unlock (domain);
2177 * clone_remote_class:
2178 * Creates a copy of the remote_class, adding the provided class or interface
2180 static MonoRemoteClass*
2181 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2183 MonoRemoteClass *rc;
2184 gpointer* key, *mp_key;
2186 key = create_remote_class_key (remote_class, extra_class);
2187 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2193 mp_key = copy_remote_class_key (domain, key);
2197 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2199 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2200 rc->proxy_class = remote_class->proxy_class;
2201 rc->interface_count = remote_class->interface_count + 1;
2203 // Keep the list of interfaces sorted, since the hash key of
2204 // the remote class depends on this
2205 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2206 if (remote_class->interfaces [i] > extra_class && i == j)
2207 rc->interfaces [j++] = extra_class;
2208 rc->interfaces [j] = remote_class->interfaces [i];
2211 rc->interfaces [j] = extra_class;
2213 // Replace the old class. The interface array is the same
2214 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2215 rc->proxy_class = extra_class;
2216 rc->interface_count = remote_class->interface_count;
2217 if (rc->interface_count > 0)
2218 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2221 rc->default_vtable = NULL;
2222 rc->xdomain_vtable = NULL;
2223 rc->proxy_class_name = remote_class->proxy_class_name;
2225 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2231 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2233 mono_domain_lock (domain);
2234 if (rp->target_domain_id != -1) {
2235 if (remote_class->xdomain_vtable == NULL)
2236 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2237 mono_domain_unlock (domain);
2238 return remote_class->xdomain_vtable;
2240 if (remote_class->default_vtable == NULL) {
2243 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2244 klass = mono_class_from_mono_type (type);
2245 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2246 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2248 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2251 mono_domain_unlock (domain);
2252 return remote_class->default_vtable;
2256 * mono_upgrade_remote_class:
2257 * @domain: the application domain
2258 * @tproxy: the proxy whose remote class has to be upgraded.
2259 * @klass: class to which the remote class can be casted.
2261 * Updates the vtable of the remote class by adding the necessary method slots
2262 * and interface offsets so it can be safely casted to klass. klass can be a
2263 * class or an interface.
2266 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2268 MonoTransparentProxy *tproxy;
2269 MonoRemoteClass *remote_class;
2270 gboolean redo_vtable;
2272 mono_domain_lock (domain);
2274 tproxy = (MonoTransparentProxy*) proxy_object;
2275 remote_class = tproxy->remote_class;
2277 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2280 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2281 if (remote_class->interfaces [i] == klass)
2282 redo_vtable = FALSE;
2285 redo_vtable = (remote_class->proxy_class != klass);
2289 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2290 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2293 mono_domain_unlock (domain);
2298 * mono_object_get_virtual_method:
2299 * @obj: object to operate on.
2302 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2303 * the instance of a callvirt of method.
2306 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2309 MonoMethod **vtable;
2311 MonoMethod *res = NULL;
2313 klass = mono_object_class (obj);
2314 if (klass == mono_defaults.transparent_proxy_class) {
2315 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2321 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2324 mono_class_setup_vtable (klass);
2325 vtable = klass->vtable;
2327 if (method->slot == -1) {
2328 /* method->slot might not be set for instances of generic methods */
2329 if (method->is_inflated) {
2330 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2331 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2334 g_assert_not_reached ();
2338 /* check method->slot is a valid index: perform isinstance? */
2339 if (method->slot != -1) {
2340 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2342 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2344 res = vtable [method->slot];
2349 /* It may be an interface, abstract class method or generic method */
2350 if (!res || mono_method_signature (res)->generic_param_count)
2353 /* generic methods demand invoke_with_check */
2354 if (mono_method_signature (res)->generic_param_count)
2355 res = mono_marshal_get_remoting_invoke_with_check (res);
2357 res = mono_marshal_get_remoting_invoke (res);
2359 if (method->is_inflated) {
2360 /* Have to inflate the result */
2361 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2371 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2373 g_error ("runtime invoke called on uninitialized runtime");
2377 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2380 * mono_runtime_invoke:
2381 * @method: method to invoke
2382 * @obJ: object instance
2383 * @params: arguments to the method
2384 * @exc: exception information.
2386 * Invokes the method represented by @method on the object @obj.
2388 * obj is the 'this' pointer, it should be NULL for static
2389 * methods, a MonoObject* for object instances and a pointer to
2390 * the value type for value types.
2392 * The params array contains the arguments to the method with the
2393 * same convention: MonoObject* pointers for object instances and
2394 * pointers to the value type otherwise.
2396 * From unmanaged code you'll usually use the
2397 * mono_runtime_invoke() variant.
2399 * Note that this function doesn't handle virtual methods for
2400 * you, it will exec the exact method you pass: we still need to
2401 * expose a function to lookup the derived class implementation
2402 * of a virtual method (there are examples of this in the code,
2405 * You can pass NULL as the exc argument if you don't want to
2406 * catch exceptions, otherwise, *exc will be set to the exception
2407 * thrown, if any. if an exception is thrown, you can't use the
2408 * MonoObject* result from the function.
2410 * If the method returns a value type, it is boxed in an object
2414 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2416 if (mono_runtime_get_no_exec ())
2417 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2419 return default_mono_runtime_invoke (method, obj, params, exc);
2423 * mono_method_get_unmanaged_thunk:
2424 * @method: method to generate a thunk for.
2426 * Returns an unmanaged->managed thunk that can be used to call
2427 * a managed method directly from C.
2429 * The thunk's C signature closely matches the managed signature:
2431 * C#: public bool Equals (object obj);
2432 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2433 * MonoObject*, MonoException**);
2435 * The 1st ("this") parameter must not be used with static methods:
2437 * C#: public static bool ReferenceEquals (object a, object b);
2438 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2441 * The last argument must be a non-null pointer of a MonoException* pointer.
2442 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2443 * exception has been thrown in managed code. Otherwise it will point
2444 * to the MonoException* caught by the thunk. In this case, the result of
2445 * the thunk is undefined:
2447 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2448 * MonoException *ex = NULL;
2449 * Equals func = mono_method_get_unmanaged_thunk (method);
2450 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2452 * // handle exception
2455 * The calling convention of the thunk matches the platform's default
2456 * convention. This means that under Windows, C declarations must
2457 * contain the __stdcall attribute:
2459 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2460 * MonoObject*, MonoException**);
2464 * Value type arguments and return values are treated as they were objects:
2466 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2467 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2469 * Arguments must be properly boxed upon trunk's invocation, while return
2470 * values must be unboxed.
2473 mono_method_get_unmanaged_thunk (MonoMethod *method)
2475 method = mono_marshal_get_thunk_invoke_wrapper (method);
2476 return mono_compile_method (method);
2480 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2484 gpointer *p = (gpointer*)dest;
2491 case MONO_TYPE_BOOLEAN:
2493 case MONO_TYPE_U1: {
2494 guint8 *p = (guint8*)dest;
2495 *p = value ? *(guint8*)value : 0;
2500 case MONO_TYPE_CHAR: {
2501 guint16 *p = (guint16*)dest;
2502 *p = value ? *(guint16*)value : 0;
2505 #if SIZEOF_VOID_P == 4
2510 case MONO_TYPE_U4: {
2511 gint32 *p = (gint32*)dest;
2512 *p = value ? *(gint32*)value : 0;
2515 #if SIZEOF_VOID_P == 8
2520 case MONO_TYPE_U8: {
2521 gint64 *p = (gint64*)dest;
2522 *p = value ? *(gint64*)value : 0;
2525 case MONO_TYPE_R4: {
2526 float *p = (float*)dest;
2527 *p = value ? *(float*)value : 0;
2530 case MONO_TYPE_R8: {
2531 double *p = (double*)dest;
2532 *p = value ? *(double*)value : 0;
2535 case MONO_TYPE_STRING:
2536 case MONO_TYPE_SZARRAY:
2537 case MONO_TYPE_CLASS:
2538 case MONO_TYPE_OBJECT:
2539 case MONO_TYPE_ARRAY:
2540 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2542 case MONO_TYPE_FNPTR:
2543 case MONO_TYPE_PTR: {
2544 gpointer *p = (gpointer*)dest;
2545 *p = deref_pointer? *(gpointer*)value: value;
2548 case MONO_TYPE_VALUETYPE:
2549 /* note that 't' and 'type->type' can be different */
2550 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2551 t = mono_class_enum_basetype (type->data.klass)->type;
2555 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2557 memset (dest, 0, size);
2559 memcpy (dest, value, size);
2562 case MONO_TYPE_GENERICINST:
2563 t = type->data.generic_class->container_class->byval_arg.type;
2566 g_warning ("got type %x", type->type);
2567 g_assert_not_reached ();
2572 * mono_field_set_value:
2573 * @obj: Instance object
2574 * @field: MonoClassField describing the field to set
2575 * @value: The value to be set
2577 * Sets the value of the field described by @field in the object instance @obj
2578 * to the value passed in @value. This method should only be used for instance
2579 * fields. For static fields, use mono_field_static_set_value.
2581 * The value must be on the native format of the field type.
2584 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2588 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2590 dest = (char*)obj + field->offset;
2591 set_value (field->type, dest, value, FALSE);
2595 * mono_field_static_set_value:
2596 * @field: MonoClassField describing the field to set
2597 * @value: The value to be set
2599 * Sets the value of the static field described by @field
2600 * to the value passed in @value.
2602 * The value must be on the native format of the field type.
2605 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2609 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2610 /* you cant set a constant! */
2611 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2613 dest = (char*)vt->data + field->offset;
2614 set_value (field->type, dest, value, FALSE);
2617 /* Used by the debugger */
2619 mono_vtable_get_static_field_data (MonoVTable *vt)
2625 * mono_field_get_value:
2626 * @obj: Object instance
2627 * @field: MonoClassField describing the field to fetch information from
2628 * @value: pointer to the location where the value will be stored
2630 * Use this routine to get the value of the field @field in the object
2633 * The pointer provided by value must be of the field type, for reference
2634 * types this is a MonoObject*, for value types its the actual pointer to
2639 * mono_field_get_value (obj, int_field, &i);
2642 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2646 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2648 src = (char*)obj + field->offset;
2649 set_value (field->type, value, src, TRUE);
2653 * mono_field_get_value_object:
2654 * @domain: domain where the object will be created (if boxing)
2655 * @field: MonoClassField describing the field to fetch information from
2656 * @obj: The object instance for the field.
2658 * Returns: a new MonoObject with the value from the given field. If the
2659 * field represents a value type, the value is boxed.
2663 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2667 MonoVTable *vtable = NULL;
2669 gboolean is_static = FALSE;
2670 gboolean is_ref = FALSE;
2672 switch (field->type->type) {
2673 case MONO_TYPE_STRING:
2674 case MONO_TYPE_OBJECT:
2675 case MONO_TYPE_CLASS:
2676 case MONO_TYPE_ARRAY:
2677 case MONO_TYPE_SZARRAY:
2682 case MONO_TYPE_BOOLEAN:
2685 case MONO_TYPE_CHAR:
2694 case MONO_TYPE_VALUETYPE:
2695 is_ref = field->type->byref;
2697 case MONO_TYPE_GENERICINST:
2698 is_ref = !field->type->data.generic_class->container_class->valuetype;
2701 g_error ("type 0x%x not handled in "
2702 "mono_field_get_value_object", field->type->type);
2706 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2708 vtable = mono_class_vtable (domain, field->parent);
2709 if (!vtable->initialized)
2710 mono_runtime_class_init (vtable);
2715 mono_field_static_get_value (vtable, field, &o);
2717 mono_field_get_value (obj, field, &o);
2722 /* boxed value type */
2723 klass = mono_class_from_mono_type (field->type);
2724 o = mono_object_new (domain, klass);
2725 v = ((gchar *) o) + sizeof (MonoObject);
2727 mono_field_static_get_value (vtable, field, v);
2729 mono_field_get_value (obj, field, v);
2736 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2739 const char *p = blob;
2740 mono_metadata_decode_blob_size (p, &p);
2743 case MONO_TYPE_BOOLEAN:
2746 *(guint8 *) value = *p;
2748 case MONO_TYPE_CHAR:
2751 *(guint16*) value = read16 (p);
2755 *(guint32*) value = read32 (p);
2759 *(guint64*) value = read64 (p);
2762 readr4 (p, (float*) value);
2765 readr8 (p, (double*) value);
2767 case MONO_TYPE_STRING:
2768 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2770 case MONO_TYPE_CLASS:
2771 *(gpointer*) value = NULL;
2775 g_warning ("type 0x%02x should not be in constant table", type);
2781 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2783 MonoTypeEnum def_type;
2786 data = mono_class_get_field_default_value (field, &def_type);
2787 mono_get_constant_value_from_blob (domain, def_type, data, value);
2791 * mono_field_static_get_value:
2792 * @vt: vtable to the object
2793 * @field: MonoClassField describing the field to fetch information from
2794 * @value: where the value is returned
2796 * Use this routine to get the value of the static field @field value.
2798 * The pointer provided by value must be of the field type, for reference
2799 * types this is a MonoObject*, for value types its the actual pointer to
2804 * mono_field_static_get_value (vt, int_field, &i);
2807 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2811 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2813 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2814 get_default_field_value (vt->domain, field, value);
2818 src = (char*)vt->data + field->offset;
2819 set_value (field->type, value, src, TRUE);
2823 * mono_property_set_value:
2824 * @prop: MonoProperty to set
2825 * @obj: instance object on which to act
2826 * @params: parameters to pass to the propery
2827 * @exc: optional exception
2829 * Invokes the property's set method with the given arguments on the
2830 * object instance obj (or NULL for static properties).
2832 * You can pass NULL as the exc argument if you don't want to
2833 * catch exceptions, otherwise, *exc will be set to the exception
2834 * thrown, if any. if an exception is thrown, you can't use the
2835 * MonoObject* result from the function.
2838 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2840 default_mono_runtime_invoke (prop->set, obj, params, exc);
2844 * mono_property_get_value:
2845 * @prop: MonoProperty to fetch
2846 * @obj: instance object on which to act
2847 * @params: parameters to pass to the propery
2848 * @exc: optional exception
2850 * Invokes the property's get method with the given arguments on the
2851 * object instance obj (or NULL for static properties).
2853 * You can pass NULL as the exc argument if you don't want to
2854 * catch exceptions, otherwise, *exc will be set to the exception
2855 * thrown, if any. if an exception is thrown, you can't use the
2856 * MonoObject* result from the function.
2858 * Returns: the value from invoking the get method on the property.
2861 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2863 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2867 * mono_nullable_init:
2868 * @buf: The nullable structure to initialize.
2869 * @value: the value to initialize from
2870 * @klass: the type for the object
2872 * Initialize the nullable structure pointed to by @buf from @value which
2873 * should be a boxed value type. The size of @buf should be able to hold
2874 * as much data as the @klass->instance_size (which is the number of bytes
2875 * that will be copies).
2877 * Since Nullables have variable structure, we can not define a C
2878 * structure for them.
2881 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2883 MonoClass *param_class = klass->cast_class;
2885 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2886 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2888 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2890 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2892 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2896 * mono_nullable_box:
2897 * @buf: The buffer representing the data to be boxed
2898 * @klass: the type to box it as.
2900 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2904 mono_nullable_box (guint8 *buf, MonoClass *klass)
2906 MonoClass *param_class = klass->cast_class;
2908 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2909 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2911 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2912 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2913 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2921 * mono_get_delegate_invoke:
2922 * @klass: The delegate class
2924 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2927 mono_get_delegate_invoke (MonoClass *klass)
2931 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2938 * mono_runtime_delegate_invoke:
2939 * @delegate: pointer to a delegate object.
2940 * @params: parameters for the delegate.
2941 * @exc: Pointer to the exception result.
2943 * Invokes the delegate method @delegate with the parameters provided.
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.
2951 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2955 im = mono_get_delegate_invoke (delegate->vtable->klass);
2958 return mono_runtime_invoke (im, delegate, params, exc);
2961 static char **main_args = NULL;
2962 static int num_main_args;
2965 * mono_runtime_get_main_args:
2967 * Returns: a MonoArray with the arguments passed to the main program
2970 mono_runtime_get_main_args (void)
2974 MonoDomain *domain = mono_domain_get ();
2979 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2981 for (i = 0; i < num_main_args; ++i)
2982 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2988 fire_process_exit_event (void)
2990 MonoClassField *field;
2991 MonoDomain *domain = mono_domain_get ();
2993 MonoObject *delegate, *exc;
2995 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2998 if (domain != mono_get_root_domain ())
3001 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3002 if (delegate == NULL)
3007 mono_runtime_delegate_invoke (delegate, pa, &exc);
3011 * mono_runtime_run_main:
3012 * @method: the method to start the application with (usually Main)
3013 * @argc: number of arguments from the command line
3014 * @argv: array of strings from the command line
3015 * @exc: excetption results
3017 * Execute a standard Main() method (argc/argv contains the
3018 * executable name). This method also sets the command line argument value
3019 * needed by System.Environment.
3024 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3028 MonoArray *args = NULL;
3029 MonoDomain *domain = mono_domain_get ();
3030 gchar *utf8_fullpath;
3033 g_assert (method != NULL);
3035 mono_thread_set_main (mono_thread_current ());
3037 main_args = g_new0 (char*, argc);
3038 num_main_args = argc;
3040 if (!g_path_is_absolute (argv [0])) {
3041 gchar *basename = g_path_get_basename (argv [0]);
3042 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3046 utf8_fullpath = mono_utf8_from_external (fullpath);
3047 if(utf8_fullpath == NULL) {
3048 /* Printing the arg text will cause glib to
3049 * whinge about "Invalid UTF-8", but at least
3050 * its relevant, and shows the problem text
3053 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3054 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3061 utf8_fullpath = mono_utf8_from_external (argv[0]);
3062 if(utf8_fullpath == NULL) {
3063 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3064 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3069 main_args [0] = utf8_fullpath;
3071 for (i = 1; i < argc; ++i) {
3074 utf8_arg=mono_utf8_from_external (argv[i]);
3075 if(utf8_arg==NULL) {
3076 /* Ditto the comment about Invalid UTF-8 here */
3077 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3078 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3082 main_args [i] = utf8_arg;
3086 if (mono_method_signature (method)->param_count) {
3087 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3088 for (i = 0; i < argc; ++i) {
3089 /* The encodings should all work, given that
3090 * we've checked all these args for the
3093 gchar *str = mono_utf8_from_external (argv [i]);
3094 MonoString *arg = mono_string_new (domain, str);
3095 mono_array_setref (args, i, arg);
3099 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3102 mono_assembly_set_main (method->klass->image->assembly);
3104 result = mono_runtime_exec_main (method, args, exc);
3105 fire_process_exit_event ();
3109 /* Used in call_unhandled_exception_delegate */
3111 create_unhandled_exception_eventargs (MonoObject *exc)
3115 MonoMethod *method = NULL;
3116 MonoBoolean is_terminating = TRUE;
3119 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3122 mono_class_init (klass);
3124 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3125 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3129 args [1] = &is_terminating;
3131 obj = mono_object_new (mono_domain_get (), klass);
3132 mono_runtime_invoke (method, obj, args, NULL);
3137 /* Used in mono_unhandled_exception */
3139 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3140 MonoObject *e = NULL;
3143 pa [0] = domain->domain;
3144 pa [1] = create_unhandled_exception_eventargs (exc);
3145 mono_runtime_delegate_invoke (delegate, pa, &e);
3148 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3149 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3154 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3157 * mono_runtime_unhandled_exception_policy_set:
3158 * @policy: the new policy
3160 * This is a VM internal routine.
3162 * Sets the runtime policy for handling unhandled exceptions.
3165 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3166 runtime_unhandled_exception_policy = policy;
3170 * mono_runtime_unhandled_exception_policy_get:
3172 * This is a VM internal routine.
3174 * Gets the runtime policy for handling unhandled exceptions.
3176 MonoRuntimeUnhandledExceptionPolicy
3177 mono_runtime_unhandled_exception_policy_get (void) {
3178 return runtime_unhandled_exception_policy;
3182 * mono_unhandled_exception:
3183 * @exc: exception thrown
3185 * This is a VM internal routine.
3187 * We call this function when we detect an unhandled exception
3188 * in the default domain.
3190 * It invokes the * UnhandledException event in AppDomain or prints
3191 * a warning to the console
3194 mono_unhandled_exception (MonoObject *exc)
3196 MonoDomain *current_domain = mono_domain_get ();
3197 MonoDomain *root_domain = mono_get_root_domain ();
3198 MonoClassField *field;
3199 MonoObject *current_appdomain_delegate;
3200 MonoObject *root_appdomain_delegate;
3202 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3203 "UnhandledException");
3206 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3207 gboolean abort_process = (mono_thread_current () == main_thread) ||
3208 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3209 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3210 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3211 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3213 current_appdomain_delegate = NULL;
3216 /* set exitcode only if we will abort the process */
3218 mono_environment_exitcode_set (1);
3219 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3220 mono_print_unhandled_exception (exc);
3222 if (root_appdomain_delegate) {
3223 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3225 if (current_appdomain_delegate) {
3226 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3233 * Launch a new thread to execute a function
3235 * main_func is called back from the thread with main_args as the
3236 * parameter. The callback function is expected to start Main()
3237 * eventually. This function then waits for all managed threads to
3239 * It is not necesseray anymore to execute managed code in a subthread,
3240 * so this function should not be used anymore by default: just
3241 * execute the code and then call mono_thread_manage ().
3244 mono_runtime_exec_managed_code (MonoDomain *domain,
3245 MonoMainThreadFunc main_func,
3248 mono_thread_create (domain, main_func, main_args);
3250 mono_thread_manage ();
3254 * Execute a standard Main() method (args doesn't contain the
3258 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3263 MonoCustomAttrInfo* cinfo;
3264 gboolean has_stathread_attribute;
3265 MonoThread* thread = mono_thread_current ();
3271 domain = mono_object_domain (args);
3272 if (!domain->entry_assembly) {
3274 MonoAssembly *assembly;
3276 assembly = method->klass->image->assembly;
3277 domain->entry_assembly = assembly;
3278 /* Domains created from another domain already have application_base and configuration_file set */
3279 if (domain->setup->application_base == NULL) {
3280 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3283 if (domain->setup->configuration_file == NULL) {
3284 str = g_strconcat (assembly->image->name, ".config", NULL);
3285 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3287 mono_set_private_bin_path_from_config (domain);
3291 cinfo = mono_custom_attrs_from_method (method);
3293 static MonoClass *stathread_attribute = NULL;
3294 if (!stathread_attribute)
3295 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3296 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3298 mono_custom_attrs_free (cinfo);
3300 has_stathread_attribute = FALSE;
3302 if (has_stathread_attribute) {
3303 thread->apartment_state = ThreadApartmentState_STA;
3304 } else if (mono_framework_version () == 1) {
3305 thread->apartment_state = ThreadApartmentState_Unknown;
3307 thread->apartment_state = ThreadApartmentState_MTA;
3309 mono_thread_init_apartment_state ();
3311 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3313 /* FIXME: check signature of method */
3314 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3316 res = mono_runtime_invoke (method, NULL, pa, exc);
3318 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3322 mono_environment_exitcode_set (rval);
3324 mono_runtime_invoke (method, NULL, pa, exc);
3328 /* If the return type of Main is void, only
3329 * set the exitcode if an exception was thrown
3330 * (we don't want to blow away an
3331 * explicitly-set exit code)
3334 mono_environment_exitcode_set (rval);
3338 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3344 * mono_install_runtime_invoke:
3345 * @func: Function to install
3347 * This is a VM internal routine
3350 mono_install_runtime_invoke (MonoInvokeFunc func)
3352 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3357 * mono_runtime_invoke_array:
3358 * @method: method to invoke
3359 * @obJ: object instance
3360 * @params: arguments to the method
3361 * @exc: exception information.
3363 * Invokes the method represented by @method on the object @obj.
3365 * obj is the 'this' pointer, it should be NULL for static
3366 * methods, a MonoObject* for object instances and a pointer to
3367 * the value type for value types.
3369 * The params array contains the arguments to the method with the
3370 * same convention: MonoObject* pointers for object instances and
3371 * pointers to the value type otherwise. The _invoke_array
3372 * variant takes a C# object[] as the params argument (MonoArray
3373 * *params): in this case the value types are boxed inside the
3374 * respective reference representation.
3376 * From unmanaged code you'll usually use the
3377 * mono_runtime_invoke() variant.
3379 * Note that this function doesn't handle virtual methods for
3380 * you, it will exec the exact method you pass: we still need to
3381 * expose a function to lookup the derived class implementation
3382 * of a virtual method (there are examples of this in the code,
3385 * You can pass NULL as the exc argument if you don't want to
3386 * catch exceptions, otherwise, *exc will be set to the exception
3387 * thrown, if any. if an exception is thrown, you can't use the
3388 * MonoObject* result from the function.
3390 * If the method returns a value type, it is boxed in an object
3394 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3397 MonoMethodSignature *sig = mono_method_signature (method);
3398 gpointer *pa = NULL;
3401 gboolean has_byref_nullables = FALSE;
3403 if (NULL != params) {
3404 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3405 for (i = 0; i < mono_array_length (params); i++) {
3406 MonoType *t = sig->params [i];
3412 case MONO_TYPE_BOOLEAN:
3415 case MONO_TYPE_CHAR:
3424 case MONO_TYPE_VALUETYPE:
3425 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3426 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3427 pa [i] = mono_array_get (params, MonoObject*, i);
3429 has_byref_nullables = TRUE;
3431 /* MS seems to create the objects if a null is passed in */
3432 if (!mono_array_get (params, MonoObject*, i))
3433 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3437 * We can't pass the unboxed vtype byref to the callee, since
3438 * that would mean the callee would be able to modify boxed
3439 * primitive types. So we (and MS) make a copy of the boxed
3440 * object, pass that to the callee, and replace the original
3441 * boxed object in the arg array with the copy.
3443 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3444 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3445 mono_array_setref (params, i, copy);
3448 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3451 case MONO_TYPE_STRING:
3452 case MONO_TYPE_OBJECT:
3453 case MONO_TYPE_CLASS:
3454 case MONO_TYPE_ARRAY:
3455 case MONO_TYPE_SZARRAY:
3457 pa [i] = mono_array_addr (params, MonoObject*, i);
3458 // FIXME: I need to check this code path
3460 pa [i] = mono_array_get (params, MonoObject*, i);
3462 case MONO_TYPE_GENERICINST:
3464 t = &t->data.generic_class->container_class->this_arg;
3466 t = &t->data.generic_class->container_class->byval_arg;
3469 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3474 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3477 if (mono_class_is_nullable (method->klass)) {
3478 /* Need to create a boxed vtype instead */
3484 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3488 obj = mono_object_new (mono_domain_get (), method->klass);
3489 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3490 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3492 if (method->klass->valuetype)
3493 o = mono_object_unbox (obj);
3496 } else if (method->klass->valuetype) {
3497 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3500 mono_runtime_invoke (method, o, pa, exc);
3503 if (mono_class_is_nullable (method->klass)) {
3504 MonoObject *nullable;
3506 /* Convert the unboxed vtype into a Nullable structure */
3507 nullable = mono_object_new (mono_domain_get (), method->klass);
3509 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3510 obj = mono_object_unbox (nullable);
3513 /* obj must be already unboxed if needed */
3514 res = mono_runtime_invoke (method, obj, pa, exc);
3516 if (has_byref_nullables) {
3518 * The runtime invoke wrapper already converted byref nullables back,
3519 * and stored them in pa, we just need to copy them back to the
3522 for (i = 0; i < mono_array_length (params); i++) {
3523 MonoType *t = sig->params [i];
3525 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3526 mono_array_setref (params, i, pa [i]);
3535 arith_overflow (void)
3537 mono_raise_exception (mono_get_exception_overflow ());
3541 * mono_object_allocate:
3542 * @size: number of bytes to allocate
3544 * This is a very simplistic routine until we have our GC-aware
3547 * Returns: an allocated object of size @size, or NULL on failure.
3549 static inline void *
3550 mono_object_allocate (size_t size, MonoVTable *vtable)
3553 mono_stats.new_object_count++;
3554 ALLOC_OBJECT (o, vtable, size);
3560 * mono_object_allocate_ptrfree:
3561 * @size: number of bytes to allocate
3563 * Note that the memory allocated is not zeroed.
3564 * Returns: an allocated object of size @size, or NULL on failure.
3566 static inline void *
3567 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3570 mono_stats.new_object_count++;
3571 ALLOC_PTRFREE (o, vtable, size);
3575 static inline void *
3576 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3579 ALLOC_TYPED (o, size, vtable);
3580 mono_stats.new_object_count++;
3587 * @klass: the class of the object that we want to create
3589 * Returns: a newly created object whose definition is
3590 * looked up using @klass. This will not invoke any constructors,
3591 * so the consumer of this routine has to invoke any constructors on
3592 * its own to initialize the object.
3595 mono_object_new (MonoDomain *domain, MonoClass *klass)
3597 MONO_ARCH_SAVE_REGS;
3598 return mono_object_new_specific (mono_class_vtable (domain, klass));
3602 * mono_object_new_specific:
3603 * @vtable: the vtable of the object that we want to create
3605 * Returns: A newly created object with class and domain specified
3609 mono_object_new_specific (MonoVTable *vtable)
3613 MONO_ARCH_SAVE_REGS;
3615 /* check for is_com_object for COM Interop */
3616 if (vtable->remote || vtable->klass->is_com_object)
3619 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3622 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3625 mono_class_init (klass);
3627 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3629 vtable->domain->create_proxy_for_type_method = im;
3632 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3634 o = mono_runtime_invoke (im, NULL, pa, NULL);
3635 if (o != NULL) return o;
3638 return mono_object_new_alloc_specific (vtable);
3642 mono_object_new_alloc_specific (MonoVTable *vtable)
3646 if (!vtable->klass->has_references) {
3647 o = mono_object_new_ptrfree (vtable);
3648 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3649 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3651 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3652 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3654 if (G_UNLIKELY (vtable->klass->has_finalize))
3655 mono_object_register_finalizer (o);
3657 if (G_UNLIKELY (profile_allocs))
3658 mono_profiler_allocation (o, vtable->klass);
3663 mono_object_new_fast (MonoVTable *vtable)
3666 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3671 mono_object_new_ptrfree (MonoVTable *vtable)
3674 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3675 #if NEED_TO_ZERO_PTRFREE
3676 /* an inline memset is much faster for the common vcase of small objects
3677 * note we assume the allocated size is a multiple of sizeof (void*).
3679 if (vtable->klass->instance_size < 128) {
3681 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3682 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3688 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3695 mono_object_new_ptrfree_box (MonoVTable *vtable)
3698 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3699 /* the object will be boxed right away, no need to memzero it */
3704 * mono_class_get_allocation_ftn:
3706 * @for_box: the object will be used for boxing
3707 * @pass_size_in_words:
3709 * Return the allocation function appropriate for the given class.
3713 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3715 *pass_size_in_words = FALSE;
3717 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3718 profile_allocs = FALSE;
3720 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3721 return mono_object_new_specific;
3723 if (!vtable->klass->has_references) {
3724 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3726 return mono_object_new_ptrfree_box;
3727 return mono_object_new_ptrfree;
3730 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3732 return mono_object_new_fast;
3735 * FIXME: This is actually slower than mono_object_new_fast, because
3736 * of the overhead of parameter passing.
3739 *pass_size_in_words = TRUE;
3740 #ifdef GC_REDIRECT_TO_LOCAL
3741 return GC_local_gcj_fast_malloc;
3743 return GC_gcj_fast_malloc;
3748 return mono_object_new_specific;
3752 * mono_object_new_from_token:
3753 * @image: Context where the type_token is hosted
3754 * @token: a token of the type that we want to create
3756 * Returns: A newly created object whose definition is
3757 * looked up using @token in the @image image
3760 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3764 class = mono_class_get (image, token);
3766 return mono_object_new (domain, class);
3771 * mono_object_clone:
3772 * @obj: the object to clone
3774 * Returns: A newly created object who is a shallow copy of @obj
3777 mono_object_clone (MonoObject *obj)
3782 size = obj->vtable->klass->instance_size;
3783 o = mono_object_allocate (size, obj->vtable);
3784 /* do not copy the sync state */
3785 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3788 if (obj->vtable->klass->has_references)
3789 mono_gc_wbarrier_object (o);
3791 if (G_UNLIKELY (profile_allocs))
3792 mono_profiler_allocation (o, obj->vtable->klass);
3794 if (obj->vtable->klass->has_finalize)
3795 mono_object_register_finalizer (o);
3800 * mono_array_full_copy:
3801 * @src: source array to copy
3802 * @dest: destination array
3804 * Copies the content of one array to another with exactly the same type and size.
3807 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3809 mono_array_size_t size;
3810 MonoClass *klass = src->obj.vtable->klass;
3812 MONO_ARCH_SAVE_REGS;
3814 g_assert (klass == dest->obj.vtable->klass);
3816 size = mono_array_length (src);
3817 g_assert (size == mono_array_length (dest));
3818 size *= mono_array_element_size (klass);
3820 if (klass->element_class->valuetype) {
3821 if (klass->element_class->has_references)
3822 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3824 memcpy (&dest->vector, &src->vector, size);
3826 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3829 memcpy (&dest->vector, &src->vector, size);
3834 * mono_array_clone_in_domain:
3835 * @domain: the domain in which the array will be cloned into
3836 * @array: the array to clone
3838 * This routine returns a copy of the array that is hosted on the
3839 * specified MonoDomain.
3842 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3845 mono_array_size_t size, i;
3846 mono_array_size_t *sizes;
3847 MonoClass *klass = array->obj.vtable->klass;
3849 MONO_ARCH_SAVE_REGS;
3851 if (array->bounds == NULL) {
3852 size = mono_array_length (array);
3853 o = mono_array_new_full (domain, klass, &size, NULL);
3855 size *= mono_array_element_size (klass);
3857 if (klass->element_class->valuetype) {
3858 if (klass->element_class->has_references)
3859 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3861 memcpy (&o->vector, &array->vector, size);
3863 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3866 memcpy (&o->vector, &array->vector, size);
3871 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3872 size = mono_array_element_size (klass);
3873 for (i = 0; i < klass->rank; ++i) {
3874 sizes [i] = array->bounds [i].length;
3875 size *= array->bounds [i].length;
3876 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3878 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3880 if (klass->element_class->valuetype) {
3881 if (klass->element_class->has_references)
3882 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3884 memcpy (&o->vector, &array->vector, size);
3886 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3889 memcpy (&o->vector, &array->vector, size);
3897 * @array: the array to clone
3899 * Returns: A newly created array who is a shallow copy of @array
3902 mono_array_clone (MonoArray *array)
3904 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3907 /* helper macros to check for overflow when calculating the size of arrays */
3908 #ifdef MONO_BIG_ARRAYS
3909 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3910 #define MYGUINT_MAX MYGUINT64_MAX
3911 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3912 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3913 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3914 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3915 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3917 #define MYGUINT32_MAX 4294967295U
3918 #define MYGUINT_MAX MYGUINT32_MAX
3919 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3920 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3921 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3922 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3923 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3927 * mono_array_new_full:
3928 * @domain: domain where the object is created
3929 * @array_class: array class
3930 * @lengths: lengths for each dimension in the array
3931 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3933 * This routine creates a new array objects with the given dimensions,
3934 * lower bounds and type.
3937 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3939 mono_array_size_t byte_len, len, bounds_size;
3945 if (!array_class->inited)
3946 mono_class_init (array_class);
3948 byte_len = mono_array_element_size (array_class);
3951 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3952 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3954 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3958 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3960 for (i = 0; i < array_class->rank; ++i) {
3961 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3963 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3964 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3969 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3970 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3972 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3973 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3974 byte_len += sizeof (MonoArray);
3977 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3978 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3979 byte_len = (byte_len + 3) & ~3;
3980 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3981 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3982 byte_len += bounds_size;
3985 * Following three lines almost taken from mono_object_new ():
3986 * they need to be kept in sync.
3988 vtable = mono_class_vtable (domain, array_class);
3989 if (!array_class->has_references) {
3990 o = mono_object_allocate_ptrfree (byte_len, vtable);
3991 #if NEED_TO_ZERO_PTRFREE
3992 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3994 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3995 o = mono_object_allocate_spec (byte_len, vtable);
3997 o = mono_object_allocate (byte_len, vtable);
4000 array = (MonoArray*)o;
4001 array->max_length = len;
4004 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4005 array->bounds = bounds;
4006 for (i = 0; i < array_class->rank; ++i) {
4007 bounds [i].length = lengths [i];
4009 bounds [i].lower_bound = lower_bounds [i];
4013 if (G_UNLIKELY (profile_allocs))
4014 mono_profiler_allocation (o, array_class);
4021 * @domain: domain where the object is created
4022 * @eclass: element class
4023 * @n: number of array elements
4025 * This routine creates a new szarray with @n elements of type @eclass.
4028 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4032 MONO_ARCH_SAVE_REGS;
4034 ac = mono_array_class_get (eclass, 1);
4037 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4041 * mono_array_new_specific:
4042 * @vtable: a vtable in the appropriate domain for an initialized class
4043 * @n: number of array elements
4045 * This routine is a fast alternative to mono_array_new() for code which
4046 * can be sure about the domain it operates in.
4049 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4053 guint32 byte_len, elem_size;
4055 MONO_ARCH_SAVE_REGS;
4057 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4062 elem_size = mono_array_element_size (vtable->klass);
4063 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4064 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4067 byte_len = n * elem_size;
4068 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4069 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4072 byte_len += sizeof (MonoArray);
4073 if (!vtable->klass->has_references) {
4074 o = mono_object_allocate_ptrfree (byte_len, vtable);
4075 #if NEED_TO_ZERO_PTRFREE
4076 ((MonoArray*)o)->bounds = NULL;
4077 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4079 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4080 o = mono_object_allocate_spec (byte_len, vtable);
4082 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4083 o = mono_object_allocate (byte_len, vtable);
4086 ao = (MonoArray *)o;
4088 if (G_UNLIKELY (profile_allocs))
4089 mono_profiler_allocation (o, vtable->klass);
4095 * mono_string_new_utf16:
4096 * @text: a pointer to an utf16 string
4097 * @len: the length of the string
4099 * Returns: A newly created string object which contains @text.
4102 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4106 s = mono_string_new_size (domain, len);
4107 g_assert (s != NULL);
4109 memcpy (mono_string_chars (s), text, len * 2);
4115 * mono_string_new_size:
4116 * @text: a pointer to an utf16 string
4117 * @len: the length of the string
4119 * Returns: A newly created string object of @len
4122 mono_string_new_size (MonoDomain *domain, gint32 len)
4126 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4128 /* overflow ? can't fit it, can't allocate it! */
4130 mono_gc_out_of_memory (-1);
4132 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4134 s = mono_object_allocate_ptrfree (size, vtable);
4137 #if NEED_TO_ZERO_PTRFREE
4140 if (G_UNLIKELY (profile_allocs))
4141 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4147 * mono_string_new_len:
4148 * @text: a pointer to an utf8 string
4149 * @length: number of bytes in @text to consider
4151 * Returns: A newly created string object which contains @text.
4154 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4156 GError *error = NULL;
4157 MonoString *o = NULL;
4159 glong items_written;
4161 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4164 o = mono_string_new_utf16 (domain, ut, items_written);
4166 g_error_free (error);
4175 * @text: a pointer to an utf8 string
4177 * Returns: A newly created string object which contains @text.
4180 mono_string_new (MonoDomain *domain, const char *text)
4182 GError *error = NULL;
4183 MonoString *o = NULL;
4185 glong items_written;
4190 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4193 o = mono_string_new_utf16 (domain, ut, items_written);
4195 g_error_free (error);
4198 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4203 MonoString *o = NULL;
4205 if (!g_utf8_validate (text, -1, &end))
4208 len = g_utf8_strlen (text, -1);
4209 o = mono_string_new_size (domain, len);
4210 str = mono_string_chars (o);
4212 while (text < end) {
4213 *str++ = g_utf8_get_char (text);
4214 text = g_utf8_next_char (text);
4221 * mono_string_new_wrapper:
4222 * @text: pointer to utf8 characters.
4224 * Helper function to create a string object from @text in the current domain.
4227 mono_string_new_wrapper (const char *text)
4229 MonoDomain *domain = mono_domain_get ();
4231 MONO_ARCH_SAVE_REGS;
4234 return mono_string_new (domain, text);
4241 * @class: the class of the value
4242 * @value: a pointer to the unboxed data
4244 * Returns: A newly created object which contains @value.
4247 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4253 g_assert (class->valuetype);
4254 if (mono_class_is_nullable (class))
4255 return mono_nullable_box (value, class);
4257 vtable = mono_class_vtable (domain, class);
4258 size = mono_class_instance_size (class);
4259 res = mono_object_new_alloc_specific (vtable);
4260 if (G_UNLIKELY (profile_allocs))
4261 mono_profiler_allocation (res, class);
4263 size = size - sizeof (MonoObject);
4266 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4269 #if NO_UNALIGNED_ACCESS
4270 memcpy ((char *)res + sizeof (MonoObject), value, size);
4274 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4277 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4280 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4283 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4286 memcpy ((char *)res + sizeof (MonoObject), value, size);
4289 if (class->has_finalize)
4290 mono_object_register_finalizer (res);
4296 * @dest: destination pointer
4297 * @src: source pointer
4298 * @klass: a valuetype class
4300 * Copy a valuetype from @src to @dest. This function must be used
4301 * when @klass contains references fields.
4304 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4306 int size = mono_class_value_size (klass, NULL);
4307 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4308 memcpy (dest, src, size);
4312 * mono_value_copy_array:
4313 * @dest: destination array
4314 * @dest_idx: index in the @dest array
4315 * @src: source pointer
4316 * @count: number of items
4318 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4319 * This function must be used when @klass contains references fields.
4320 * Overlap is handled.
4323 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4325 int size = mono_array_element_size (dest->obj.vtable->klass);
4326 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4327 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4328 memmove (d, src, size * count);
4332 * mono_object_get_domain:
4333 * @obj: object to query
4335 * Returns: the MonoDomain where the object is hosted
4338 mono_object_get_domain (MonoObject *obj)
4340 return mono_object_domain (obj);
4344 * mono_object_get_class:
4345 * @obj: object to query
4347 * Returns: the MonOClass of the object.
4350 mono_object_get_class (MonoObject *obj)
4352 return mono_object_class (obj);
4355 * mono_object_get_size:
4356 * @o: object to query
4358 * Returns: the size, in bytes, of @o
4361 mono_object_get_size (MonoObject* o)
4363 MonoClass* klass = mono_object_class (o);
4364 if (klass == mono_defaults.string_class) {
4365 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4366 } else if (o->vtable->rank) {
4367 MonoArray *array = (MonoArray*)o;
4368 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4369 if (array->bounds) {
4372 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4376 return mono_class_instance_size (klass);
4381 * mono_object_unbox:
4382 * @obj: object to unbox
4384 * Returns: a pointer to the start of the valuetype boxed in this
4387 * This method will assert if the object passed is not a valuetype.
4390 mono_object_unbox (MonoObject *obj)
4392 /* add assert for valuetypes? */
4393 g_assert (obj->vtable->klass->valuetype);
4394 return ((char*)obj) + sizeof (MonoObject);
4398 * mono_object_isinst:
4400 * @klass: a pointer to a class
4402 * Returns: @obj if @obj is derived from @klass
4405 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4408 mono_class_init (klass);
4410 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4411 return mono_object_isinst_mbyref (obj, klass);
4416 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4420 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4429 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4430 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4434 MonoClass *oklass = vt->klass;
4435 if ((oklass == mono_defaults.transparent_proxy_class))
4436 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4438 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4442 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4444 MonoDomain *domain = mono_domain_get ();
4446 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4447 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4448 MonoMethod *im = NULL;
4451 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4452 im = mono_object_get_virtual_method (rp, im);
4455 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4458 res = mono_runtime_invoke (im, rp, pa, NULL);
4460 if (*(MonoBoolean *) mono_object_unbox(res)) {
4461 /* Update the vtable of the remote type, so it can safely cast to this new type */
4462 mono_upgrade_remote_class (domain, obj, klass);
4471 * mono_object_castclass_mbyref:
4473 * @klass: a pointer to a class
4475 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4478 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4480 if (!obj) return NULL;
4481 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4483 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4485 "InvalidCastException"));
4490 MonoDomain *orig_domain;
4496 str_lookup (MonoDomain *domain, gpointer user_data)
4498 LDStrInfo *info = user_data;
4499 if (info->res || domain == info->orig_domain)
4501 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4507 mono_string_get_pinned (MonoString *str)
4511 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4512 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4513 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4514 news->length = mono_string_length (str);
4519 #define mono_string_get_pinned(str) (str)
4523 mono_string_is_interned_lookup (MonoString *str, int insert)
4525 MonoGHashTable *ldstr_table;
4529 domain = ((MonoObject *)str)->vtable->domain;
4530 ldstr_table = domain->ldstr_table;
4532 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4537 str = mono_string_get_pinned (str);
4538 mono_g_hash_table_insert (ldstr_table, str, str);
4542 LDStrInfo ldstr_info;
4543 ldstr_info.orig_domain = domain;
4544 ldstr_info.ins = str;
4545 ldstr_info.res = NULL;
4547 mono_domain_foreach (str_lookup, &ldstr_info);
4548 if (ldstr_info.res) {
4550 * the string was already interned in some other domain:
4551 * intern it in the current one as well.
4553 mono_g_hash_table_insert (ldstr_table, str, str);
4563 * mono_string_is_interned:
4564 * @o: String to probe
4566 * Returns whether the string has been interned.
4569 mono_string_is_interned (MonoString *o)
4571 return mono_string_is_interned_lookup (o, FALSE);
4575 * mono_string_intern:
4576 * @o: String to intern
4578 * Interns the string passed.
4579 * Returns: The interned string.
4582 mono_string_intern (MonoString *str)
4584 return mono_string_is_interned_lookup (str, TRUE);
4589 * @domain: the domain where the string will be used.
4590 * @image: a metadata context
4591 * @idx: index into the user string table.
4593 * Implementation for the ldstr opcode.
4594 * Returns: a loaded string from the @image/@idx combination.
4597 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4599 MONO_ARCH_SAVE_REGS;
4602 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4604 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4608 * mono_ldstr_metadata_sig
4609 * @domain: the domain for the string
4610 * @sig: the signature of a metadata string
4612 * Returns: a MonoString for a string stored in the metadata
4615 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4617 const char *str = sig;
4618 MonoString *o, *interned;
4621 len2 = mono_metadata_decode_blob_size (str, &str);
4624 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4625 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4628 guint16 *p2 = (guint16*)mono_string_chars (o);
4629 for (i = 0; i < len2; ++i) {
4630 *p2 = GUINT16_FROM_LE (*p2);
4636 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4638 /* o will get garbage collected */
4642 o = mono_string_get_pinned (o);
4643 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4650 * mono_string_to_utf8:
4651 * @s: a System.String
4653 * Return the UTF8 representation for @s.
4654 * the resulting buffer nedds to be freed with g_free().
4657 mono_string_to_utf8 (MonoString *s)
4661 GError *error = NULL;
4667 return g_strdup ("");
4669 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4671 MonoException *exc = mono_get_exception_argument ("string", error->message);
4672 g_error_free (error);
4673 mono_raise_exception(exc);
4675 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4676 if (s->length > written) {
4677 /* allocate the total length and copy the part of the string that has been converted */
4678 char *as2 = g_malloc0 (s->length);
4679 memcpy (as2, as, written);
4688 * mono_string_to_utf16:
4691 * Return an null-terminated array of the utf-16 chars
4692 * contained in @s. The result must be freed with g_free().
4693 * This is a temporary helper until our string implementation
4694 * is reworked to always include the null terminating char.
4697 mono_string_to_utf16 (MonoString *s)
4704 as = g_malloc ((s->length * 2) + 2);
4705 as [(s->length * 2)] = '\0';
4706 as [(s->length * 2) + 1] = '\0';
4709 return (gunichar2 *)(as);
4712 memcpy (as, mono_string_chars(s), s->length * 2);
4713 return (gunichar2 *)(as);
4717 * mono_string_from_utf16:
4718 * @data: the UTF16 string (LPWSTR) to convert
4720 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4722 * Returns: a MonoString.
4725 mono_string_from_utf16 (gunichar2 *data)
4727 MonoDomain *domain = mono_domain_get ();
4733 while (data [len]) len++;
4735 return mono_string_new_utf16 (domain, data, len);
4740 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4747 return mono_string_to_utf8 (s);
4749 r = mono_string_to_utf8 (s);
4753 len = strlen (r) + 1;
4755 mp_s = mono_mempool_alloc (mp, len);
4757 mp_s = mono_image_alloc (image, len);
4759 memcpy (mp_s, r, len);
4767 * mono_string_to_utf8_image:
4768 * @s: a System.String
4770 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4773 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4775 return mono_string_to_utf8_internal (NULL, image, s);
4779 * mono_string_to_utf8_mp:
4780 * @s: a System.String
4782 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4785 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4787 return mono_string_to_utf8_internal (mp, NULL, s);
4791 default_ex_handler (MonoException *ex)
4793 MonoObject *o = (MonoObject*)ex;
4794 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4798 static MonoExceptionFunc ex_handler = default_ex_handler;
4801 * mono_install_handler:
4802 * @func: exception handler
4804 * This is an internal JIT routine used to install the handler for exceptions
4808 mono_install_handler (MonoExceptionFunc func)
4810 ex_handler = func? func: default_ex_handler;
4814 * mono_raise_exception:
4815 * @ex: exception object
4817 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4820 mono_raise_exception (MonoException *ex)
4823 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4824 * that will cause gcc to omit the function epilog, causing problems when
4825 * the JIT tries to walk the stack, since the return address on the stack
4826 * will point into the next function in the executable, not this one.
4829 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4830 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4836 * mono_wait_handle_new:
4837 * @domain: Domain where the object will be created
4838 * @handle: Handle for the wait handle
4840 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4843 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4845 MonoWaitHandle *res;
4846 gpointer params [1];
4847 static MonoMethod *handle_set;
4849 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4851 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4853 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4855 params [0] = &handle;
4856 mono_runtime_invoke (handle_set, res, params, NULL);
4862 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4864 static MonoClassField *f_os_handle;
4865 static MonoClassField *f_safe_handle;
4867 if (!f_os_handle && !f_safe_handle) {
4868 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4869 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4874 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4878 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4884 * mono_async_result_new:
4885 * @domain:domain where the object will be created.
4886 * @handle: wait handle.
4887 * @state: state to pass to AsyncResult
4888 * @data: C closure data.
4890 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4891 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4895 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4897 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4898 MonoMethod *method = mono_get_context_capture_method ();
4900 /* we must capture the execution context from the original thread */
4902 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4903 /* note: result may be null if the flow is suppressed */
4907 MONO_OBJECT_SETREF (res, object_data, object_data);
4908 MONO_OBJECT_SETREF (res, async_state, state);
4910 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4912 res->sync_completed = FALSE;
4913 res->completed = FALSE;
4919 mono_message_init (MonoDomain *domain,
4920 MonoMethodMessage *this,
4921 MonoReflectionMethod *method,
4922 MonoArray *out_args)
4924 static MonoClass *object_array_klass;
4925 static MonoClass *byte_array_klass;
4926 static MonoClass *string_array_klass;
4927 MonoMethodSignature *sig = mono_method_signature (method->method);
4933 if (!object_array_klass) {
4936 klass = mono_array_class_get (mono_defaults.object_class, 1);
4939 mono_memory_barrier ();
4940 object_array_klass = klass;
4942 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4945 mono_memory_barrier ();
4946 byte_array_klass = klass;
4948 klass = mono_array_class_get (mono_defaults.string_class, 1);
4951 mono_memory_barrier ();
4952 string_array_klass = klass;
4955 MONO_OBJECT_SETREF (this, method, method);
4957 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4958 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4959 this->async_result = NULL;
4960 this->call_type = CallType_Sync;
4962 names = g_new (char *, sig->param_count);
4963 mono_method_get_param_names (method->method, (const char **) names);
4964 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4966 for (i = 0; i < sig->param_count; i++) {
4967 name = mono_string_new (domain, names [i]);
4968 mono_array_setref (this->names, i, name);
4972 for (i = 0, j = 0; i < sig->param_count; i++) {
4973 if (sig->params [i]->byref) {
4975 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4976 mono_array_setref (this->args, i, arg);
4980 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4984 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4987 mono_array_set (this->arg_types, guint8, i, arg_type);
4992 * mono_remoting_invoke:
4993 * @real_proxy: pointer to a RealProxy object
4994 * @msg: The MonoMethodMessage to execute
4995 * @exc: used to store exceptions
4996 * @out_args: used to store output arguments
4998 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4999 * IMessage interface and it is not trivial to extract results from there. So
5000 * we call an helper method PrivateInvoke instead of calling
5001 * RealProxy::Invoke() directly.
5003 * Returns: the result object.
5006 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5007 MonoObject **exc, MonoArray **out_args)
5009 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5012 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5015 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5017 real_proxy->vtable->domain->private_invoke_method = im;
5020 pa [0] = real_proxy;
5025 return mono_runtime_invoke (im, NULL, pa, exc);
5029 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5030 MonoObject **exc, MonoArray **out_args)
5032 static MonoClass *object_array_klass;
5035 MonoMethodSignature *sig;
5037 int i, j, outarg_count = 0;
5039 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5041 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5042 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5043 target = tp->rp->unwrapped_server;
5045 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5049 domain = mono_domain_get ();
5050 method = msg->method->method;
5051 sig = mono_method_signature (method);
5053 for (i = 0; i < sig->param_count; i++) {
5054 if (sig->params [i]->byref)
5058 if (!object_array_klass) {
5061 klass = mono_array_class_get (mono_defaults.object_class, 1);
5064 mono_memory_barrier ();
5065 object_array_klass = klass;
5068 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5069 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5072 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5074 for (i = 0, j = 0; i < sig->param_count; i++) {
5075 if (sig->params [i]->byref) {
5077 arg = mono_array_get (msg->args, gpointer, i);
5078 mono_array_setref (*out_args, j, arg);
5087 * mono_print_unhandled_exception:
5088 * @exc: The exception
5090 * Prints the unhandled exception.
5093 mono_print_unhandled_exception (MonoObject *exc)
5095 char *message = (char *) "";
5099 gboolean free_message = FALSE;
5101 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5102 klass = exc->vtable->klass;
5104 while (klass && method == NULL) {
5105 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5107 klass = klass->parent;
5112 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5114 message = mono_string_to_utf8 (str);
5115 free_message = TRUE;
5120 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5121 * exc->vtable->klass->name, message);
5123 g_printerr ("\nUnhandled Exception: %s\n", message);
5130 * mono_delegate_ctor:
5131 * @this: pointer to an uninitialized delegate object
5132 * @target: target object
5133 * @addr: pointer to native code
5136 * Initialize a delegate and sets a specific method, not the one
5137 * associated with addr. This is useful when sharing generic code.
5138 * In that case addr will most probably not be associated with the
5139 * correct instantiation of the method.
5142 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5144 MonoDelegate *delegate = (MonoDelegate *)this;
5151 delegate->method = method;
5153 class = this->vtable->klass;
5154 mono_stats.delegate_creations++;
5156 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5158 method = mono_marshal_get_remoting_invoke (method);
5159 delegate->method_ptr = mono_compile_method (method);
5160 MONO_OBJECT_SETREF (delegate, target, target);
5161 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5162 method = mono_marshal_get_unbox_wrapper (method);
5163 delegate->method_ptr = mono_compile_method (method);
5164 MONO_OBJECT_SETREF (delegate, target, target);
5166 delegate->method_ptr = addr;
5167 MONO_OBJECT_SETREF (delegate, target, target);
5170 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5174 * mono_delegate_ctor:
5175 * @this: pointer to an uninitialized delegate object
5176 * @target: target object
5177 * @addr: pointer to native code
5179 * This is used to initialize a delegate.
5182 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5184 MonoDomain *domain = mono_domain_get ();
5186 MonoMethod *method = NULL;
5190 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5191 method = ji->method;
5192 g_assert (!method->klass->generic_container);
5195 mono_delegate_ctor_with_method (this, target, addr, method);
5199 * mono_method_call_message_new:
5200 * @method: method to encapsulate
5201 * @params: parameters to the method
5202 * @invoke: optional, delegate invoke.
5203 * @cb: async callback delegate.
5204 * @state: state passed to the async callback.
5206 * Translates arguments pointers into a MonoMethodMessage.
5209 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5210 MonoDelegate **cb, MonoObject **state)
5212 MonoDomain *domain = mono_domain_get ();
5213 MonoMethodSignature *sig = mono_method_signature (method);
5214 MonoMethodMessage *msg;
5217 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5220 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5221 count = sig->param_count - 2;
5223 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5224 count = sig->param_count;
5227 for (i = 0; i < count; i++) {
5232 if (sig->params [i]->byref)
5233 vpos = *((gpointer *)params [i]);
5237 type = sig->params [i]->type;
5238 class = mono_class_from_mono_type (sig->params [i]);
5240 if (class->valuetype)
5241 arg = mono_value_box (domain, class, vpos);
5243 arg = *((MonoObject **)vpos);
5245 mono_array_setref (msg->args, i, arg);
5248 if (cb != NULL && state != NULL) {
5249 *cb = *((MonoDelegate **)params [i]);
5251 *state = *((MonoObject **)params [i]);
5258 * mono_method_return_message_restore:
5260 * Restore results from message based processing back to arguments pointers
5263 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5265 MonoMethodSignature *sig = mono_method_signature (method);
5266 int i, j, type, size, out_len;
5268 if (out_args == NULL)
5270 out_len = mono_array_length (out_args);
5274 for (i = 0, j = 0; i < sig->param_count; i++) {
5275 MonoType *pt = sig->params [i];
5280 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5282 arg = mono_array_get (out_args, gpointer, j);
5286 case MONO_TYPE_VOID:
5287 g_assert_not_reached ();
5291 case MONO_TYPE_BOOLEAN:
5294 case MONO_TYPE_CHAR:
5301 case MONO_TYPE_VALUETYPE: {
5303 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5304 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5307 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5308 memset (*((gpointer *)params [i]), 0, size);
5312 case MONO_TYPE_STRING:
5313 case MONO_TYPE_CLASS:
5314 case MONO_TYPE_ARRAY:
5315 case MONO_TYPE_SZARRAY:
5316 case MONO_TYPE_OBJECT:
5317 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5320 g_assert_not_reached ();
5329 * mono_load_remote_field:
5330 * @this: pointer to an object
5331 * @klass: klass of the object containing @field
5332 * @field: the field to load
5333 * @res: a storage to store the result
5335 * This method is called by the runtime on attempts to load fields of
5336 * transparent proxy objects. @this points to such TP, @klass is the class of
5337 * the object containing @field. @res is a storage location which can be
5338 * used to store the result.
5340 * Returns: an address pointing to the value of field.
5343 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5345 static MonoMethod *getter = NULL;
5346 MonoDomain *domain = mono_domain_get ();
5347 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5348 MonoClass *field_class;
5349 MonoMethodMessage *msg;
5350 MonoArray *out_args;
5354 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5355 g_assert (res != NULL);
5357 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5358 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5363 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5367 field_class = mono_class_from_mono_type (field->type);
5369 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5370 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5371 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5373 full_name = mono_type_get_full_name (klass);
5374 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5375 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5378 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5380 if (exc) mono_raise_exception ((MonoException *)exc);
5382 if (mono_array_length (out_args) == 0)
5385 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5387 if (field_class->valuetype) {
5388 return ((char *)*res) + sizeof (MonoObject);
5394 * mono_load_remote_field_new:
5399 * Missing documentation.
5402 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5404 static MonoMethod *getter = NULL;
5405 MonoDomain *domain = mono_domain_get ();
5406 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5407 MonoClass *field_class;
5408 MonoMethodMessage *msg;
5409 MonoArray *out_args;
5410 MonoObject *exc, *res;
5413 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5415 field_class = mono_class_from_mono_type (field->type);
5417 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5419 if (field_class->valuetype) {
5420 res = mono_object_new (domain, field_class);
5421 val = ((gchar *) res) + sizeof (MonoObject);
5425 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5430 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5434 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5435 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5437 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5439 full_name = mono_type_get_full_name (klass);
5440 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5441 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5444 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5446 if (exc) mono_raise_exception ((MonoException *)exc);
5448 if (mono_array_length (out_args) == 0)
5451 res = mono_array_get (out_args, MonoObject *, 0);
5457 * mono_store_remote_field:
5458 * @this: pointer to an object
5459 * @klass: klass of the object containing @field
5460 * @field: the field to load
5461 * @val: the value/object to store
5463 * This method is called by the runtime on attempts to store fields of
5464 * transparent proxy objects. @this points to such TP, @klass is the class of
5465 * the object containing @field. @val is the new value to store in @field.
5468 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5470 static MonoMethod *setter = NULL;
5471 MonoDomain *domain = mono_domain_get ();
5472 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5473 MonoClass *field_class;
5474 MonoMethodMessage *msg;
5475 MonoArray *out_args;
5480 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5482 field_class = mono_class_from_mono_type (field->type);
5484 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5485 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5486 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5491 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5495 if (field_class->valuetype)
5496 arg = mono_value_box (domain, field_class, val);
5498 arg = *((MonoObject **)val);
5501 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5502 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5504 full_name = mono_type_get_full_name (klass);
5505 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5506 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5507 mono_array_setref (msg->args, 2, arg);
5510 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5512 if (exc) mono_raise_exception ((MonoException *)exc);
5516 * mono_store_remote_field_new:
5522 * Missing documentation
5525 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5527 static MonoMethod *setter = NULL;
5528 MonoDomain *domain = mono_domain_get ();
5529 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5530 MonoClass *field_class;
5531 MonoMethodMessage *msg;
5532 MonoArray *out_args;
5536 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5538 field_class = mono_class_from_mono_type (field->type);
5540 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5541 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5542 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5547 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5551 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5552 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5554 full_name = mono_type_get_full_name (klass);
5555 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5556 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5557 mono_array_setref (msg->args, 2, arg);
5560 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5562 if (exc) mono_raise_exception ((MonoException *)exc);
5566 * mono_create_ftnptr:
5568 * Given a function address, create a function descriptor for it.
5569 * This is only needed on IA64 and PPC64.
5572 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5577 mono_domain_lock (domain);
5578 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5579 mono_domain_unlock (domain);
5585 #elif defined(__ppc64__) || defined(__powerpc64__)
5588 mono_domain_lock (domain);
5589 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5590 mono_domain_unlock (domain);
5603 * mono_get_addr_from_ftnptr:
5605 * Given a pointer to a function descriptor, return the function address.
5606 * This is only needed on IA64 and PPC64.
5609 mono_get_addr_from_ftnptr (gpointer descr)
5611 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5612 return *(gpointer*)descr;
5620 * mono_string_chars:
5623 * Returns a pointer to the UCS16 characters stored in the MonoString
5626 mono_string_chars(MonoString *s)
5628 /* This method is here only for documentation extraction, this is a macro */
5632 * mono_string_length:
5635 * Returns the lenght in characters of the string
5638 mono_string_length (MonoString *s)
5640 /* This method is here only for documentation extraction, this is a macro */