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 * LOCKING: requires the loader and domain locks.
1189 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1192 guint32 imt_collisions_bitmap = 0;
1193 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1194 int method_count = 0;
1195 gboolean record_method_count_for_max_collisions = FALSE;
1198 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1200 for (i = 0; i < klass->interface_offsets_count; ++i) {
1201 MonoClass *iface = klass->interfaces_packed [i];
1202 int interface_offset = klass->interface_offsets_packed [i];
1203 int method_slot_in_interface;
1204 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1207 if (slot_num >= 0 && iface->is_inflated) {
1209 * The imt slot of the method is the same as for its declaring method,
1210 * see the comment in mono_method_get_imt_slot (), so we can
1211 * avoid inflating methods which will be discarded by
1212 * add_imt_builder_entry anyway.
1214 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1215 if (mono_method_get_imt_slot (method) != slot_num)
1218 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1219 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1222 if (extra_interfaces) {
1223 int interface_offset = klass->vtable_size;
1225 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1226 MonoClass* iface = list_item->data;
1227 int method_slot_in_interface;
1228 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1229 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1230 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1232 interface_offset += iface->method.count;
1235 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1236 /* overwrite the imt slot only if we're building all the entries or if
1237 * we're uilding this specific one
1239 if (slot_num < 0 || i == slot_num)
1240 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1242 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1244 if (imt_builder [i] != NULL) {
1245 int methods_in_slot = imt_builder [i]->children + 1;
1246 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1247 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1248 record_method_count_for_max_collisions = TRUE;
1250 method_count += methods_in_slot;
1254 mono_stats.imt_number_of_methods += method_count;
1255 if (record_method_count_for_max_collisions) {
1256 mono_stats.imt_method_count_when_max_collisions = method_count;
1259 for (i = 0; i < MONO_IMT_SIZE; i++) {
1260 MonoImtBuilderEntry* entry = imt_builder [i];
1261 while (entry != NULL) {
1262 MonoImtBuilderEntry* next = entry->next;
1268 /* we OR the bitmap since we may build just a single imt slot at a time */
1269 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1273 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1274 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1277 static gpointer imt_trampoline = NULL;
1280 mono_install_imt_trampoline (gpointer tramp_code)
1282 imt_trampoline = tramp_code;
1285 static gpointer vtable_trampoline = NULL;
1288 mono_install_vtable_trampoline (gpointer tramp_code)
1290 vtable_trampoline = tramp_code;
1294 * mono_vtable_build_imt_slot:
1295 * @vtable: virtual object table struct
1296 * @imt_slot: slot in the IMT table
1298 * Fill the given @imt_slot in the IMT table of @vtable with
1299 * a trampoline or a thunk for the case of collisions.
1300 * This is part of the internal mono API.
1302 * LOCKING: Take the domain lock.
1305 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1307 gpointer *imt = (gpointer*)vtable;
1308 imt -= MONO_IMT_SIZE;
1309 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1311 /* no support for extra interfaces: the proxy objects will need
1312 * to build the complete IMT
1313 * Update and heck needs to ahppen inside the proper domain lock, as all
1314 * the changes made to a MonoVTable.
1316 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1317 mono_domain_lock (vtable->domain);
1318 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1319 if (imt [imt_slot] == imt_trampoline)
1320 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1321 mono_domain_unlock (vtable->domain);
1322 mono_loader_unlock ();
1327 * The first two free list entries both belong to the wait list: The
1328 * first entry is the pointer to the head of the list and the second
1329 * entry points to the last element. That way appending and removing
1330 * the first element are both O(1) operations.
1332 #define NUM_FREE_LISTS 12
1333 #define FIRST_FREE_LIST_SIZE 64
1334 #define MAX_WAIT_LENGTH 50
1335 #define THUNK_THRESHOLD 10
1338 * LOCKING: The domain lock must be held.
1341 init_thunk_free_lists (MonoDomain *domain)
1343 if (domain->thunk_free_lists)
1345 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1349 list_index_for_size (int item_size)
1352 int size = FIRST_FREE_LIST_SIZE;
1354 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1363 * mono_method_alloc_generic_virtual_thunk:
1365 * @size: size in bytes
1367 * Allocs size bytes to be used for the code of a generic virtual
1368 * thunk. It's either allocated from the domain's code manager or
1369 * reused from a previously invalidated piece.
1371 * LOCKING: The domain lock must be held.
1374 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1376 static gboolean inited = FALSE;
1377 static int generic_virtual_thunks_size = 0;
1381 MonoThunkFreeList **l;
1383 init_thunk_free_lists (domain);
1385 size += sizeof (guint32);
1386 if (size < sizeof (MonoThunkFreeList))
1387 size = sizeof (MonoThunkFreeList);
1389 i = list_index_for_size (size);
1390 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1391 if ((*l)->size >= size) {
1392 MonoThunkFreeList *item = *l;
1394 return ((guint32*)item) + 1;
1398 /* no suitable item found - search lists of larger sizes */
1399 while (++i < NUM_FREE_LISTS) {
1400 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1403 g_assert (item->size > size);
1404 domain->thunk_free_lists [i] = item->next;
1405 return ((guint32*)item) + 1;
1408 /* still nothing found - allocate it */
1410 mono_counters_register ("Generic virtual thunk bytes",
1411 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1414 generic_virtual_thunks_size += size;
1416 p = mono_domain_code_reserve (domain, size);
1423 * LOCKING: The domain lock must be held.
1426 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1429 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1431 init_thunk_free_lists (domain);
1433 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1434 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1435 int length = item->length;
1438 /* unlink the first item from the wait list */
1439 domain->thunk_free_lists [0] = item->next;
1440 domain->thunk_free_lists [0]->length = length - 1;
1442 i = list_index_for_size (item->size);
1444 /* put it in the free list */
1445 item->next = domain->thunk_free_lists [i];
1446 domain->thunk_free_lists [i] = item;
1450 if (domain->thunk_free_lists [1]) {
1451 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1452 domain->thunk_free_lists [0]->length++;
1454 g_assert (!domain->thunk_free_lists [0]);
1456 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1457 domain->thunk_free_lists [0]->length = 1;
1461 typedef struct _GenericVirtualCase {
1462 MonoGenericInst *inst;
1465 struct _GenericVirtualCase *next;
1466 } GenericVirtualCase;
1469 * mono_method_add_generic_virtual_invocation:
1471 * @vtable_slot: pointer to the vtable slot
1472 * @method_inst: the method's method_inst
1473 * @code: the method's code
1475 * Registers a call via unmanaged code to a generic virtual method
1476 * instantiation. If the number of calls reaches a threshold
1477 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1478 * virtual method thunk.
1481 mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable_slot,
1482 MonoGenericInst *method_inst, gpointer code)
1484 static gboolean inited = FALSE;
1485 static int num_added = 0;
1487 GenericVirtualCase *gvc, *list;
1488 MonoImtBuilderEntry *entries;
1492 mono_domain_lock (domain);
1493 if (!domain->generic_virtual_cases)
1494 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1496 /* Check whether the case was already added */
1497 gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1499 if (gvc->inst == method_inst)
1504 /* If not found, make a new one */
1506 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1507 gvc->inst = method_inst;
1510 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1512 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1515 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1521 if (++gvc->count < THUNK_THRESHOLD) {
1522 mono_domain_unlock (domain);
1527 for (list = gvc; list; list = list->next) {
1528 MonoImtBuilderEntry *entry;
1530 if (list->count < THUNK_THRESHOLD)
1533 entry = g_new0 (MonoImtBuilderEntry, 1);
1534 entry->key = list->inst;
1535 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1537 entry->children = entries->children + 1;
1538 entry->next = entries;
1542 sorted = imt_sort_slot_entries (entries);
1544 if (*vtable_slot != vtable_trampoline)
1545 invalidate_generic_virtual_thunk (domain, *vtable_slot);
1547 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1550 mono_domain_unlock (domain);
1553 MonoImtBuilderEntry *next = entries->next;
1558 for (i = 0; i < sorted->len; ++i)
1559 g_free (g_ptr_array_index (sorted, i));
1560 g_ptr_array_free (sorted, TRUE);
1563 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1566 * mono_class_vtable:
1567 * @domain: the application domain
1568 * @class: the class to initialize
1570 * VTables are domain specific because we create domain specific code, and
1571 * they contain the domain specific static class data.
1572 * On failure, NULL is returned, and class->exception_type is set.
1575 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1577 MonoClassRuntimeInfo *runtime_info;
1581 /* this check can be inlined in jitted code, too */
1582 runtime_info = class->runtime_info;
1583 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1584 return runtime_info->domain_vtables [domain->domain_id];
1585 if (class->exception_type)
1587 return mono_class_create_runtime_vtable (domain, class);
1591 * mono_class_try_get_vtable:
1592 * @domain: the application domain
1593 * @class: the class to initialize
1595 * This function tries to get the associated vtable from @class if
1596 * it was already created.
1599 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1601 MonoClassRuntimeInfo *runtime_info;
1605 runtime_info = class->runtime_info;
1606 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1607 return runtime_info->domain_vtables [domain->domain_id];
1612 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1615 MonoClassRuntimeInfo *runtime_info, *old_info;
1616 MonoClassField *field;
1619 int imt_table_bytes = 0;
1620 guint32 vtable_size, class_size;
1623 gpointer *interface_offsets;
1625 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1626 mono_domain_lock (domain);
1627 runtime_info = class->runtime_info;
1628 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1629 mono_domain_unlock (domain);
1630 mono_loader_unlock ();
1631 return runtime_info->domain_vtables [domain->domain_id];
1633 if (!class->inited || class->exception_type) {
1634 if (!mono_class_init (class) || class->exception_type){
1636 mono_domain_unlock (domain);
1637 mono_loader_unlock ();
1638 exc = mono_class_get_exception_for_failure (class);
1640 mono_raise_exception (exc);
1644 mono_class_init (class);
1647 * For some classes, mono_class_init () already computed class->vtable_size, and
1648 * that is all that is needed because of the vtable trampolines.
1650 if (!class->vtable_size)
1651 mono_class_setup_vtable (class);
1653 if (class->exception_type) {
1654 mono_domain_unlock (domain);
1659 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1660 if (class->interface_offsets_count) {
1661 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1662 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1663 mono_stats.imt_number_of_tables++;
1664 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1667 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1668 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1671 mono_stats.used_class_count++;
1672 mono_stats.class_vtable_size += vtable_size;
1673 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1676 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1678 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1680 vt->rank = class->rank;
1681 vt->domain = domain;
1683 mono_class_compute_gc_descriptor (class);
1685 * We can't use typed allocation in the non-root domains, since the
1686 * collector needs the GC descriptor stored in the vtable even after
1687 * the mempool containing the vtable is destroyed when the domain is
1688 * unloaded. An alternative might be to allocate vtables in the GC
1689 * heap, but this does not seem to work (it leads to crashes inside
1690 * libgc). If that approach is tried, two gc descriptors need to be
1691 * allocated for each class: one for the root domain, and one for all
1692 * other domains. The second descriptor should contain a bit for the
1693 * vtable field in MonoObject, since we can no longer assume the
1694 * vtable is reachable by other roots after the appdomain is unloaded.
1696 #ifdef HAVE_BOEHM_GC
1697 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1698 vt->gc_descr = GC_NO_DESCRIPTOR;
1701 vt->gc_descr = class->gc_descr;
1703 if ((class_size = mono_class_data_size (class))) {
1704 if (class->has_static_refs) {
1705 gpointer statics_gc_descr;
1707 gsize default_bitmap [4] = {0};
1710 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1711 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1712 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1713 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1714 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1715 if (bitmap != default_bitmap)
1718 vt->data = mono_domain_alloc0 (domain, class_size);
1720 mono_stats.class_static_data_size += class_size;
1725 while ((field = mono_class_get_fields (class, &iter))) {
1726 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1728 if (mono_field_is_deleted (field))
1730 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1731 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1732 if (special_static != SPECIAL_STATIC_NONE) {
1733 guint32 size, offset;
1735 size = mono_type_size (field->type, &align);
1736 offset = mono_alloc_special_static_data (special_static, size, align);
1737 if (!domain->special_static_fields)
1738 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1739 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1743 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1744 MonoClass *fklass = mono_class_from_mono_type (field->type);
1745 const char *data = mono_field_get_data (field);
1747 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1748 t = (char*)vt->data + field->offset;
1749 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1752 if (fklass->valuetype) {
1753 memcpy (t, data, mono_class_value_size (fklass, NULL));
1755 /* it's a pointer type: add check */
1756 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1763 vt->max_interface_id = class->max_interface_id;
1764 vt->interface_bitmap = class->interface_bitmap;
1766 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1767 // class->name, class->interface_offsets_count);
1769 if (! ARCH_USE_IMT) {
1770 /* initialize interface offsets */
1771 for (i = 0; i < class->interface_offsets_count; ++i) {
1772 int interface_id = class->interfaces_packed [i]->interface_id;
1773 int slot = class->interface_offsets_packed [i];
1774 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1778 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1779 * as we change the code in appdomain.c to invalidate vtables by
1780 * looking at the possible MonoClasses created for the domain.
1782 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1783 /* class->runtime_info is protected by the loader lock, both when
1784 * it it enlarged and when it is stored info.
1787 old_info = class->runtime_info;
1788 if (old_info && old_info->max_domain >= domain->domain_id) {
1789 /* someone already created a large enough runtime info */
1790 mono_memory_barrier ();
1791 old_info->domain_vtables [domain->domain_id] = vt;
1793 int new_size = domain->domain_id;
1795 new_size = MAX (new_size, old_info->max_domain);
1797 /* make the new size a power of two */
1799 while (new_size > i)
1802 /* this is a bounded memory retention issue: may want to
1803 * handle it differently when we'll have a rcu-like system.
1805 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1806 runtime_info->max_domain = new_size - 1;
1807 /* copy the stuff from the older info */
1809 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1811 runtime_info->domain_vtables [domain->domain_id] = vt;
1813 mono_memory_barrier ();
1814 class->runtime_info = runtime_info;
1817 /* Initialize vtable */
1818 if (vtable_trampoline) {
1819 // This also covers the AOT case
1820 for (i = 0; i < class->vtable_size; ++i) {
1821 vt->vtable [i] = vtable_trampoline;
1824 mono_class_setup_vtable (class);
1826 for (i = 0; i < class->vtable_size; ++i) {
1829 if ((cm = class->vtable [i])) {
1830 if (mono_method_signature (cm)->generic_param_count)
1831 /* FIXME: Why is this needed ? */
1832 vt->vtable [i] = cm;
1834 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1839 if (ARCH_USE_IMT && imt_table_bytes) {
1840 /* Now that the vtable is full, we can actually fill up the IMT */
1841 if (imt_trampoline) {
1842 /* lazy construction of the IMT entries enabled */
1843 for (i = 0; i < MONO_IMT_SIZE; ++i)
1844 interface_offsets [i] = imt_trampoline;
1846 build_imt (class, vt, domain, interface_offsets, NULL);
1850 mono_domain_unlock (domain);
1851 mono_loader_unlock ();
1853 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1854 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1855 MonoException *exc = mono_class_get_exception_for_failure (class);
1857 mono_raise_exception (exc);
1860 /* make sure the parent is initialized */
1862 mono_class_vtable (domain, class->parent);
1864 vt->type = mono_type_get_object (domain, &class->byval_arg);
1865 if (class->contextbound)
1874 * mono_class_proxy_vtable:
1875 * @domain: the application domain
1876 * @remove_class: the remote class
1878 * Creates a vtable for transparent proxies. It is basically
1879 * a copy of the real vtable of the class wrapped in @remote_class,
1880 * but all function pointers invoke the remoting functions, and
1881 * vtable->klass points to the transparent proxy class, and not to @class.
1884 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1886 MonoVTable *vt, *pvt;
1887 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1889 GSList *extra_interfaces = NULL;
1890 MonoClass *class = remote_class->proxy_class;
1891 gpointer *interface_offsets;
1893 vt = mono_class_vtable (domain, class);
1894 max_interface_id = vt->max_interface_id;
1896 /* Calculate vtable space for extra interfaces */
1897 for (j = 0; j < remote_class->interface_count; j++) {
1898 MonoClass* iclass = remote_class->interfaces[j];
1902 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1903 continue; /* interface implemented by the class */
1904 if (g_slist_find (extra_interfaces, iclass))
1907 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1909 method_count = mono_class_num_methods (iclass);
1911 ifaces = mono_class_get_implemented_interfaces (iclass);
1913 for (i = 0; i < ifaces->len; ++i) {
1914 MonoClass *ic = g_ptr_array_index (ifaces, i);
1915 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1916 continue; /* interface implemented by the class */
1917 if (g_slist_find (extra_interfaces, ic))
1919 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1920 method_count += mono_class_num_methods (ic);
1922 g_ptr_array_free (ifaces, TRUE);
1925 extra_interface_vtsize += method_count * sizeof (gpointer);
1926 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1930 mono_stats.imt_number_of_tables++;
1931 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1932 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1933 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1935 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1936 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1939 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1941 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1943 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1945 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1946 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1948 pvt->klass = mono_defaults.transparent_proxy_class;
1949 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1950 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1952 /* initialize vtable */
1953 mono_class_setup_vtable (class);
1954 for (i = 0; i < class->vtable_size; ++i) {
1957 if ((cm = class->vtable [i]))
1958 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
1960 pvt->vtable [i] = NULL;
1963 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1964 /* create trampolines for abstract methods */
1965 for (k = class; k; k = k->parent) {
1967 gpointer iter = NULL;
1968 while ((m = mono_class_get_methods (k, &iter)))
1969 if (!pvt->vtable [m->slot])
1970 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
1974 pvt->max_interface_id = max_interface_id;
1975 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1977 if (! ARCH_USE_IMT) {
1978 /* initialize interface offsets */
1979 for (i = 0; i < class->interface_offsets_count; ++i) {
1980 int interface_id = class->interfaces_packed [i]->interface_id;
1981 int slot = class->interface_offsets_packed [i];
1982 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1985 for (i = 0; i < class->interface_offsets_count; ++i) {
1986 int interface_id = class->interfaces_packed [i]->interface_id;
1987 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1990 if (extra_interfaces) {
1991 int slot = class->vtable_size;
1997 /* Create trampolines for the methods of the interfaces */
1998 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1999 interf = list_item->data;
2001 if (! ARCH_USE_IMT) {
2002 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2004 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2008 while ((cm = mono_class_get_methods (interf, &iter)))
2009 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2011 slot += mono_class_num_methods (interf);
2013 if (! ARCH_USE_IMT) {
2014 g_slist_free (extra_interfaces);
2019 /* Now that the vtable is full, we can actually fill up the IMT */
2020 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2021 if (extra_interfaces) {
2022 g_slist_free (extra_interfaces);
2030 * mono_class_field_is_special_static:
2032 * Returns whether @field is a thread/context static field.
2035 mono_class_field_is_special_static (MonoClassField *field)
2037 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2039 if (mono_field_is_deleted (field))
2041 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2042 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2049 * mono_class_has_special_static_fields:
2051 * Returns whenever @klass has any thread/context static fields.
2054 mono_class_has_special_static_fields (MonoClass *klass)
2056 MonoClassField *field;
2060 while ((field = mono_class_get_fields (klass, &iter))) {
2061 g_assert (field->parent == klass);
2062 if (mono_class_field_is_special_static (field))
2070 * create_remote_class_key:
2071 * Creates an array of pointers that can be used as a hash key for a remote class.
2072 * The first element of the array is the number of pointers.
2075 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2080 if (remote_class == NULL) {
2081 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2082 key = g_malloc (sizeof(gpointer) * 3);
2083 key [0] = GINT_TO_POINTER (2);
2084 key [1] = mono_defaults.marshalbyrefobject_class;
2085 key [2] = extra_class;
2087 key = g_malloc (sizeof(gpointer) * 2);
2088 key [0] = GINT_TO_POINTER (1);
2089 key [1] = extra_class;
2092 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2093 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2094 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2095 key [1] = remote_class->proxy_class;
2097 // Keep the list of interfaces sorted
2098 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2099 if (extra_class && remote_class->interfaces [i] > extra_class) {
2100 key [j++] = extra_class;
2103 key [j] = remote_class->interfaces [i];
2106 key [j] = extra_class;
2108 // Replace the old class. The interface list is the same
2109 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2110 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2111 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2112 for (i = 0; i < remote_class->interface_count; i++)
2113 key [2 + i] = remote_class->interfaces [i];
2121 * copy_remote_class_key:
2123 * Make a copy of KEY in the domain and return the copy.
2126 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2128 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2129 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2131 memcpy (mp_key, key, key_size);
2137 * mono_remote_class:
2138 * @domain: the application domain
2139 * @class_name: name of the remote class
2141 * Creates and initializes a MonoRemoteClass object for a remote type.
2145 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2147 MonoRemoteClass *rc;
2148 gpointer* key, *mp_key;
2150 key = create_remote_class_key (NULL, proxy_class);
2152 mono_domain_lock (domain);
2153 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2157 mono_domain_unlock (domain);
2161 mp_key = copy_remote_class_key (domain, key);
2165 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2166 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
2167 rc->interface_count = 1;
2168 rc->interfaces [0] = proxy_class;
2169 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2171 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
2172 rc->interface_count = 0;
2173 rc->proxy_class = proxy_class;
2176 rc->default_vtable = NULL;
2177 rc->xdomain_vtable = NULL;
2178 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2179 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2181 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2183 mono_domain_unlock (domain);
2188 * clone_remote_class:
2189 * Creates a copy of the remote_class, adding the provided class or interface
2191 static MonoRemoteClass*
2192 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2194 MonoRemoteClass *rc;
2195 gpointer* key, *mp_key;
2197 key = create_remote_class_key (remote_class, extra_class);
2198 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2204 mp_key = copy_remote_class_key (domain, key);
2208 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2210 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2211 rc->proxy_class = remote_class->proxy_class;
2212 rc->interface_count = remote_class->interface_count + 1;
2214 // Keep the list of interfaces sorted, since the hash key of
2215 // the remote class depends on this
2216 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2217 if (remote_class->interfaces [i] > extra_class && i == j)
2218 rc->interfaces [j++] = extra_class;
2219 rc->interfaces [j] = remote_class->interfaces [i];
2222 rc->interfaces [j] = extra_class;
2224 // Replace the old class. The interface array is the same
2225 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
2226 rc->proxy_class = extra_class;
2227 rc->interface_count = remote_class->interface_count;
2228 if (rc->interface_count > 0)
2229 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2232 rc->default_vtable = NULL;
2233 rc->xdomain_vtable = NULL;
2234 rc->proxy_class_name = remote_class->proxy_class_name;
2236 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2242 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2244 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2245 mono_domain_lock (domain);
2246 if (rp->target_domain_id != -1) {
2247 if (remote_class->xdomain_vtable == NULL)
2248 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2249 mono_domain_unlock (domain);
2250 mono_loader_unlock ();
2251 return remote_class->xdomain_vtable;
2253 if (remote_class->default_vtable == NULL) {
2256 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2257 klass = mono_class_from_mono_type (type);
2258 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2259 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2261 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2264 mono_domain_unlock (domain);
2265 mono_loader_unlock ();
2266 return remote_class->default_vtable;
2270 * mono_upgrade_remote_class:
2271 * @domain: the application domain
2272 * @tproxy: the proxy whose remote class has to be upgraded.
2273 * @klass: class to which the remote class can be casted.
2275 * Updates the vtable of the remote class by adding the necessary method slots
2276 * and interface offsets so it can be safely casted to klass. klass can be a
2277 * class or an interface.
2280 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2282 MonoTransparentProxy *tproxy;
2283 MonoRemoteClass *remote_class;
2284 gboolean redo_vtable;
2286 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2287 mono_domain_lock (domain);
2289 tproxy = (MonoTransparentProxy*) proxy_object;
2290 remote_class = tproxy->remote_class;
2292 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2295 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2296 if (remote_class->interfaces [i] == klass)
2297 redo_vtable = FALSE;
2300 redo_vtable = (remote_class->proxy_class != klass);
2304 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2305 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2308 mono_domain_unlock (domain);
2309 mono_loader_unlock ();
2314 * mono_object_get_virtual_method:
2315 * @obj: object to operate on.
2318 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2319 * the instance of a callvirt of method.
2322 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2325 MonoMethod **vtable;
2327 MonoMethod *res = NULL;
2329 klass = mono_object_class (obj);
2330 if (klass == mono_defaults.transparent_proxy_class) {
2331 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2337 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2340 mono_class_setup_vtable (klass);
2341 vtable = klass->vtable;
2343 if (method->slot == -1) {
2344 /* method->slot might not be set for instances of generic methods */
2345 if (method->is_inflated) {
2346 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2347 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2350 g_assert_not_reached ();
2354 /* check method->slot is a valid index: perform isinstance? */
2355 if (method->slot != -1) {
2356 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2358 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2360 res = vtable [method->slot];
2365 /* It may be an interface, abstract class method or generic method */
2366 if (!res || mono_method_signature (res)->generic_param_count)
2369 /* generic methods demand invoke_with_check */
2370 if (mono_method_signature (res)->generic_param_count)
2371 res = mono_marshal_get_remoting_invoke_with_check (res);
2373 res = mono_marshal_get_remoting_invoke (res);
2375 if (method->is_inflated) {
2376 /* Have to inflate the result */
2377 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2387 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2389 g_error ("runtime invoke called on uninitialized runtime");
2393 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2396 * mono_runtime_invoke:
2397 * @method: method to invoke
2398 * @obJ: object instance
2399 * @params: arguments to the method
2400 * @exc: exception information.
2402 * Invokes the method represented by @method on the object @obj.
2404 * obj is the 'this' pointer, it should be NULL for static
2405 * methods, a MonoObject* for object instances and a pointer to
2406 * the value type for value types.
2408 * The params array contains the arguments to the method with the
2409 * same convention: MonoObject* pointers for object instances and
2410 * pointers to the value type otherwise.
2412 * From unmanaged code you'll usually use the
2413 * mono_runtime_invoke() variant.
2415 * Note that this function doesn't handle virtual methods for
2416 * you, it will exec the exact method you pass: we still need to
2417 * expose a function to lookup the derived class implementation
2418 * of a virtual method (there are examples of this in the code,
2421 * You can pass NULL as the exc argument if you don't want to
2422 * catch exceptions, otherwise, *exc will be set to the exception
2423 * thrown, if any. if an exception is thrown, you can't use the
2424 * MonoObject* result from the function.
2426 * If the method returns a value type, it is boxed in an object
2430 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2432 if (mono_runtime_get_no_exec ())
2433 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2435 return default_mono_runtime_invoke (method, obj, params, exc);
2439 * mono_method_get_unmanaged_thunk:
2440 * @method: method to generate a thunk for.
2442 * Returns an unmanaged->managed thunk that can be used to call
2443 * a managed method directly from C.
2445 * The thunk's C signature closely matches the managed signature:
2447 * C#: public bool Equals (object obj);
2448 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2449 * MonoObject*, MonoException**);
2451 * The 1st ("this") parameter must not be used with static methods:
2453 * C#: public static bool ReferenceEquals (object a, object b);
2454 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2457 * The last argument must be a non-null pointer of a MonoException* pointer.
2458 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2459 * exception has been thrown in managed code. Otherwise it will point
2460 * to the MonoException* caught by the thunk. In this case, the result of
2461 * the thunk is undefined:
2463 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2464 * MonoException *ex = NULL;
2465 * Equals func = mono_method_get_unmanaged_thunk (method);
2466 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2468 * // handle exception
2471 * The calling convention of the thunk matches the platform's default
2472 * convention. This means that under Windows, C declarations must
2473 * contain the __stdcall attribute:
2475 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2476 * MonoObject*, MonoException**);
2480 * Value type arguments and return values are treated as they were objects:
2482 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2483 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2485 * Arguments must be properly boxed upon trunk's invocation, while return
2486 * values must be unboxed.
2489 mono_method_get_unmanaged_thunk (MonoMethod *method)
2491 method = mono_marshal_get_thunk_invoke_wrapper (method);
2492 return mono_compile_method (method);
2496 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2500 gpointer *p = (gpointer*)dest;
2507 case MONO_TYPE_BOOLEAN:
2509 case MONO_TYPE_U1: {
2510 guint8 *p = (guint8*)dest;
2511 *p = value ? *(guint8*)value : 0;
2516 case MONO_TYPE_CHAR: {
2517 guint16 *p = (guint16*)dest;
2518 *p = value ? *(guint16*)value : 0;
2521 #if SIZEOF_VOID_P == 4
2526 case MONO_TYPE_U4: {
2527 gint32 *p = (gint32*)dest;
2528 *p = value ? *(gint32*)value : 0;
2531 #if SIZEOF_VOID_P == 8
2536 case MONO_TYPE_U8: {
2537 gint64 *p = (gint64*)dest;
2538 *p = value ? *(gint64*)value : 0;
2541 case MONO_TYPE_R4: {
2542 float *p = (float*)dest;
2543 *p = value ? *(float*)value : 0;
2546 case MONO_TYPE_R8: {
2547 double *p = (double*)dest;
2548 *p = value ? *(double*)value : 0;
2551 case MONO_TYPE_STRING:
2552 case MONO_TYPE_SZARRAY:
2553 case MONO_TYPE_CLASS:
2554 case MONO_TYPE_OBJECT:
2555 case MONO_TYPE_ARRAY:
2556 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2558 case MONO_TYPE_FNPTR:
2559 case MONO_TYPE_PTR: {
2560 gpointer *p = (gpointer*)dest;
2561 *p = deref_pointer? *(gpointer*)value: value;
2564 case MONO_TYPE_VALUETYPE:
2565 /* note that 't' and 'type->type' can be different */
2566 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2567 t = mono_class_enum_basetype (type->data.klass)->type;
2571 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2573 memset (dest, 0, size);
2575 memcpy (dest, value, size);
2578 case MONO_TYPE_GENERICINST:
2579 t = type->data.generic_class->container_class->byval_arg.type;
2582 g_warning ("got type %x", type->type);
2583 g_assert_not_reached ();
2588 * mono_field_set_value:
2589 * @obj: Instance object
2590 * @field: MonoClassField describing the field to set
2591 * @value: The value to be set
2593 * Sets the value of the field described by @field in the object instance @obj
2594 * to the value passed in @value. This method should only be used for instance
2595 * fields. For static fields, use mono_field_static_set_value.
2597 * The value must be on the native format of the field type.
2600 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2604 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2606 dest = (char*)obj + field->offset;
2607 set_value (field->type, dest, value, FALSE);
2611 * mono_field_static_set_value:
2612 * @field: MonoClassField describing the field to set
2613 * @value: The value to be set
2615 * Sets the value of the static field described by @field
2616 * to the value passed in @value.
2618 * The value must be on the native format of the field type.
2621 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2625 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2626 /* you cant set a constant! */
2627 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2629 dest = (char*)vt->data + field->offset;
2630 set_value (field->type, dest, value, FALSE);
2633 /* Used by the debugger */
2635 mono_vtable_get_static_field_data (MonoVTable *vt)
2641 * mono_field_get_value:
2642 * @obj: Object instance
2643 * @field: MonoClassField describing the field to fetch information from
2644 * @value: pointer to the location where the value will be stored
2646 * Use this routine to get the value of the field @field in the object
2649 * The pointer provided by value must be of the field type, for reference
2650 * types this is a MonoObject*, for value types its the actual pointer to
2655 * mono_field_get_value (obj, int_field, &i);
2658 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2662 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2664 src = (char*)obj + field->offset;
2665 set_value (field->type, value, src, TRUE);
2669 * mono_field_get_value_object:
2670 * @domain: domain where the object will be created (if boxing)
2671 * @field: MonoClassField describing the field to fetch information from
2672 * @obj: The object instance for the field.
2674 * Returns: a new MonoObject with the value from the given field. If the
2675 * field represents a value type, the value is boxed.
2679 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2683 MonoVTable *vtable = NULL;
2685 gboolean is_static = FALSE;
2686 gboolean is_ref = FALSE;
2688 switch (field->type->type) {
2689 case MONO_TYPE_STRING:
2690 case MONO_TYPE_OBJECT:
2691 case MONO_TYPE_CLASS:
2692 case MONO_TYPE_ARRAY:
2693 case MONO_TYPE_SZARRAY:
2698 case MONO_TYPE_BOOLEAN:
2701 case MONO_TYPE_CHAR:
2710 case MONO_TYPE_VALUETYPE:
2711 is_ref = field->type->byref;
2713 case MONO_TYPE_GENERICINST:
2714 is_ref = !field->type->data.generic_class->container_class->valuetype;
2717 g_error ("type 0x%x not handled in "
2718 "mono_field_get_value_object", field->type->type);
2722 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2724 vtable = mono_class_vtable (domain, field->parent);
2725 if (!vtable->initialized)
2726 mono_runtime_class_init (vtable);
2731 mono_field_static_get_value (vtable, field, &o);
2733 mono_field_get_value (obj, field, &o);
2738 /* boxed value type */
2739 klass = mono_class_from_mono_type (field->type);
2740 o = mono_object_new (domain, klass);
2741 v = ((gchar *) o) + sizeof (MonoObject);
2743 mono_field_static_get_value (vtable, field, v);
2745 mono_field_get_value (obj, field, v);
2752 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2755 const char *p = blob;
2756 mono_metadata_decode_blob_size (p, &p);
2759 case MONO_TYPE_BOOLEAN:
2762 *(guint8 *) value = *p;
2764 case MONO_TYPE_CHAR:
2767 *(guint16*) value = read16 (p);
2771 *(guint32*) value = read32 (p);
2775 *(guint64*) value = read64 (p);
2778 readr4 (p, (float*) value);
2781 readr8 (p, (double*) value);
2783 case MONO_TYPE_STRING:
2784 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2786 case MONO_TYPE_CLASS:
2787 *(gpointer*) value = NULL;
2791 g_warning ("type 0x%02x should not be in constant table", type);
2797 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2799 MonoTypeEnum def_type;
2802 data = mono_class_get_field_default_value (field, &def_type);
2803 mono_get_constant_value_from_blob (domain, def_type, data, value);
2807 * mono_field_static_get_value:
2808 * @vt: vtable to the object
2809 * @field: MonoClassField describing the field to fetch information from
2810 * @value: where the value is returned
2812 * Use this routine to get the value of the static field @field value.
2814 * The pointer provided by value must be of the field type, for reference
2815 * types this is a MonoObject*, for value types its the actual pointer to
2820 * mono_field_static_get_value (vt, int_field, &i);
2823 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2827 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2829 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2830 get_default_field_value (vt->domain, field, value);
2834 src = (char*)vt->data + field->offset;
2835 set_value (field->type, value, src, TRUE);
2839 * mono_property_set_value:
2840 * @prop: MonoProperty to set
2841 * @obj: instance object on which to act
2842 * @params: parameters to pass to the propery
2843 * @exc: optional exception
2845 * Invokes the property's set method with the given arguments on the
2846 * object instance obj (or NULL for static properties).
2848 * You can pass NULL as the exc argument if you don't want to
2849 * catch exceptions, otherwise, *exc will be set to the exception
2850 * thrown, if any. if an exception is thrown, you can't use the
2851 * MonoObject* result from the function.
2854 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2856 default_mono_runtime_invoke (prop->set, obj, params, exc);
2860 * mono_property_get_value:
2861 * @prop: MonoProperty to fetch
2862 * @obj: instance object on which to act
2863 * @params: parameters to pass to the propery
2864 * @exc: optional exception
2866 * Invokes the property's get method with the given arguments on the
2867 * object instance obj (or NULL for static properties).
2869 * You can pass NULL as the exc argument if you don't want to
2870 * catch exceptions, otherwise, *exc will be set to the exception
2871 * thrown, if any. if an exception is thrown, you can't use the
2872 * MonoObject* result from the function.
2874 * Returns: the value from invoking the get method on the property.
2877 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2879 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2883 * mono_nullable_init:
2884 * @buf: The nullable structure to initialize.
2885 * @value: the value to initialize from
2886 * @klass: the type for the object
2888 * Initialize the nullable structure pointed to by @buf from @value which
2889 * should be a boxed value type. The size of @buf should be able to hold
2890 * as much data as the @klass->instance_size (which is the number of bytes
2891 * that will be copies).
2893 * Since Nullables have variable structure, we can not define a C
2894 * structure for them.
2897 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2899 MonoClass *param_class = klass->cast_class;
2901 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2902 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2904 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2906 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2908 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2912 * mono_nullable_box:
2913 * @buf: The buffer representing the data to be boxed
2914 * @klass: the type to box it as.
2916 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2920 mono_nullable_box (guint8 *buf, MonoClass *klass)
2922 MonoClass *param_class = klass->cast_class;
2924 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2925 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2927 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2928 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2929 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2937 * mono_get_delegate_invoke:
2938 * @klass: The delegate class
2940 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2943 mono_get_delegate_invoke (MonoClass *klass)
2947 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2954 * mono_runtime_delegate_invoke:
2955 * @delegate: pointer to a delegate object.
2956 * @params: parameters for the delegate.
2957 * @exc: Pointer to the exception result.
2959 * Invokes the delegate method @delegate with the parameters provided.
2961 * You can pass NULL as the exc argument if you don't want to
2962 * catch exceptions, otherwise, *exc will be set to the exception
2963 * thrown, if any. if an exception is thrown, you can't use the
2964 * MonoObject* result from the function.
2967 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2971 im = mono_get_delegate_invoke (delegate->vtable->klass);
2974 return mono_runtime_invoke (im, delegate, params, exc);
2977 static char **main_args = NULL;
2978 static int num_main_args;
2981 * mono_runtime_get_main_args:
2983 * Returns: a MonoArray with the arguments passed to the main program
2986 mono_runtime_get_main_args (void)
2990 MonoDomain *domain = mono_domain_get ();
2995 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2997 for (i = 0; i < num_main_args; ++i)
2998 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3004 fire_process_exit_event (void)
3006 MonoClassField *field;
3007 MonoDomain *domain = mono_domain_get ();
3009 MonoObject *delegate, *exc;
3011 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3014 if (domain != mono_get_root_domain ())
3017 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3018 if (delegate == NULL)
3023 mono_runtime_delegate_invoke (delegate, pa, &exc);
3027 * mono_runtime_run_main:
3028 * @method: the method to start the application with (usually Main)
3029 * @argc: number of arguments from the command line
3030 * @argv: array of strings from the command line
3031 * @exc: excetption results
3033 * Execute a standard Main() method (argc/argv contains the
3034 * executable name). This method also sets the command line argument value
3035 * needed by System.Environment.
3040 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3044 MonoArray *args = NULL;
3045 MonoDomain *domain = mono_domain_get ();
3046 gchar *utf8_fullpath;
3049 g_assert (method != NULL);
3051 mono_thread_set_main (mono_thread_current ());
3053 main_args = g_new0 (char*, argc);
3054 num_main_args = argc;
3056 if (!g_path_is_absolute (argv [0])) {
3057 gchar *basename = g_path_get_basename (argv [0]);
3058 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3062 utf8_fullpath = mono_utf8_from_external (fullpath);
3063 if(utf8_fullpath == NULL) {
3064 /* Printing the arg text will cause glib to
3065 * whinge about "Invalid UTF-8", but at least
3066 * its relevant, and shows the problem text
3069 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3070 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3077 utf8_fullpath = mono_utf8_from_external (argv[0]);
3078 if(utf8_fullpath == NULL) {
3079 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3080 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3085 main_args [0] = utf8_fullpath;
3087 for (i = 1; i < argc; ++i) {
3090 utf8_arg=mono_utf8_from_external (argv[i]);
3091 if(utf8_arg==NULL) {
3092 /* Ditto the comment about Invalid UTF-8 here */
3093 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3094 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3098 main_args [i] = utf8_arg;
3102 if (mono_method_signature (method)->param_count) {
3103 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3104 for (i = 0; i < argc; ++i) {
3105 /* The encodings should all work, given that
3106 * we've checked all these args for the
3109 gchar *str = mono_utf8_from_external (argv [i]);
3110 MonoString *arg = mono_string_new (domain, str);
3111 mono_array_setref (args, i, arg);
3115 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3118 mono_assembly_set_main (method->klass->image->assembly);
3120 result = mono_runtime_exec_main (method, args, exc);
3121 fire_process_exit_event ();
3125 /* Used in call_unhandled_exception_delegate */
3127 create_unhandled_exception_eventargs (MonoObject *exc)
3131 MonoMethod *method = NULL;
3132 MonoBoolean is_terminating = TRUE;
3135 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3138 mono_class_init (klass);
3140 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3141 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3145 args [1] = &is_terminating;
3147 obj = mono_object_new (mono_domain_get (), klass);
3148 mono_runtime_invoke (method, obj, args, NULL);
3153 /* Used in mono_unhandled_exception */
3155 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3156 MonoObject *e = NULL;
3159 pa [0] = domain->domain;
3160 pa [1] = create_unhandled_exception_eventargs (exc);
3161 mono_runtime_delegate_invoke (delegate, pa, &e);
3164 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3165 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3170 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3173 * mono_runtime_unhandled_exception_policy_set:
3174 * @policy: the new policy
3176 * This is a VM internal routine.
3178 * Sets the runtime policy for handling unhandled exceptions.
3181 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3182 runtime_unhandled_exception_policy = policy;
3186 * mono_runtime_unhandled_exception_policy_get:
3188 * This is a VM internal routine.
3190 * Gets the runtime policy for handling unhandled exceptions.
3192 MonoRuntimeUnhandledExceptionPolicy
3193 mono_runtime_unhandled_exception_policy_get (void) {
3194 return runtime_unhandled_exception_policy;
3198 * mono_unhandled_exception:
3199 * @exc: exception thrown
3201 * This is a VM internal routine.
3203 * We call this function when we detect an unhandled exception
3204 * in the default domain.
3206 * It invokes the * UnhandledException event in AppDomain or prints
3207 * a warning to the console
3210 mono_unhandled_exception (MonoObject *exc)
3212 MonoDomain *current_domain = mono_domain_get ();
3213 MonoDomain *root_domain = mono_get_root_domain ();
3214 MonoClassField *field;
3215 MonoObject *current_appdomain_delegate;
3216 MonoObject *root_appdomain_delegate;
3218 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3219 "UnhandledException");
3222 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3223 gboolean abort_process = (mono_thread_current () == main_thread) ||
3224 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3225 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3226 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3227 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3229 current_appdomain_delegate = NULL;
3232 /* set exitcode only if we will abort the process */
3234 mono_environment_exitcode_set (1);
3235 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3236 mono_print_unhandled_exception (exc);
3238 if (root_appdomain_delegate) {
3239 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3241 if (current_appdomain_delegate) {
3242 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3249 * Launch a new thread to execute a function
3251 * main_func is called back from the thread with main_args as the
3252 * parameter. The callback function is expected to start Main()
3253 * eventually. This function then waits for all managed threads to
3255 * It is not necesseray anymore to execute managed code in a subthread,
3256 * so this function should not be used anymore by default: just
3257 * execute the code and then call mono_thread_manage ().
3260 mono_runtime_exec_managed_code (MonoDomain *domain,
3261 MonoMainThreadFunc main_func,
3264 mono_thread_create (domain, main_func, main_args);
3266 mono_thread_manage ();
3270 * Execute a standard Main() method (args doesn't contain the
3274 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3279 MonoCustomAttrInfo* cinfo;
3280 gboolean has_stathread_attribute;
3281 MonoThread* thread = mono_thread_current ();
3287 domain = mono_object_domain (args);
3288 if (!domain->entry_assembly) {
3290 MonoAssembly *assembly;
3292 assembly = method->klass->image->assembly;
3293 domain->entry_assembly = assembly;
3294 /* Domains created from another domain already have application_base and configuration_file set */
3295 if (domain->setup->application_base == NULL) {
3296 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3299 if (domain->setup->configuration_file == NULL) {
3300 str = g_strconcat (assembly->image->name, ".config", NULL);
3301 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3303 mono_set_private_bin_path_from_config (domain);
3307 cinfo = mono_custom_attrs_from_method (method);
3309 static MonoClass *stathread_attribute = NULL;
3310 if (!stathread_attribute)
3311 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3312 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3314 mono_custom_attrs_free (cinfo);
3316 has_stathread_attribute = FALSE;
3318 if (has_stathread_attribute) {
3319 thread->apartment_state = ThreadApartmentState_STA;
3320 } else if (mono_framework_version () == 1) {
3321 thread->apartment_state = ThreadApartmentState_Unknown;
3323 thread->apartment_state = ThreadApartmentState_MTA;
3325 mono_thread_init_apartment_state ();
3327 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3329 /* FIXME: check signature of method */
3330 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3332 res = mono_runtime_invoke (method, NULL, pa, exc);
3334 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3338 mono_environment_exitcode_set (rval);
3340 mono_runtime_invoke (method, NULL, pa, exc);
3344 /* If the return type of Main is void, only
3345 * set the exitcode if an exception was thrown
3346 * (we don't want to blow away an
3347 * explicitly-set exit code)
3350 mono_environment_exitcode_set (rval);
3354 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3360 * mono_install_runtime_invoke:
3361 * @func: Function to install
3363 * This is a VM internal routine
3366 mono_install_runtime_invoke (MonoInvokeFunc func)
3368 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3373 * mono_runtime_invoke_array:
3374 * @method: method to invoke
3375 * @obJ: object instance
3376 * @params: arguments to the method
3377 * @exc: exception information.
3379 * Invokes the method represented by @method on the object @obj.
3381 * obj is the 'this' pointer, it should be NULL for static
3382 * methods, a MonoObject* for object instances and a pointer to
3383 * the value type for value types.
3385 * The params array contains the arguments to the method with the
3386 * same convention: MonoObject* pointers for object instances and
3387 * pointers to the value type otherwise. The _invoke_array
3388 * variant takes a C# object[] as the params argument (MonoArray
3389 * *params): in this case the value types are boxed inside the
3390 * respective reference representation.
3392 * From unmanaged code you'll usually use the
3393 * mono_runtime_invoke() variant.
3395 * Note that this function doesn't handle virtual methods for
3396 * you, it will exec the exact method you pass: we still need to
3397 * expose a function to lookup the derived class implementation
3398 * of a virtual method (there are examples of this in the code,
3401 * You can pass NULL as the exc argument if you don't want to
3402 * catch exceptions, otherwise, *exc will be set to the exception
3403 * thrown, if any. if an exception is thrown, you can't use the
3404 * MonoObject* result from the function.
3406 * If the method returns a value type, it is boxed in an object
3410 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3413 MonoMethodSignature *sig = mono_method_signature (method);
3414 gpointer *pa = NULL;
3417 gboolean has_byref_nullables = FALSE;
3419 if (NULL != params) {
3420 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3421 for (i = 0; i < mono_array_length (params); i++) {
3422 MonoType *t = sig->params [i];
3428 case MONO_TYPE_BOOLEAN:
3431 case MONO_TYPE_CHAR:
3440 case MONO_TYPE_VALUETYPE:
3441 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3442 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3443 pa [i] = mono_array_get (params, MonoObject*, i);
3445 has_byref_nullables = TRUE;
3447 /* MS seems to create the objects if a null is passed in */
3448 if (!mono_array_get (params, MonoObject*, i))
3449 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3453 * We can't pass the unboxed vtype byref to the callee, since
3454 * that would mean the callee would be able to modify boxed
3455 * primitive types. So we (and MS) make a copy of the boxed
3456 * object, pass that to the callee, and replace the original
3457 * boxed object in the arg array with the copy.
3459 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3460 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3461 mono_array_setref (params, i, copy);
3464 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3467 case MONO_TYPE_STRING:
3468 case MONO_TYPE_OBJECT:
3469 case MONO_TYPE_CLASS:
3470 case MONO_TYPE_ARRAY:
3471 case MONO_TYPE_SZARRAY:
3473 pa [i] = mono_array_addr (params, MonoObject*, i);
3474 // FIXME: I need to check this code path
3476 pa [i] = mono_array_get (params, MonoObject*, i);
3478 case MONO_TYPE_GENERICINST:
3480 t = &t->data.generic_class->container_class->this_arg;
3482 t = &t->data.generic_class->container_class->byval_arg;
3485 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3490 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3493 if (mono_class_is_nullable (method->klass)) {
3494 /* Need to create a boxed vtype instead */
3500 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3504 obj = mono_object_new (mono_domain_get (), method->klass);
3505 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3506 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3508 if (method->klass->valuetype)
3509 o = mono_object_unbox (obj);
3512 } else if (method->klass->valuetype) {
3513 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3516 mono_runtime_invoke (method, o, pa, exc);
3519 if (mono_class_is_nullable (method->klass)) {
3520 MonoObject *nullable;
3522 /* Convert the unboxed vtype into a Nullable structure */
3523 nullable = mono_object_new (mono_domain_get (), method->klass);
3525 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3526 obj = mono_object_unbox (nullable);
3529 /* obj must be already unboxed if needed */
3530 res = mono_runtime_invoke (method, obj, pa, exc);
3532 if (has_byref_nullables) {
3534 * The runtime invoke wrapper already converted byref nullables back,
3535 * and stored them in pa, we just need to copy them back to the
3538 for (i = 0; i < mono_array_length (params); i++) {
3539 MonoType *t = sig->params [i];
3541 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3542 mono_array_setref (params, i, pa [i]);
3551 arith_overflow (void)
3553 mono_raise_exception (mono_get_exception_overflow ());
3557 * mono_object_allocate:
3558 * @size: number of bytes to allocate
3560 * This is a very simplistic routine until we have our GC-aware
3563 * Returns: an allocated object of size @size, or NULL on failure.
3565 static inline void *
3566 mono_object_allocate (size_t size, MonoVTable *vtable)
3569 mono_stats.new_object_count++;
3570 ALLOC_OBJECT (o, vtable, size);
3576 * mono_object_allocate_ptrfree:
3577 * @size: number of bytes to allocate
3579 * Note that the memory allocated is not zeroed.
3580 * Returns: an allocated object of size @size, or NULL on failure.
3582 static inline void *
3583 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3586 mono_stats.new_object_count++;
3587 ALLOC_PTRFREE (o, vtable, size);
3591 static inline void *
3592 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3595 ALLOC_TYPED (o, size, vtable);
3596 mono_stats.new_object_count++;
3603 * @klass: the class of the object that we want to create
3605 * Returns: a newly created object whose definition is
3606 * looked up using @klass. This will not invoke any constructors,
3607 * so the consumer of this routine has to invoke any constructors on
3608 * its own to initialize the object.
3611 mono_object_new (MonoDomain *domain, MonoClass *klass)
3613 MONO_ARCH_SAVE_REGS;
3614 return mono_object_new_specific (mono_class_vtable (domain, klass));
3618 * mono_object_new_specific:
3619 * @vtable: the vtable of the object that we want to create
3621 * Returns: A newly created object with class and domain specified
3625 mono_object_new_specific (MonoVTable *vtable)
3629 MONO_ARCH_SAVE_REGS;
3631 /* check for is_com_object for COM Interop */
3632 if (vtable->remote || vtable->klass->is_com_object)
3635 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3638 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3641 mono_class_init (klass);
3643 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3645 vtable->domain->create_proxy_for_type_method = im;
3648 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3650 o = mono_runtime_invoke (im, NULL, pa, NULL);
3651 if (o != NULL) return o;
3654 return mono_object_new_alloc_specific (vtable);
3658 mono_object_new_alloc_specific (MonoVTable *vtable)
3662 if (!vtable->klass->has_references) {
3663 o = mono_object_new_ptrfree (vtable);
3664 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3665 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3667 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3668 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3670 if (G_UNLIKELY (vtable->klass->has_finalize))
3671 mono_object_register_finalizer (o);
3673 if (G_UNLIKELY (profile_allocs))
3674 mono_profiler_allocation (o, vtable->klass);
3679 mono_object_new_fast (MonoVTable *vtable)
3682 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3687 mono_object_new_ptrfree (MonoVTable *vtable)
3690 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3691 #if NEED_TO_ZERO_PTRFREE
3692 /* an inline memset is much faster for the common vcase of small objects
3693 * note we assume the allocated size is a multiple of sizeof (void*).
3695 if (vtable->klass->instance_size < 128) {
3697 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3698 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3704 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3711 mono_object_new_ptrfree_box (MonoVTable *vtable)
3714 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3715 /* the object will be boxed right away, no need to memzero it */
3720 * mono_class_get_allocation_ftn:
3722 * @for_box: the object will be used for boxing
3723 * @pass_size_in_words:
3725 * Return the allocation function appropriate for the given class.
3729 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3731 *pass_size_in_words = FALSE;
3733 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3734 profile_allocs = FALSE;
3736 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3737 return mono_object_new_specific;
3739 if (!vtable->klass->has_references) {
3740 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3742 return mono_object_new_ptrfree_box;
3743 return mono_object_new_ptrfree;
3746 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3748 return mono_object_new_fast;
3751 * FIXME: This is actually slower than mono_object_new_fast, because
3752 * of the overhead of parameter passing.
3755 *pass_size_in_words = TRUE;
3756 #ifdef GC_REDIRECT_TO_LOCAL
3757 return GC_local_gcj_fast_malloc;
3759 return GC_gcj_fast_malloc;
3764 return mono_object_new_specific;
3768 * mono_object_new_from_token:
3769 * @image: Context where the type_token is hosted
3770 * @token: a token of the type that we want to create
3772 * Returns: A newly created object whose definition is
3773 * looked up using @token in the @image image
3776 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3780 class = mono_class_get (image, token);
3782 return mono_object_new (domain, class);
3787 * mono_object_clone:
3788 * @obj: the object to clone
3790 * Returns: A newly created object who is a shallow copy of @obj
3793 mono_object_clone (MonoObject *obj)
3798 size = obj->vtable->klass->instance_size;
3799 o = mono_object_allocate (size, obj->vtable);
3800 /* do not copy the sync state */
3801 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3804 if (obj->vtable->klass->has_references)
3805 mono_gc_wbarrier_object (o);
3807 if (G_UNLIKELY (profile_allocs))
3808 mono_profiler_allocation (o, obj->vtable->klass);
3810 if (obj->vtable->klass->has_finalize)
3811 mono_object_register_finalizer (o);
3816 * mono_array_full_copy:
3817 * @src: source array to copy
3818 * @dest: destination array
3820 * Copies the content of one array to another with exactly the same type and size.
3823 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3825 mono_array_size_t size;
3826 MonoClass *klass = src->obj.vtable->klass;
3828 MONO_ARCH_SAVE_REGS;
3830 g_assert (klass == dest->obj.vtable->klass);
3832 size = mono_array_length (src);
3833 g_assert (size == mono_array_length (dest));
3834 size *= mono_array_element_size (klass);
3836 if (klass->element_class->valuetype) {
3837 if (klass->element_class->has_references)
3838 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3840 memcpy (&dest->vector, &src->vector, size);
3842 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3845 memcpy (&dest->vector, &src->vector, size);
3850 * mono_array_clone_in_domain:
3851 * @domain: the domain in which the array will be cloned into
3852 * @array: the array to clone
3854 * This routine returns a copy of the array that is hosted on the
3855 * specified MonoDomain.
3858 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3861 mono_array_size_t size, i;
3862 mono_array_size_t *sizes;
3863 MonoClass *klass = array->obj.vtable->klass;
3865 MONO_ARCH_SAVE_REGS;
3867 if (array->bounds == NULL) {
3868 size = mono_array_length (array);
3869 o = mono_array_new_full (domain, klass, &size, NULL);
3871 size *= mono_array_element_size (klass);
3873 if (klass->element_class->valuetype) {
3874 if (klass->element_class->has_references)
3875 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3877 memcpy (&o->vector, &array->vector, size);
3879 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3882 memcpy (&o->vector, &array->vector, size);
3887 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3888 size = mono_array_element_size (klass);
3889 for (i = 0; i < klass->rank; ++i) {
3890 sizes [i] = array->bounds [i].length;
3891 size *= array->bounds [i].length;
3892 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3894 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3896 if (klass->element_class->valuetype) {
3897 if (klass->element_class->has_references)
3898 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
3900 memcpy (&o->vector, &array->vector, size);
3902 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3905 memcpy (&o->vector, &array->vector, size);
3913 * @array: the array to clone
3915 * Returns: A newly created array who is a shallow copy of @array
3918 mono_array_clone (MonoArray *array)
3920 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3923 /* helper macros to check for overflow when calculating the size of arrays */
3924 #ifdef MONO_BIG_ARRAYS
3925 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3926 #define MYGUINT_MAX MYGUINT64_MAX
3927 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3928 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3929 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3930 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3931 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3933 #define MYGUINT32_MAX 4294967295U
3934 #define MYGUINT_MAX MYGUINT32_MAX
3935 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3936 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3937 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3938 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3939 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3943 * mono_array_new_full:
3944 * @domain: domain where the object is created
3945 * @array_class: array class
3946 * @lengths: lengths for each dimension in the array
3947 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3949 * This routine creates a new array objects with the given dimensions,
3950 * lower bounds and type.
3953 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3955 mono_array_size_t byte_len, len, bounds_size;
3961 if (!array_class->inited)
3962 mono_class_init (array_class);
3964 byte_len = mono_array_element_size (array_class);
3967 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3968 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3970 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3974 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3976 for (i = 0; i < array_class->rank; ++i) {
3977 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3979 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3980 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3985 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3986 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3988 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3989 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3990 byte_len += sizeof (MonoArray);
3993 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3994 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3995 byte_len = (byte_len + 3) & ~3;
3996 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3997 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3998 byte_len += bounds_size;
4001 * Following three lines almost taken from mono_object_new ():
4002 * they need to be kept in sync.
4004 vtable = mono_class_vtable (domain, array_class);
4005 if (!array_class->has_references) {
4006 o = mono_object_allocate_ptrfree (byte_len, vtable);
4007 #if NEED_TO_ZERO_PTRFREE
4008 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4010 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4011 o = mono_object_allocate_spec (byte_len, vtable);
4013 o = mono_object_allocate (byte_len, vtable);
4016 array = (MonoArray*)o;
4017 array->max_length = len;
4020 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4021 array->bounds = bounds;
4022 for (i = 0; i < array_class->rank; ++i) {
4023 bounds [i].length = lengths [i];
4025 bounds [i].lower_bound = lower_bounds [i];
4029 if (G_UNLIKELY (profile_allocs))
4030 mono_profiler_allocation (o, array_class);
4037 * @domain: domain where the object is created
4038 * @eclass: element class
4039 * @n: number of array elements
4041 * This routine creates a new szarray with @n elements of type @eclass.
4044 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4048 MONO_ARCH_SAVE_REGS;
4050 ac = mono_array_class_get (eclass, 1);
4053 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4057 * mono_array_new_specific:
4058 * @vtable: a vtable in the appropriate domain for an initialized class
4059 * @n: number of array elements
4061 * This routine is a fast alternative to mono_array_new() for code which
4062 * can be sure about the domain it operates in.
4065 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4069 guint32 byte_len, elem_size;
4071 MONO_ARCH_SAVE_REGS;
4073 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4078 elem_size = mono_array_element_size (vtable->klass);
4079 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4080 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4083 byte_len = n * elem_size;
4084 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4085 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4088 byte_len += sizeof (MonoArray);
4089 if (!vtable->klass->has_references) {
4090 o = mono_object_allocate_ptrfree (byte_len, vtable);
4091 #if NEED_TO_ZERO_PTRFREE
4092 ((MonoArray*)o)->bounds = NULL;
4093 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4095 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4096 o = mono_object_allocate_spec (byte_len, vtable);
4098 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4099 o = mono_object_allocate (byte_len, vtable);
4102 ao = (MonoArray *)o;
4104 if (G_UNLIKELY (profile_allocs))
4105 mono_profiler_allocation (o, vtable->klass);
4111 * mono_string_new_utf16:
4112 * @text: a pointer to an utf16 string
4113 * @len: the length of the string
4115 * Returns: A newly created string object which contains @text.
4118 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4122 s = mono_string_new_size (domain, len);
4123 g_assert (s != NULL);
4125 memcpy (mono_string_chars (s), text, len * 2);
4131 * mono_string_new_size:
4132 * @text: a pointer to an utf16 string
4133 * @len: the length of the string
4135 * Returns: A newly created string object of @len
4138 mono_string_new_size (MonoDomain *domain, gint32 len)
4142 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4144 /* overflow ? can't fit it, can't allocate it! */
4146 mono_gc_out_of_memory (-1);
4148 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4150 s = mono_object_allocate_ptrfree (size, vtable);
4153 #if NEED_TO_ZERO_PTRFREE
4156 if (G_UNLIKELY (profile_allocs))
4157 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4163 * mono_string_new_len:
4164 * @text: a pointer to an utf8 string
4165 * @length: number of bytes in @text to consider
4167 * Returns: A newly created string object which contains @text.
4170 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4172 GError *error = NULL;
4173 MonoString *o = NULL;
4175 glong items_written;
4177 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4180 o = mono_string_new_utf16 (domain, ut, items_written);
4182 g_error_free (error);
4191 * @text: a pointer to an utf8 string
4193 * Returns: A newly created string object which contains @text.
4196 mono_string_new (MonoDomain *domain, const char *text)
4198 GError *error = NULL;
4199 MonoString *o = NULL;
4201 glong items_written;
4206 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4209 o = mono_string_new_utf16 (domain, ut, items_written);
4211 g_error_free (error);
4214 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4219 MonoString *o = NULL;
4221 if (!g_utf8_validate (text, -1, &end))
4224 len = g_utf8_strlen (text, -1);
4225 o = mono_string_new_size (domain, len);
4226 str = mono_string_chars (o);
4228 while (text < end) {
4229 *str++ = g_utf8_get_char (text);
4230 text = g_utf8_next_char (text);
4237 * mono_string_new_wrapper:
4238 * @text: pointer to utf8 characters.
4240 * Helper function to create a string object from @text in the current domain.
4243 mono_string_new_wrapper (const char *text)
4245 MonoDomain *domain = mono_domain_get ();
4247 MONO_ARCH_SAVE_REGS;
4250 return mono_string_new (domain, text);
4257 * @class: the class of the value
4258 * @value: a pointer to the unboxed data
4260 * Returns: A newly created object which contains @value.
4263 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4269 g_assert (class->valuetype);
4270 if (mono_class_is_nullable (class))
4271 return mono_nullable_box (value, class);
4273 vtable = mono_class_vtable (domain, class);
4274 size = mono_class_instance_size (class);
4275 res = mono_object_new_alloc_specific (vtable);
4276 if (G_UNLIKELY (profile_allocs))
4277 mono_profiler_allocation (res, class);
4279 size = size - sizeof (MonoObject);
4282 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4285 #if NO_UNALIGNED_ACCESS
4286 memcpy ((char *)res + sizeof (MonoObject), value, size);
4290 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4293 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4296 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4299 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4302 memcpy ((char *)res + sizeof (MonoObject), value, size);
4305 if (class->has_finalize)
4306 mono_object_register_finalizer (res);
4312 * @dest: destination pointer
4313 * @src: source pointer
4314 * @klass: a valuetype class
4316 * Copy a valuetype from @src to @dest. This function must be used
4317 * when @klass contains references fields.
4320 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4322 int size = mono_class_value_size (klass, NULL);
4323 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4324 memcpy (dest, src, size);
4328 * mono_value_copy_array:
4329 * @dest: destination array
4330 * @dest_idx: index in the @dest array
4331 * @src: source pointer
4332 * @count: number of items
4334 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4335 * This function must be used when @klass contains references fields.
4336 * Overlap is handled.
4339 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4341 int size = mono_array_element_size (dest->obj.vtable->klass);
4342 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4343 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4344 memmove (d, src, size * count);
4348 * mono_object_get_domain:
4349 * @obj: object to query
4351 * Returns: the MonoDomain where the object is hosted
4354 mono_object_get_domain (MonoObject *obj)
4356 return mono_object_domain (obj);
4360 * mono_object_get_class:
4361 * @obj: object to query
4363 * Returns: the MonOClass of the object.
4366 mono_object_get_class (MonoObject *obj)
4368 return mono_object_class (obj);
4371 * mono_object_get_size:
4372 * @o: object to query
4374 * Returns: the size, in bytes, of @o
4377 mono_object_get_size (MonoObject* o)
4379 MonoClass* klass = mono_object_class (o);
4380 if (klass == mono_defaults.string_class) {
4381 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4382 } else if (o->vtable->rank) {
4383 MonoArray *array = (MonoArray*)o;
4384 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4385 if (array->bounds) {
4388 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4392 return mono_class_instance_size (klass);
4397 * mono_object_unbox:
4398 * @obj: object to unbox
4400 * Returns: a pointer to the start of the valuetype boxed in this
4403 * This method will assert if the object passed is not a valuetype.
4406 mono_object_unbox (MonoObject *obj)
4408 /* add assert for valuetypes? */
4409 g_assert (obj->vtable->klass->valuetype);
4410 return ((char*)obj) + sizeof (MonoObject);
4414 * mono_object_isinst:
4416 * @klass: a pointer to a class
4418 * Returns: @obj if @obj is derived from @klass
4421 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4424 mono_class_init (klass);
4426 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4427 return mono_object_isinst_mbyref (obj, klass);
4432 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4436 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4445 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4446 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4450 MonoClass *oklass = vt->klass;
4451 if ((oklass == mono_defaults.transparent_proxy_class))
4452 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4454 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4458 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4460 MonoDomain *domain = mono_domain_get ();
4462 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4463 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4464 MonoMethod *im = NULL;
4467 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4468 im = mono_object_get_virtual_method (rp, im);
4471 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4474 res = mono_runtime_invoke (im, rp, pa, NULL);
4476 if (*(MonoBoolean *) mono_object_unbox(res)) {
4477 /* Update the vtable of the remote type, so it can safely cast to this new type */
4478 mono_upgrade_remote_class (domain, obj, klass);
4487 * mono_object_castclass_mbyref:
4489 * @klass: a pointer to a class
4491 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4494 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4496 if (!obj) return NULL;
4497 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4499 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4501 "InvalidCastException"));
4506 MonoDomain *orig_domain;
4512 str_lookup (MonoDomain *domain, gpointer user_data)
4514 LDStrInfo *info = user_data;
4515 if (info->res || domain == info->orig_domain)
4517 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4523 mono_string_get_pinned (MonoString *str)
4527 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4528 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4529 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4530 news->length = mono_string_length (str);
4535 #define mono_string_get_pinned(str) (str)
4539 mono_string_is_interned_lookup (MonoString *str, int insert)
4541 MonoGHashTable *ldstr_table;
4545 domain = ((MonoObject *)str)->vtable->domain;
4546 ldstr_table = domain->ldstr_table;
4548 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4553 str = mono_string_get_pinned (str);
4554 mono_g_hash_table_insert (ldstr_table, str, str);
4558 LDStrInfo ldstr_info;
4559 ldstr_info.orig_domain = domain;
4560 ldstr_info.ins = str;
4561 ldstr_info.res = NULL;
4563 mono_domain_foreach (str_lookup, &ldstr_info);
4564 if (ldstr_info.res) {
4566 * the string was already interned in some other domain:
4567 * intern it in the current one as well.
4569 mono_g_hash_table_insert (ldstr_table, str, str);
4579 * mono_string_is_interned:
4580 * @o: String to probe
4582 * Returns whether the string has been interned.
4585 mono_string_is_interned (MonoString *o)
4587 return mono_string_is_interned_lookup (o, FALSE);
4591 * mono_string_intern:
4592 * @o: String to intern
4594 * Interns the string passed.
4595 * Returns: The interned string.
4598 mono_string_intern (MonoString *str)
4600 return mono_string_is_interned_lookup (str, TRUE);
4605 * @domain: the domain where the string will be used.
4606 * @image: a metadata context
4607 * @idx: index into the user string table.
4609 * Implementation for the ldstr opcode.
4610 * Returns: a loaded string from the @image/@idx combination.
4613 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4615 MONO_ARCH_SAVE_REGS;
4618 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4620 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4624 * mono_ldstr_metadata_sig
4625 * @domain: the domain for the string
4626 * @sig: the signature of a metadata string
4628 * Returns: a MonoString for a string stored in the metadata
4631 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4633 const char *str = sig;
4634 MonoString *o, *interned;
4637 len2 = mono_metadata_decode_blob_size (str, &str);
4640 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4641 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4644 guint16 *p2 = (guint16*)mono_string_chars (o);
4645 for (i = 0; i < len2; ++i) {
4646 *p2 = GUINT16_FROM_LE (*p2);
4652 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4654 /* o will get garbage collected */
4658 o = mono_string_get_pinned (o);
4659 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4666 * mono_string_to_utf8:
4667 * @s: a System.String
4669 * Return the UTF8 representation for @s.
4670 * the resulting buffer nedds to be freed with g_free().
4673 mono_string_to_utf8 (MonoString *s)
4677 GError *error = NULL;
4683 return g_strdup ("");
4685 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4687 MonoException *exc = mono_get_exception_argument ("string", error->message);
4688 g_error_free (error);
4689 mono_raise_exception(exc);
4691 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4692 if (s->length > written) {
4693 /* allocate the total length and copy the part of the string that has been converted */
4694 char *as2 = g_malloc0 (s->length);
4695 memcpy (as2, as, written);
4704 * mono_string_to_utf16:
4707 * Return an null-terminated array of the utf-16 chars
4708 * contained in @s. The result must be freed with g_free().
4709 * This is a temporary helper until our string implementation
4710 * is reworked to always include the null terminating char.
4713 mono_string_to_utf16 (MonoString *s)
4720 as = g_malloc ((s->length * 2) + 2);
4721 as [(s->length * 2)] = '\0';
4722 as [(s->length * 2) + 1] = '\0';
4725 return (gunichar2 *)(as);
4728 memcpy (as, mono_string_chars(s), s->length * 2);
4729 return (gunichar2 *)(as);
4733 * mono_string_from_utf16:
4734 * @data: the UTF16 string (LPWSTR) to convert
4736 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4738 * Returns: a MonoString.
4741 mono_string_from_utf16 (gunichar2 *data)
4743 MonoDomain *domain = mono_domain_get ();
4749 while (data [len]) len++;
4751 return mono_string_new_utf16 (domain, data, len);
4756 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4763 return mono_string_to_utf8 (s);
4765 r = mono_string_to_utf8 (s);
4769 len = strlen (r) + 1;
4771 mp_s = mono_mempool_alloc (mp, len);
4773 mp_s = mono_image_alloc (image, len);
4775 memcpy (mp_s, r, len);
4783 * mono_string_to_utf8_image:
4784 * @s: a System.String
4786 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4789 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4791 return mono_string_to_utf8_internal (NULL, image, s);
4795 * mono_string_to_utf8_mp:
4796 * @s: a System.String
4798 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4801 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4803 return mono_string_to_utf8_internal (mp, NULL, s);
4807 default_ex_handler (MonoException *ex)
4809 MonoObject *o = (MonoObject*)ex;
4810 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4814 static MonoExceptionFunc ex_handler = default_ex_handler;
4817 * mono_install_handler:
4818 * @func: exception handler
4820 * This is an internal JIT routine used to install the handler for exceptions
4824 mono_install_handler (MonoExceptionFunc func)
4826 ex_handler = func? func: default_ex_handler;
4830 * mono_raise_exception:
4831 * @ex: exception object
4833 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4836 mono_raise_exception (MonoException *ex)
4839 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4840 * that will cause gcc to omit the function epilog, causing problems when
4841 * the JIT tries to walk the stack, since the return address on the stack
4842 * will point into the next function in the executable, not this one.
4845 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4846 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4852 * mono_wait_handle_new:
4853 * @domain: Domain where the object will be created
4854 * @handle: Handle for the wait handle
4856 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4859 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4861 MonoWaitHandle *res;
4862 gpointer params [1];
4863 static MonoMethod *handle_set;
4865 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4867 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4869 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4871 params [0] = &handle;
4872 mono_runtime_invoke (handle_set, res, params, NULL);
4878 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4880 static MonoClassField *f_os_handle;
4881 static MonoClassField *f_safe_handle;
4883 if (!f_os_handle && !f_safe_handle) {
4884 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4885 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4890 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4894 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4900 * mono_async_result_new:
4901 * @domain:domain where the object will be created.
4902 * @handle: wait handle.
4903 * @state: state to pass to AsyncResult
4904 * @data: C closure data.
4906 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4907 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4911 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4913 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4914 MonoMethod *method = mono_get_context_capture_method ();
4916 /* we must capture the execution context from the original thread */
4918 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4919 /* note: result may be null if the flow is suppressed */
4923 MONO_OBJECT_SETREF (res, object_data, object_data);
4924 MONO_OBJECT_SETREF (res, async_state, state);
4926 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4928 res->sync_completed = FALSE;
4929 res->completed = FALSE;
4935 mono_message_init (MonoDomain *domain,
4936 MonoMethodMessage *this,
4937 MonoReflectionMethod *method,
4938 MonoArray *out_args)
4940 static MonoClass *object_array_klass;
4941 static MonoClass *byte_array_klass;
4942 static MonoClass *string_array_klass;
4943 MonoMethodSignature *sig = mono_method_signature (method->method);
4949 if (!object_array_klass) {
4952 klass = mono_array_class_get (mono_defaults.object_class, 1);
4955 mono_memory_barrier ();
4956 object_array_klass = klass;
4958 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4961 mono_memory_barrier ();
4962 byte_array_klass = klass;
4964 klass = mono_array_class_get (mono_defaults.string_class, 1);
4967 mono_memory_barrier ();
4968 string_array_klass = klass;
4971 MONO_OBJECT_SETREF (this, method, method);
4973 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4974 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4975 this->async_result = NULL;
4976 this->call_type = CallType_Sync;
4978 names = g_new (char *, sig->param_count);
4979 mono_method_get_param_names (method->method, (const char **) names);
4980 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4982 for (i = 0; i < sig->param_count; i++) {
4983 name = mono_string_new (domain, names [i]);
4984 mono_array_setref (this->names, i, name);
4988 for (i = 0, j = 0; i < sig->param_count; i++) {
4989 if (sig->params [i]->byref) {
4991 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4992 mono_array_setref (this->args, i, arg);
4996 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5000 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5003 mono_array_set (this->arg_types, guint8, i, arg_type);
5008 * mono_remoting_invoke:
5009 * @real_proxy: pointer to a RealProxy object
5010 * @msg: The MonoMethodMessage to execute
5011 * @exc: used to store exceptions
5012 * @out_args: used to store output arguments
5014 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5015 * IMessage interface and it is not trivial to extract results from there. So
5016 * we call an helper method PrivateInvoke instead of calling
5017 * RealProxy::Invoke() directly.
5019 * Returns: the result object.
5022 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5023 MonoObject **exc, MonoArray **out_args)
5025 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5028 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5031 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5033 real_proxy->vtable->domain->private_invoke_method = im;
5036 pa [0] = real_proxy;
5041 return mono_runtime_invoke (im, NULL, pa, exc);
5045 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5046 MonoObject **exc, MonoArray **out_args)
5048 static MonoClass *object_array_klass;
5051 MonoMethodSignature *sig;
5053 int i, j, outarg_count = 0;
5055 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5057 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5058 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5059 target = tp->rp->unwrapped_server;
5061 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5065 domain = mono_domain_get ();
5066 method = msg->method->method;
5067 sig = mono_method_signature (method);
5069 for (i = 0; i < sig->param_count; i++) {
5070 if (sig->params [i]->byref)
5074 if (!object_array_klass) {
5077 klass = mono_array_class_get (mono_defaults.object_class, 1);
5080 mono_memory_barrier ();
5081 object_array_klass = klass;
5084 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5085 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5088 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5090 for (i = 0, j = 0; i < sig->param_count; i++) {
5091 if (sig->params [i]->byref) {
5093 arg = mono_array_get (msg->args, gpointer, i);
5094 mono_array_setref (*out_args, j, arg);
5103 * mono_print_unhandled_exception:
5104 * @exc: The exception
5106 * Prints the unhandled exception.
5109 mono_print_unhandled_exception (MonoObject *exc)
5111 char *message = (char *) "";
5115 gboolean free_message = FALSE;
5117 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5118 klass = exc->vtable->klass;
5120 while (klass && method == NULL) {
5121 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5123 klass = klass->parent;
5128 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5130 message = mono_string_to_utf8 (str);
5131 free_message = TRUE;
5136 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5137 * exc->vtable->klass->name, message);
5139 g_printerr ("\nUnhandled Exception: %s\n", message);
5146 * mono_delegate_ctor:
5147 * @this: pointer to an uninitialized delegate object
5148 * @target: target object
5149 * @addr: pointer to native code
5152 * Initialize a delegate and sets a specific method, not the one
5153 * associated with addr. This is useful when sharing generic code.
5154 * In that case addr will most probably not be associated with the
5155 * correct instantiation of the method.
5158 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5160 MonoDelegate *delegate = (MonoDelegate *)this;
5167 delegate->method = method;
5169 class = this->vtable->klass;
5170 mono_stats.delegate_creations++;
5172 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5174 method = mono_marshal_get_remoting_invoke (method);
5175 delegate->method_ptr = mono_compile_method (method);
5176 MONO_OBJECT_SETREF (delegate, target, target);
5177 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5178 method = mono_marshal_get_unbox_wrapper (method);
5179 delegate->method_ptr = mono_compile_method (method);
5180 MONO_OBJECT_SETREF (delegate, target, target);
5182 delegate->method_ptr = addr;
5183 MONO_OBJECT_SETREF (delegate, target, target);
5186 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5190 * mono_delegate_ctor:
5191 * @this: pointer to an uninitialized delegate object
5192 * @target: target object
5193 * @addr: pointer to native code
5195 * This is used to initialize a delegate.
5198 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5200 MonoDomain *domain = mono_domain_get ();
5202 MonoMethod *method = NULL;
5206 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5207 method = ji->method;
5208 g_assert (!method->klass->generic_container);
5211 mono_delegate_ctor_with_method (this, target, addr, method);
5215 * mono_method_call_message_new:
5216 * @method: method to encapsulate
5217 * @params: parameters to the method
5218 * @invoke: optional, delegate invoke.
5219 * @cb: async callback delegate.
5220 * @state: state passed to the async callback.
5222 * Translates arguments pointers into a MonoMethodMessage.
5225 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5226 MonoDelegate **cb, MonoObject **state)
5228 MonoDomain *domain = mono_domain_get ();
5229 MonoMethodSignature *sig = mono_method_signature (method);
5230 MonoMethodMessage *msg;
5233 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5236 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5237 count = sig->param_count - 2;
5239 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5240 count = sig->param_count;
5243 for (i = 0; i < count; i++) {
5248 if (sig->params [i]->byref)
5249 vpos = *((gpointer *)params [i]);
5253 type = sig->params [i]->type;
5254 class = mono_class_from_mono_type (sig->params [i]);
5256 if (class->valuetype)
5257 arg = mono_value_box (domain, class, vpos);
5259 arg = *((MonoObject **)vpos);
5261 mono_array_setref (msg->args, i, arg);
5264 if (cb != NULL && state != NULL) {
5265 *cb = *((MonoDelegate **)params [i]);
5267 *state = *((MonoObject **)params [i]);
5274 * mono_method_return_message_restore:
5276 * Restore results from message based processing back to arguments pointers
5279 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5281 MonoMethodSignature *sig = mono_method_signature (method);
5282 int i, j, type, size, out_len;
5284 if (out_args == NULL)
5286 out_len = mono_array_length (out_args);
5290 for (i = 0, j = 0; i < sig->param_count; i++) {
5291 MonoType *pt = sig->params [i];
5296 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5298 arg = mono_array_get (out_args, gpointer, j);
5302 case MONO_TYPE_VOID:
5303 g_assert_not_reached ();
5307 case MONO_TYPE_BOOLEAN:
5310 case MONO_TYPE_CHAR:
5317 case MONO_TYPE_VALUETYPE: {
5319 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5320 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5323 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5324 memset (*((gpointer *)params [i]), 0, size);
5328 case MONO_TYPE_STRING:
5329 case MONO_TYPE_CLASS:
5330 case MONO_TYPE_ARRAY:
5331 case MONO_TYPE_SZARRAY:
5332 case MONO_TYPE_OBJECT:
5333 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5336 g_assert_not_reached ();
5345 * mono_load_remote_field:
5346 * @this: pointer to an object
5347 * @klass: klass of the object containing @field
5348 * @field: the field to load
5349 * @res: a storage to store the result
5351 * This method is called by the runtime on attempts to load fields of
5352 * transparent proxy objects. @this points to such TP, @klass is the class of
5353 * the object containing @field. @res is a storage location which can be
5354 * used to store the result.
5356 * Returns: an address pointing to the value of field.
5359 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5361 static MonoMethod *getter = NULL;
5362 MonoDomain *domain = mono_domain_get ();
5363 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5364 MonoClass *field_class;
5365 MonoMethodMessage *msg;
5366 MonoArray *out_args;
5370 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5371 g_assert (res != NULL);
5373 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5374 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5379 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5383 field_class = mono_class_from_mono_type (field->type);
5385 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5386 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5387 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5389 full_name = mono_type_get_full_name (klass);
5390 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5391 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5394 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5396 if (exc) mono_raise_exception ((MonoException *)exc);
5398 if (mono_array_length (out_args) == 0)
5401 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5403 if (field_class->valuetype) {
5404 return ((char *)*res) + sizeof (MonoObject);
5410 * mono_load_remote_field_new:
5415 * Missing documentation.
5418 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5420 static MonoMethod *getter = NULL;
5421 MonoDomain *domain = mono_domain_get ();
5422 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5423 MonoClass *field_class;
5424 MonoMethodMessage *msg;
5425 MonoArray *out_args;
5426 MonoObject *exc, *res;
5429 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5431 field_class = mono_class_from_mono_type (field->type);
5433 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5435 if (field_class->valuetype) {
5436 res = mono_object_new (domain, field_class);
5437 val = ((gchar *) res) + sizeof (MonoObject);
5441 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5446 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5450 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5451 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5453 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5455 full_name = mono_type_get_full_name (klass);
5456 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5457 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5460 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5462 if (exc) mono_raise_exception ((MonoException *)exc);
5464 if (mono_array_length (out_args) == 0)
5467 res = mono_array_get (out_args, MonoObject *, 0);
5473 * mono_store_remote_field:
5474 * @this: pointer to an object
5475 * @klass: klass of the object containing @field
5476 * @field: the field to load
5477 * @val: the value/object to store
5479 * This method is called by the runtime on attempts to store fields of
5480 * transparent proxy objects. @this points to such TP, @klass is the class of
5481 * the object containing @field. @val is the new value to store in @field.
5484 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5486 static MonoMethod *setter = NULL;
5487 MonoDomain *domain = mono_domain_get ();
5488 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5489 MonoClass *field_class;
5490 MonoMethodMessage *msg;
5491 MonoArray *out_args;
5496 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5498 field_class = mono_class_from_mono_type (field->type);
5500 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5501 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5502 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5507 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5511 if (field_class->valuetype)
5512 arg = mono_value_box (domain, field_class, val);
5514 arg = *((MonoObject **)val);
5517 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5518 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5520 full_name = mono_type_get_full_name (klass);
5521 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5522 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5523 mono_array_setref (msg->args, 2, arg);
5526 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5528 if (exc) mono_raise_exception ((MonoException *)exc);
5532 * mono_store_remote_field_new:
5538 * Missing documentation
5541 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5543 static MonoMethod *setter = NULL;
5544 MonoDomain *domain = mono_domain_get ();
5545 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5546 MonoClass *field_class;
5547 MonoMethodMessage *msg;
5548 MonoArray *out_args;
5552 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5554 field_class = mono_class_from_mono_type (field->type);
5556 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5557 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5558 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5563 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5567 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5568 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5570 full_name = mono_type_get_full_name (klass);
5571 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5572 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5573 mono_array_setref (msg->args, 2, arg);
5576 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5578 if (exc) mono_raise_exception ((MonoException *)exc);
5582 * mono_create_ftnptr:
5584 * Given a function address, create a function descriptor for it.
5585 * This is only needed on IA64 and PPC64.
5588 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5593 desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
5599 #elif defined(__ppc64__) || defined(__powerpc64__)
5602 desc = mono_domain_code_reserve (domain, 3 * sizeof (gpointer));
5615 * mono_get_addr_from_ftnptr:
5617 * Given a pointer to a function descriptor, return the function address.
5618 * This is only needed on IA64 and PPC64.
5621 mono_get_addr_from_ftnptr (gpointer descr)
5623 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5624 return *(gpointer*)descr;
5632 * mono_string_chars:
5635 * Returns a pointer to the UCS16 characters stored in the MonoString
5638 mono_string_chars(MonoString *s)
5640 /* This method is here only for documentation extraction, this is a macro */
5644 * mono_string_length:
5647 * Returns the lenght in characters of the string
5650 mono_string_length (MonoString *s)
5652 /* This method is here only for documentation extraction, this is a macro */