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-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/threadpool.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include "cominterop.h"
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
51 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
52 #ifdef HAVE_GC_GCJ_MALLOC
53 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
66 #define NEED_TO_ZERO_PTRFREE 1
67 #define GC_NO_DESCRIPTOR (NULL)
68 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
69 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
70 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
84 free_main_args (void);
87 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
90 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
91 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
92 static CRITICAL_SECTION ldstr_section;
94 static gboolean profile_allocs = TRUE;
97 mono_runtime_object_init (MonoObject *this)
99 MonoMethod *method = NULL;
100 MonoClass *klass = this->vtable->klass;
102 method = mono_class_get_method_from_name (klass, ".ctor", 0);
105 if (method->klass->valuetype)
106 this = mono_object_unbox (this);
107 mono_runtime_invoke (method, this, NULL, NULL);
110 /* The pseudo algorithm for type initialization from the spec
111 Note it doesn't say anything about domains - only threads.
113 2. If the type is initialized you are done.
114 2.1. If the type is not yet initialized, try to take an
116 2.2. If successful, record this thread as responsible for
117 initializing the type and proceed to step 2.3.
118 2.2.1. If not, see whether this thread or any thread
119 waiting for this thread to complete already holds the lock.
120 2.2.2. If so, return since blocking would create a deadlock. This thread
121 will now see an incompletely initialized state for the type,
122 but no deadlock will arise.
123 2.2.3 If not, block until the type is initialized then return.
124 2.3 Initialize the parent type and then all interfaces implemented
126 2.4 Execute the type initialization code for this type.
127 2.5 Mark the type as initialized, release the initialization lock,
128 awaken any threads waiting for this type to be initialized,
135 guint32 initializing_tid;
136 guint32 waiting_count;
138 CRITICAL_SECTION initialization_section;
139 } TypeInitializationLock;
141 /* for locking access to type_initialization_hash and blocked_thread_hash */
142 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
143 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
144 static CRITICAL_SECTION type_initialization_section;
146 /* from vtable to lock */
147 static GHashTable *type_initialization_hash;
149 /* from thread id to thread id being waited on */
150 static GHashTable *blocked_thread_hash;
153 static MonoThread *main_thread;
155 /* Functions supplied by the runtime */
156 static MonoRuntimeCallbacks callbacks;
159 * mono_thread_set_main:
160 * @thread: thread to set as the main thread
162 * This function can be used to instruct the runtime to treat @thread
163 * as the main thread, ie, the thread that would normally execute the Main()
164 * method. This basically means that at the end of @thread, the runtime will
165 * wait for the existing foreground threads to quit and other such details.
168 mono_thread_set_main (MonoThread *thread)
170 static gboolean registered = FALSE;
173 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
177 main_thread = thread;
181 mono_thread_get_main (void)
187 mono_type_initialization_init (void)
189 InitializeCriticalSection (&type_initialization_section);
190 type_initialization_hash = g_hash_table_new (NULL, NULL);
191 blocked_thread_hash = g_hash_table_new (NULL, NULL);
192 InitializeCriticalSection (&ldstr_section);
196 mono_type_initialization_cleanup (void)
199 /* This is causing race conditions with
200 * mono_release_type_locks
202 DeleteCriticalSection (&type_initialization_section);
203 g_hash_table_destroy (type_initialization_hash);
204 type_initialization_hash = NULL;
206 DeleteCriticalSection (&ldstr_section);
207 g_hash_table_destroy (blocked_thread_hash);
208 blocked_thread_hash = NULL;
214 * get_type_init_exception_for_vtable:
216 * Return the stored type initialization exception for VTABLE.
218 static MonoException*
219 get_type_init_exception_for_vtable (MonoVTable *vtable)
221 MonoDomain *domain = vtable->domain;
222 MonoClass *klass = vtable->klass;
226 g_assert (vtable->init_failed);
229 * If the initializing thread was rudely aborted, the exception is not stored
233 mono_domain_lock (domain);
234 if (domain->type_init_exception_hash)
235 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
236 mono_domain_unlock (domain);
239 if (klass->name_space && *klass->name_space)
240 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
242 full_name = g_strdup (klass->name);
243 ex = mono_get_exception_type_initialization (full_name, NULL);
250 * mono_runtime_class_init:
251 * @vtable: vtable that needs to be initialized
253 * This routine calls the class constructor for @vtable.
256 mono_runtime_class_init (MonoVTable *vtable)
258 mono_runtime_class_init_full (vtable, TRUE);
262 * mono_runtime_class_init_full:
263 * @vtable that neeeds to be initialized
264 * @raise_exception is TRUE, exceptions are raised intead of returned
268 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
271 MonoException *exc_to_throw;
272 MonoMethod *method = NULL;
278 if (vtable->initialized)
282 klass = vtable->klass;
284 if (!klass->image->checked_module_cctor) {
285 mono_image_check_for_module_cctor (klass->image);
286 if (klass->image->has_module_cctor) {
287 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
288 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
291 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
296 method = mono_class_get_cctor (klass);
299 MonoDomain *domain = vtable->domain;
300 TypeInitializationLock *lock;
301 guint32 tid = GetCurrentThreadId();
302 int do_initialization = 0;
303 MonoDomain *last_domain = NULL;
305 mono_type_initialization_lock ();
306 /* double check... */
307 if (vtable->initialized) {
308 mono_type_initialization_unlock ();
311 if (vtable->init_failed) {
312 mono_type_initialization_unlock ();
314 /* The type initialization already failed once, rethrow the same exception */
316 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
317 return get_type_init_exception_for_vtable (vtable);
319 lock = g_hash_table_lookup (type_initialization_hash, vtable);
321 /* This thread will get to do the initialization */
322 if (mono_domain_get () != domain) {
323 /* Transfer into the target domain */
324 last_domain = mono_domain_get ();
325 if (!mono_domain_set (domain, FALSE)) {
326 vtable->initialized = 1;
327 mono_type_initialization_unlock ();
329 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
330 return mono_get_exception_appdomain_unloaded ();
333 lock = g_malloc (sizeof(TypeInitializationLock));
334 InitializeCriticalSection (&lock->initialization_section);
335 lock->initializing_tid = tid;
336 lock->waiting_count = 1;
338 /* grab the vtable lock while this thread still owns type_initialization_section */
339 EnterCriticalSection (&lock->initialization_section);
340 g_hash_table_insert (type_initialization_hash, vtable, lock);
341 do_initialization = 1;
344 TypeInitializationLock *pending_lock;
346 if (lock->initializing_tid == tid || lock->done) {
347 mono_type_initialization_unlock ();
350 /* see if the thread doing the initialization is already blocked on this thread */
351 blocked = GUINT_TO_POINTER (lock->initializing_tid);
352 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
353 if (pending_lock->initializing_tid == tid) {
354 if (!pending_lock->done) {
355 mono_type_initialization_unlock ();
358 /* the thread doing the initialization is blocked on this thread,
359 but on a lock that has already been freed. It just hasn't got
364 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
366 ++lock->waiting_count;
367 /* record the fact that we are waiting on the initializing thread */
368 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
370 mono_type_initialization_unlock ();
372 if (do_initialization) {
373 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
375 /* If the initialization failed, mark the class as unusable. */
376 /* Avoid infinite loops */
378 (klass->image == mono_defaults.corlib &&
379 !strcmp (klass->name_space, "System") &&
380 !strcmp (klass->name, "TypeInitializationException")))) {
381 vtable->init_failed = 1;
383 if (klass->name_space && *klass->name_space)
384 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
386 full_name = g_strdup (klass->name);
387 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
391 * Store the exception object so it could be thrown on subsequent
394 mono_domain_lock (domain);
395 if (!domain->type_init_exception_hash)
396 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
397 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
398 mono_domain_unlock (domain);
402 mono_domain_set (last_domain, TRUE);
404 LeaveCriticalSection (&lock->initialization_section);
406 /* this just blocks until the initializing thread is done */
407 EnterCriticalSection (&lock->initialization_section);
408 LeaveCriticalSection (&lock->initialization_section);
411 mono_type_initialization_lock ();
412 if (lock->initializing_tid != tid)
413 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
414 --lock->waiting_count;
415 if (lock->waiting_count == 0) {
416 DeleteCriticalSection (&lock->initialization_section);
417 g_hash_table_remove (type_initialization_hash, vtable);
420 mono_memory_barrier ();
421 if (!vtable->init_failed)
422 vtable->initialized = 1;
423 mono_type_initialization_unlock ();
425 if (vtable->init_failed) {
426 /* Either we were the initializing thread or we waited for the initialization */
428 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
429 return get_type_init_exception_for_vtable (vtable);
432 vtable->initialized = 1;
439 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
441 MonoVTable *vtable = (MonoVTable*)key;
443 TypeInitializationLock *lock = (TypeInitializationLock*) value;
444 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
447 * Have to set this since it cannot be set by the normal code in
448 * mono_runtime_class_init (). In this case, the exception object is not stored,
449 * and get_type_init_exception_for_class () needs to be aware of this.
451 vtable->init_failed = 1;
452 LeaveCriticalSection (&lock->initialization_section);
453 --lock->waiting_count;
454 if (lock->waiting_count == 0) {
455 DeleteCriticalSection (&lock->initialization_section);
464 mono_release_type_locks (MonoInternalThread *thread)
466 mono_type_initialization_lock ();
467 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
468 mono_type_initialization_unlock ();
472 default_trampoline (MonoMethod *method)
478 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
480 g_assert_not_reached ();
486 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
488 g_error ("remoting not installed");
493 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
495 g_assert_not_reached ();
499 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
500 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
501 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
502 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
503 static MonoImtThunkBuilder imt_thunk_builder = NULL;
504 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
505 #if (MONO_IMT_SIZE > 32)
506 #error "MONO_IMT_SIZE cannot be larger than 32"
510 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
512 memcpy (&callbacks, cbs, sizeof (*cbs));
515 MonoRuntimeCallbacks*
516 mono_get_runtime_callbacks (void)
522 mono_install_trampoline (MonoTrampoline func)
524 arch_create_jit_trampoline = func? func: default_trampoline;
528 mono_install_jump_trampoline (MonoJumpTrampoline func)
530 arch_create_jump_trampoline = func? func: default_jump_trampoline;
534 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
536 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
540 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
542 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
546 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
547 imt_thunk_builder = func;
550 static MonoCompileFunc default_mono_compile_method = NULL;
553 * mono_install_compile_method:
554 * @func: function to install
556 * This is a VM internal routine
559 mono_install_compile_method (MonoCompileFunc func)
561 default_mono_compile_method = func;
565 * mono_compile_method:
566 * @method: The method to compile.
568 * This JIT-compiles the method, and returns the pointer to the native code
572 mono_compile_method (MonoMethod *method)
574 if (!default_mono_compile_method) {
575 g_error ("compile method called on uninitialized runtime");
578 return default_mono_compile_method (method);
582 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
584 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
588 mono_runtime_create_delegate_trampoline (MonoClass *klass)
590 return arch_create_delegate_trampoline (mono_domain_get (), klass);
593 static MonoFreeMethodFunc default_mono_free_method = NULL;
596 * mono_install_free_method:
597 * @func: pointer to the MonoFreeMethodFunc used to release a method
599 * This is an internal VM routine, it is used for the engines to
600 * register a handler to release the resources associated with a method.
602 * Methods are freed when no more references to the delegate that holds
606 mono_install_free_method (MonoFreeMethodFunc func)
608 default_mono_free_method = func;
612 * mono_runtime_free_method:
613 * @domain; domain where the method is hosted
614 * @method: method to release
616 * This routine is invoked to free the resources associated with
617 * a method that has been JIT compiled. This is used to discard
618 * methods that were used only temporarily (for example, used in marshalling)
622 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
624 if (default_mono_free_method != NULL)
625 default_mono_free_method (domain, method);
627 mono_method_clear_object (domain, method);
629 mono_free_method (method);
633 * The vtables in the root appdomain are assumed to be reachable by other
634 * roots, and we don't use typed allocation in the other domains.
637 /* The sync block is no longer a GC pointer */
638 #define GC_HEADER_BITMAP (0)
640 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
643 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
645 MonoClassField *field;
651 max_size = mono_class_data_size (class) / sizeof (gpointer);
653 max_size = class->instance_size / sizeof (gpointer);
654 if (max_size > size) {
655 g_assert (offset <= 0);
656 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
661 /*An Ephemeron cannot be marked by sgen*/
662 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
664 memset (bitmap, 0, size / 8);
669 for (p = class; p != NULL; p = p->parent) {
670 gpointer iter = NULL;
671 while ((field = mono_class_get_fields (p, &iter))) {
675 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
677 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
680 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
683 /* FIXME: should not happen, flag as type load error */
684 if (field->type->byref)
687 if (static_fields && field->offset == -1)
691 pos = field->offset / sizeof (gpointer);
694 type = mono_type_get_underlying_type (field->type);
695 switch (type->type) {
698 case MONO_TYPE_FNPTR:
700 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
705 if (class->image != mono_defaults.corlib)
708 case MONO_TYPE_STRING:
709 case MONO_TYPE_SZARRAY:
710 case MONO_TYPE_CLASS:
711 case MONO_TYPE_OBJECT:
712 case MONO_TYPE_ARRAY:
713 g_assert ((field->offset % sizeof(gpointer)) == 0);
715 g_assert (pos < size || pos <= max_size);
716 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
717 *max_set = MAX (*max_set, pos);
719 case MONO_TYPE_GENERICINST:
720 if (!mono_type_generic_inst_is_valuetype (type)) {
721 g_assert ((field->offset % sizeof(gpointer)) == 0);
723 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
724 *max_set = MAX (*max_set, pos);
729 case MONO_TYPE_VALUETYPE: {
730 MonoClass *fclass = mono_class_from_mono_type (field->type);
731 if (fclass->has_references) {
732 /* remove the object header */
733 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
747 case MONO_TYPE_BOOLEAN:
751 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
762 * mono_class_compute_bitmap:
764 * Mono internal function to compute a bitmap of reference fields in a class.
767 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
769 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
774 * similar to the above, but sets the bits in the bitmap for any non-ref field
775 * and ignores static fields
778 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
780 MonoClassField *field;
785 max_size = class->instance_size / sizeof (gpointer);
786 if (max_size >= size) {
787 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
790 for (p = class; p != NULL; p = p->parent) {
791 gpointer iter = NULL;
792 while ((field = mono_class_get_fields (p, &iter))) {
795 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
797 /* FIXME: should not happen, flag as type load error */
798 if (field->type->byref)
801 pos = field->offset / sizeof (gpointer);
804 type = mono_type_get_underlying_type (field->type);
805 switch (type->type) {
806 #if SIZEOF_VOID_P == 8
810 case MONO_TYPE_FNPTR:
815 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
816 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
817 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
820 #if SIZEOF_VOID_P == 4
824 case MONO_TYPE_FNPTR:
829 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
830 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
831 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
837 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
838 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
839 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
842 case MONO_TYPE_BOOLEAN:
845 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
847 case MONO_TYPE_STRING:
848 case MONO_TYPE_SZARRAY:
849 case MONO_TYPE_CLASS:
850 case MONO_TYPE_OBJECT:
851 case MONO_TYPE_ARRAY:
853 case MONO_TYPE_GENERICINST:
854 if (!mono_type_generic_inst_is_valuetype (type)) {
859 case MONO_TYPE_VALUETYPE: {
860 MonoClass *fclass = mono_class_from_mono_type (field->type);
861 /* remove the object header */
862 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
866 g_assert_not_reached ();
875 * mono_class_insecure_overlapping:
876 * check if a class with explicit layout has references and non-references
877 * fields overlapping.
879 * Returns: TRUE if it is insecure to load the type.
882 mono_class_insecure_overlapping (MonoClass *klass)
886 gsize default_bitmap [4] = {0};
888 gsize default_nrbitmap [4] = {0};
889 int i, insecure = FALSE;
892 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
893 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
895 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
896 int idx = i % (sizeof (bitmap [0]) * 8);
897 if (bitmap [idx] & nrbitmap [idx]) {
902 if (bitmap != default_bitmap)
904 if (nrbitmap != default_nrbitmap)
907 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
915 mono_string_alloc (int length)
917 return mono_string_new_size (mono_domain_get (), length);
921 mono_class_compute_gc_descriptor (MonoClass *class)
925 gsize default_bitmap [4] = {0};
926 static gboolean gcj_inited = FALSE;
931 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
932 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
933 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
934 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
936 #ifdef HAVE_GC_GCJ_MALLOC
938 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
942 #ifdef GC_REDIRECT_TO_LOCAL
943 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
944 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
946 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
947 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
952 mono_loader_unlock ();
956 mono_class_init (class);
958 if (class->gc_descr_inited)
961 class->gc_descr_inited = TRUE;
962 class->gc_descr = GC_NO_DESCRIPTOR;
964 bitmap = default_bitmap;
965 if (class == mono_defaults.string_class) {
966 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
967 } else if (class->rank) {
968 mono_class_compute_gc_descriptor (class->element_class);
969 if (!class->element_class->valuetype) {
971 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
972 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
973 class->name_space, class->name);*/
975 /* remove the object header */
976 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
977 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
978 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
979 class->name_space, class->name);*/
980 if (bitmap != default_bitmap)
984 /*static int count = 0;
987 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
988 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
990 if (class->gc_descr == GC_NO_DESCRIPTOR)
991 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
993 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
994 if (bitmap != default_bitmap)
1000 * field_is_special_static:
1001 * @fklass: The MonoClass to look up.
1002 * @field: The MonoClassField describing the field.
1004 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1005 * SPECIAL_STATIC_NONE otherwise.
1008 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1010 MonoCustomAttrInfo *ainfo;
1012 ainfo = mono_custom_attrs_from_field (fklass, field);
1015 for (i = 0; i < ainfo->num_attrs; ++i) {
1016 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1017 if (klass->image == mono_defaults.corlib) {
1018 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1019 mono_custom_attrs_free (ainfo);
1020 return SPECIAL_STATIC_THREAD;
1022 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1023 mono_custom_attrs_free (ainfo);
1024 return SPECIAL_STATIC_CONTEXT;
1028 mono_custom_attrs_free (ainfo);
1029 return SPECIAL_STATIC_NONE;
1032 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1033 #define mix(a,b,c) { \
1034 a -= c; a ^= rot(c, 4); c += b; \
1035 b -= a; b ^= rot(a, 6); a += c; \
1036 c -= b; c ^= rot(b, 8); b += a; \
1037 a -= c; a ^= rot(c,16); c += b; \
1038 b -= a; b ^= rot(a,19); a += c; \
1039 c -= b; c ^= rot(b, 4); b += a; \
1041 #define final(a,b,c) { \
1042 c ^= b; c -= rot(b,14); \
1043 a ^= c; a -= rot(c,11); \
1044 b ^= a; b -= rot(a,25); \
1045 c ^= b; c -= rot(b,16); \
1046 a ^= c; a -= rot(c,4); \
1047 b ^= a; b -= rot(a,14); \
1048 c ^= b; c -= rot(b,24); \
1052 * mono_method_get_imt_slot:
1054 * The IMT slot is embedded into AOTed code, so this must return the same value
1055 * for the same method across all executions. This means:
1056 * - pointers shouldn't be used as hash values.
1057 * - mono_metadata_str_hash () should be used for hashing strings.
1060 mono_method_get_imt_slot (MonoMethod *method)
1062 MonoMethodSignature *sig;
1064 guint32 *hashes_start, *hashes;
1068 /* This can be used to stress tests the collision code */
1072 * We do this to simplify generic sharing. It will hurt
1073 * performance in cases where a class implements two different
1074 * instantiations of the same generic interface.
1075 * The code in build_imt_slots () depends on this.
1077 if (method->is_inflated)
1078 method = ((MonoMethodInflated*)method)->declaring;
1080 sig = mono_method_signature (method);
1081 hashes_count = sig->param_count + 4;
1082 hashes_start = malloc (hashes_count * sizeof (guint32));
1083 hashes = hashes_start;
1085 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1086 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1087 method->klass->name_space, method->klass->name, method->name);
1088 g_assert_not_reached ();
1091 /* Initialize hashes */
1092 hashes [0] = mono_metadata_str_hash (method->klass->name);
1093 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1094 hashes [2] = mono_metadata_str_hash (method->name);
1095 hashes [3] = mono_metadata_type_hash (sig->ret);
1096 for (i = 0; i < sig->param_count; i++) {
1097 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1100 /* Setup internal state */
1101 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1103 /* Handle most of the hashes */
1104 while (hashes_count > 3) {
1113 /* Handle the last 3 hashes (all the case statements fall through) */
1114 switch (hashes_count) {
1115 case 3 : c += hashes [2];
1116 case 2 : b += hashes [1];
1117 case 1 : a += hashes [0];
1119 case 0: /* nothing left to add */
1123 free (hashes_start);
1124 /* Report the result */
1125 return c % MONO_IMT_SIZE;
1134 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1135 guint32 imt_slot = mono_method_get_imt_slot (method);
1136 MonoImtBuilderEntry *entry;
1138 if (slot_num >= 0 && imt_slot != slot_num) {
1139 /* we build just a single imt slot and this is not it */
1143 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1144 entry->key = method;
1145 entry->value.vtable_slot = vtable_slot;
1146 entry->next = imt_builder [imt_slot];
1147 if (imt_builder [imt_slot] != NULL) {
1148 entry->children = imt_builder [imt_slot]->children + 1;
1149 if (entry->children == 1) {
1150 mono_stats.imt_slots_with_collisions++;
1151 *imt_collisions_bitmap |= (1 << imt_slot);
1154 entry->children = 0;
1155 mono_stats.imt_used_slots++;
1157 imt_builder [imt_slot] = entry;
1160 char *method_name = mono_method_full_name (method, TRUE);
1161 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1162 method, method_name, imt_slot, vtable_slot, entry->children);
1163 g_free (method_name);
1170 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1172 MonoMethod *method = e->key;
1173 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1177 method->klass->name_space,
1178 method->klass->name,
1181 printf (" * %s: NULL\n", message);
1187 compare_imt_builder_entries (const void *p1, const void *p2) {
1188 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1189 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1191 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1195 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1197 int count = end - start;
1198 int chunk_start = out_array->len;
1201 for (i = start; i < end; ++i) {
1202 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1203 item->key = sorted_array [i]->key;
1204 item->value = sorted_array [i]->value;
1205 item->has_target_code = sorted_array [i]->has_target_code;
1206 item->is_equals = TRUE;
1208 item->check_target_idx = out_array->len + 1;
1210 item->check_target_idx = 0;
1211 g_ptr_array_add (out_array, item);
1214 int middle = start + count / 2;
1215 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1217 item->key = sorted_array [middle]->key;
1218 item->is_equals = FALSE;
1219 g_ptr_array_add (out_array, item);
1220 imt_emit_ir (sorted_array, start, middle, out_array);
1221 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1227 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1228 int number_of_entries = entries->children + 1;
1229 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1230 GPtrArray *result = g_ptr_array_new ();
1231 MonoImtBuilderEntry *current_entry;
1234 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1235 sorted_array [i] = current_entry;
1237 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1239 /*for (i = 0; i < number_of_entries; i++) {
1240 print_imt_entry (" sorted array:", sorted_array [i], i);
1243 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1245 free (sorted_array);
1250 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1252 if (imt_builder_entry != NULL) {
1253 if (imt_builder_entry->children == 0 && !fail_tramp) {
1254 /* No collision, return the vtable slot contents */
1255 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1257 /* Collision, build the thunk */
1258 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1261 result = imt_thunk_builder (vtable, domain,
1262 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1263 for (i = 0; i < imt_ir->len; ++i)
1264 g_free (g_ptr_array_index (imt_ir, i));
1265 g_ptr_array_free (imt_ir, TRUE);
1277 static MonoImtBuilderEntry*
1278 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1281 * LOCKING: requires the loader and domain locks.
1285 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1289 guint32 imt_collisions_bitmap = 0;
1290 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1291 int method_count = 0;
1292 gboolean record_method_count_for_max_collisions = FALSE;
1293 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1296 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1298 for (i = 0; i < klass->interface_offsets_count; ++i) {
1299 MonoClass *iface = klass->interfaces_packed [i];
1300 int interface_offset = klass->interface_offsets_packed [i];
1301 int method_slot_in_interface, vt_slot;
1303 if (mono_class_has_variant_generic_params (iface))
1304 has_variant_iface = TRUE;
1306 vt_slot = interface_offset;
1307 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1310 if (slot_num >= 0 && iface->is_inflated) {
1312 * The imt slot of the method is the same as for its declaring method,
1313 * see the comment in mono_method_get_imt_slot (), so we can
1314 * avoid inflating methods which will be discarded by
1315 * add_imt_builder_entry anyway.
1317 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1318 if (mono_method_get_imt_slot (method) != slot_num) {
1323 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1324 if (method->is_generic) {
1325 has_generic_virtual = TRUE;
1330 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1331 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1336 if (extra_interfaces) {
1337 int interface_offset = klass->vtable_size;
1339 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1340 MonoClass* iface = list_item->data;
1341 int method_slot_in_interface;
1342 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1343 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1344 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1346 interface_offset += iface->method.count;
1349 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1350 /* overwrite the imt slot only if we're building all the entries or if
1351 * we're building this specific one
1353 if (slot_num < 0 || i == slot_num) {
1354 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1357 if (imt_builder [i]) {
1358 MonoImtBuilderEntry *entry;
1360 /* Link entries with imt_builder [i] */
1361 for (entry = entries; entry->next; entry = entry->next) {
1363 MonoMethod *method = (MonoMethod*)entry->key;
1364 char *method_name = mono_method_full_name (method, TRUE);
1365 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1366 g_free (method_name);
1369 entry->next = imt_builder [i];
1370 entries->children += imt_builder [i]->children + 1;
1372 imt_builder [i] = entries;
1375 if (has_generic_virtual || has_variant_iface) {
1377 * There might be collisions later when the the thunk is expanded.
1379 imt_collisions_bitmap |= (1 << i);
1382 * The IMT thunk might be called with an instance of one of the
1383 * generic virtual methods, so has to fallback to the IMT trampoline.
1385 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1387 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1390 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1394 if (imt_builder [i] != NULL) {
1395 int methods_in_slot = imt_builder [i]->children + 1;
1396 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1397 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1398 record_method_count_for_max_collisions = TRUE;
1400 method_count += methods_in_slot;
1404 mono_stats.imt_number_of_methods += method_count;
1405 if (record_method_count_for_max_collisions) {
1406 mono_stats.imt_method_count_when_max_collisions = method_count;
1409 for (i = 0; i < MONO_IMT_SIZE; i++) {
1410 MonoImtBuilderEntry* entry = imt_builder [i];
1411 while (entry != NULL) {
1412 MonoImtBuilderEntry* next = entry->next;
1418 /* we OR the bitmap since we may build just a single imt slot at a time */
1419 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1423 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1424 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1428 * mono_vtable_build_imt_slot:
1429 * @vtable: virtual object table struct
1430 * @imt_slot: slot in the IMT table
1432 * Fill the given @imt_slot in the IMT table of @vtable with
1433 * a trampoline or a thunk for the case of collisions.
1434 * This is part of the internal mono API.
1436 * LOCKING: Take the domain lock.
1439 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1441 gpointer *imt = (gpointer*)vtable;
1442 imt -= MONO_IMT_SIZE;
1443 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1445 /* no support for extra interfaces: the proxy objects will need
1446 * to build the complete IMT
1447 * Update and heck needs to ahppen inside the proper domain lock, as all
1448 * the changes made to a MonoVTable.
1450 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1451 mono_domain_lock (vtable->domain);
1452 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1453 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1454 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1455 mono_domain_unlock (vtable->domain);
1456 mono_loader_unlock ();
1461 * The first two free list entries both belong to the wait list: The
1462 * first entry is the pointer to the head of the list and the second
1463 * entry points to the last element. That way appending and removing
1464 * the first element are both O(1) operations.
1466 #ifdef MONO_SMALL_CONFIG
1467 #define NUM_FREE_LISTS 6
1469 #define NUM_FREE_LISTS 12
1471 #define FIRST_FREE_LIST_SIZE 64
1472 #define MAX_WAIT_LENGTH 50
1473 #define THUNK_THRESHOLD 10
1476 * LOCKING: The domain lock must be held.
1479 init_thunk_free_lists (MonoDomain *domain)
1481 if (domain->thunk_free_lists)
1483 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1487 list_index_for_size (int item_size)
1490 int size = FIRST_FREE_LIST_SIZE;
1492 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1501 * mono_method_alloc_generic_virtual_thunk:
1503 * @size: size in bytes
1505 * Allocs size bytes to be used for the code of a generic virtual
1506 * thunk. It's either allocated from the domain's code manager or
1507 * reused from a previously invalidated piece.
1509 * LOCKING: The domain lock must be held.
1512 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1514 static gboolean inited = FALSE;
1515 static int generic_virtual_thunks_size = 0;
1519 MonoThunkFreeList **l;
1521 init_thunk_free_lists (domain);
1523 size += sizeof (guint32);
1524 if (size < sizeof (MonoThunkFreeList))
1525 size = sizeof (MonoThunkFreeList);
1527 i = list_index_for_size (size);
1528 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1529 if ((*l)->size >= size) {
1530 MonoThunkFreeList *item = *l;
1532 return ((guint32*)item) + 1;
1536 /* no suitable item found - search lists of larger sizes */
1537 while (++i < NUM_FREE_LISTS) {
1538 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1541 g_assert (item->size > size);
1542 domain->thunk_free_lists [i] = item->next;
1543 return ((guint32*)item) + 1;
1546 /* still nothing found - allocate it */
1548 mono_counters_register ("Generic virtual thunk bytes",
1549 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1552 generic_virtual_thunks_size += size;
1554 p = mono_domain_code_reserve (domain, size);
1557 mono_domain_lock (domain);
1558 if (!domain->generic_virtual_thunks)
1559 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1560 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1561 mono_domain_unlock (domain);
1567 * LOCKING: The domain lock must be held.
1570 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1573 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1574 gboolean found = FALSE;
1576 mono_domain_lock (domain);
1577 if (!domain->generic_virtual_thunks)
1578 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1579 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1581 mono_domain_unlock (domain);
1584 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1586 init_thunk_free_lists (domain);
1588 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1589 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1590 int length = item->length;
1593 /* unlink the first item from the wait list */
1594 domain->thunk_free_lists [0] = item->next;
1595 domain->thunk_free_lists [0]->length = length - 1;
1597 i = list_index_for_size (item->size);
1599 /* put it in the free list */
1600 item->next = domain->thunk_free_lists [i];
1601 domain->thunk_free_lists [i] = item;
1605 if (domain->thunk_free_lists [1]) {
1606 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1607 domain->thunk_free_lists [0]->length++;
1609 g_assert (!domain->thunk_free_lists [0]);
1611 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1612 domain->thunk_free_lists [0]->length = 1;
1616 typedef struct _GenericVirtualCase {
1620 struct _GenericVirtualCase *next;
1621 } GenericVirtualCase;
1624 * get_generic_virtual_entries:
1626 * Return IMT entries for the generic virtual method instances and
1627 * variant interface methods for vtable slot
1630 static MonoImtBuilderEntry*
1631 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1633 GenericVirtualCase *list;
1634 MonoImtBuilderEntry *entries;
1636 mono_domain_lock (domain);
1637 if (!domain->generic_virtual_cases)
1638 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1640 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1643 for (; list; list = list->next) {
1644 MonoImtBuilderEntry *entry;
1646 if (list->count < THUNK_THRESHOLD)
1649 entry = g_new0 (MonoImtBuilderEntry, 1);
1650 entry->key = list->method;
1651 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1652 entry->has_target_code = 1;
1654 entry->children = entries->children + 1;
1655 entry->next = entries;
1659 mono_domain_unlock (domain);
1661 /* FIXME: Leaking memory ? */
1666 * mono_method_add_generic_virtual_invocation:
1668 * @vtable_slot: pointer to the vtable slot
1669 * @method: the inflated generic virtual method
1670 * @code: the method's code
1672 * Registers a call via unmanaged code to a generic virtual method
1673 * instantiation or variant interface method. If the number of calls reaches a threshold
1674 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1675 * virtual method thunk.
1678 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1679 gpointer *vtable_slot,
1680 MonoMethod *method, gpointer code)
1682 static gboolean inited = FALSE;
1683 static int num_added = 0;
1685 GenericVirtualCase *gvc, *list;
1686 MonoImtBuilderEntry *entries;
1690 mono_domain_lock (domain);
1691 if (!domain->generic_virtual_cases)
1692 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1694 /* Check whether the case was already added */
1695 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1698 if (gvc->method == method)
1703 /* If not found, make a new one */
1705 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1706 gvc->method = method;
1709 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1711 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1714 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1720 if (++gvc->count == THUNK_THRESHOLD) {
1721 gpointer *old_thunk = *vtable_slot;
1722 gpointer vtable_trampoline = NULL;
1723 gpointer imt_trampoline = NULL;
1725 if ((gpointer)vtable_slot < (gpointer)vtable) {
1726 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1727 int imt_slot = MONO_IMT_SIZE + displacement;
1729 /* Force the rebuild of the thunk at the next call */
1730 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1731 *vtable_slot = imt_trampoline;
1733 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1735 entries = get_generic_virtual_entries (domain, vtable_slot);
1737 sorted = imt_sort_slot_entries (entries);
1739 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1743 MonoImtBuilderEntry *next = entries->next;
1748 for (i = 0; i < sorted->len; ++i)
1749 g_free (g_ptr_array_index (sorted, i));
1750 g_ptr_array_free (sorted, TRUE);
1753 #ifndef __native_client__
1754 /* We don't re-use any thunks as there is a lot of overhead */
1755 /* to deleting and re-using code in Native Client. */
1756 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1757 invalidate_generic_virtual_thunk (domain, old_thunk);
1761 mono_domain_unlock (domain);
1764 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1767 * mono_class_vtable:
1768 * @domain: the application domain
1769 * @class: the class to initialize
1771 * VTables are domain specific because we create domain specific code, and
1772 * they contain the domain specific static class data.
1773 * On failure, NULL is returned, and class->exception_type is set.
1776 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1778 return mono_class_vtable_full (domain, class, FALSE);
1782 * mono_class_vtable_full:
1783 * @domain: the application domain
1784 * @class: the class to initialize
1785 * @raise_on_error if an exception should be raised on failure or not
1787 * VTables are domain specific because we create domain specific code, and
1788 * they contain the domain specific static class data.
1791 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1793 MonoClassRuntimeInfo *runtime_info;
1797 if (class->exception_type) {
1799 mono_raise_exception (mono_class_get_exception_for_failure (class));
1803 /* this check can be inlined in jitted code, too */
1804 runtime_info = class->runtime_info;
1805 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1806 return runtime_info->domain_vtables [domain->domain_id];
1807 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1811 * mono_class_try_get_vtable:
1812 * @domain: the application domain
1813 * @class: the class to initialize
1815 * This function tries to get the associated vtable from @class if
1816 * it was already created.
1819 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1821 MonoClassRuntimeInfo *runtime_info;
1825 runtime_info = class->runtime_info;
1826 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1827 return runtime_info->domain_vtables [domain->domain_id];
1832 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1835 MonoClassRuntimeInfo *runtime_info, *old_info;
1836 MonoClassField *field;
1838 int i, vtable_slots;
1839 int imt_table_bytes = 0;
1841 guint32 vtable_size, class_size;
1844 gpointer *interface_offsets;
1846 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1847 mono_domain_lock (domain);
1848 runtime_info = class->runtime_info;
1849 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1850 mono_domain_unlock (domain);
1851 mono_loader_unlock ();
1852 return runtime_info->domain_vtables [domain->domain_id];
1854 if (!class->inited || class->exception_type) {
1855 if (!mono_class_init (class) || class->exception_type) {
1856 mono_domain_unlock (domain);
1857 mono_loader_unlock ();
1859 mono_raise_exception (mono_class_get_exception_for_failure (class));
1864 /* Array types require that their element type be valid*/
1865 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1866 MonoClass *element_class = class->element_class;
1867 if (!element_class->inited)
1868 mono_class_init (element_class);
1870 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1871 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1872 mono_class_setup_vtable (element_class);
1874 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1875 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1876 if (class->exception_type == MONO_EXCEPTION_NONE)
1877 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1878 mono_domain_unlock (domain);
1879 mono_loader_unlock ();
1881 mono_raise_exception (mono_class_get_exception_for_failure (class));
1887 * For some classes, mono_class_init () already computed class->vtable_size, and
1888 * that is all that is needed because of the vtable trampolines.
1890 if (!class->vtable_size)
1891 mono_class_setup_vtable (class);
1893 if (class->generic_class && !class->vtable)
1894 mono_class_check_vtable_constraints (class, NULL);
1896 /* Initialize klass->has_finalize */
1897 mono_class_has_finalizer (class);
1899 if (class->exception_type) {
1900 mono_domain_unlock (domain);
1901 mono_loader_unlock ();
1903 mono_raise_exception (mono_class_get_exception_for_failure (class));
1907 vtable_slots = class->vtable_size;
1908 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1909 class_size = mono_class_data_size (class);
1914 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1915 if (class->interface_offsets_count) {
1916 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1917 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1918 mono_stats.imt_number_of_tables++;
1919 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1922 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1923 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1926 mono_stats.used_class_count++;
1927 mono_stats.class_vtable_size += vtable_size;
1928 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1931 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1933 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1935 vt->rank = class->rank;
1936 vt->domain = domain;
1938 mono_class_compute_gc_descriptor (class);
1940 * We can't use typed allocation in the non-root domains, since the
1941 * collector needs the GC descriptor stored in the vtable even after
1942 * the mempool containing the vtable is destroyed when the domain is
1943 * unloaded. An alternative might be to allocate vtables in the GC
1944 * heap, but this does not seem to work (it leads to crashes inside
1945 * libgc). If that approach is tried, two gc descriptors need to be
1946 * allocated for each class: one for the root domain, and one for all
1947 * other domains. The second descriptor should contain a bit for the
1948 * vtable field in MonoObject, since we can no longer assume the
1949 * vtable is reachable by other roots after the appdomain is unloaded.
1951 #ifdef HAVE_BOEHM_GC
1952 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1953 vt->gc_descr = GC_NO_DESCRIPTOR;
1956 vt->gc_descr = class->gc_descr;
1958 gc_bits = mono_gc_get_vtable_bits (class);
1959 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1961 vt->gc_bits = gc_bits;
1964 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1965 if (class->has_static_refs) {
1966 gpointer statics_gc_descr;
1968 gsize default_bitmap [4] = {0};
1971 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1972 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1973 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1974 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1975 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1976 if (bitmap != default_bitmap)
1979 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1981 vt->has_static_fields = TRUE;
1982 mono_stats.class_static_data_size += class_size;
1987 while ((field = mono_class_get_fields (class, &iter))) {
1988 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1990 if (mono_field_is_deleted (field))
1992 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1993 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1994 if (special_static != SPECIAL_STATIC_NONE) {
1995 guint32 size, offset;
1997 gsize default_bitmap [4] = {0};
2001 if (mono_type_is_reference (field->type)) {
2002 default_bitmap [0] = 1;
2004 bitmap = default_bitmap;
2005 } else if (mono_type_is_struct (field->type)) {
2006 fclass = mono_class_from_mono_type (field->type);
2007 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2009 default_bitmap [0] = 0;
2011 bitmap = default_bitmap;
2013 size = mono_type_size (field->type, &align);
2014 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2015 if (!domain->special_static_fields)
2016 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2017 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2018 if (bitmap != default_bitmap)
2021 * This marks the field as special static to speed up the
2022 * checks in mono_field_static_get/set_value ().
2028 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2029 MonoClass *fklass = mono_class_from_mono_type (field->type);
2030 const char *data = mono_field_get_data (field);
2032 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2033 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2034 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2037 if (fklass->valuetype) {
2038 memcpy (t, data, mono_class_value_size (fklass, NULL));
2040 /* it's a pointer type: add check */
2041 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2048 vt->max_interface_id = class->max_interface_id;
2049 vt->interface_bitmap = class->interface_bitmap;
2051 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2052 // class->name, class->interface_offsets_count);
2054 if (! ARCH_USE_IMT) {
2055 /* initialize interface offsets */
2056 for (i = 0; i < class->interface_offsets_count; ++i) {
2057 int interface_id = class->interfaces_packed [i]->interface_id;
2058 int slot = class->interface_offsets_packed [i];
2059 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2063 /* Initialize vtable */
2064 if (callbacks.get_vtable_trampoline) {
2065 // This also covers the AOT case
2066 for (i = 0; i < class->vtable_size; ++i) {
2067 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2070 mono_class_setup_vtable (class);
2072 for (i = 0; i < class->vtable_size; ++i) {
2075 if ((cm = class->vtable [i]))
2076 vt->vtable [i] = arch_create_jit_trampoline (cm);
2080 if (ARCH_USE_IMT && imt_table_bytes) {
2081 /* Now that the vtable is full, we can actually fill up the IMT */
2082 if (callbacks.get_imt_trampoline) {
2083 /* lazy construction of the IMT entries enabled */
2084 for (i = 0; i < MONO_IMT_SIZE; ++i)
2085 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2087 build_imt (class, vt, domain, interface_offsets, NULL);
2092 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2093 * re-acquire them and check if another thread has created the vtable in the meantime.
2095 /* Special case System.MonoType to avoid infinite recursion */
2096 if (class != mono_defaults.monotype_class) {
2097 /*FIXME check for OOM*/
2098 vt->type = mono_type_get_object (domain, &class->byval_arg);
2099 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2100 /* This is unregistered in
2101 unregister_vtable_reflection_type() in
2103 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2106 if (class->contextbound)
2111 /* class_vtable_array keeps an array of created vtables
2113 g_ptr_array_add (domain->class_vtable_array, vt);
2114 /* class->runtime_info is protected by the loader lock, both when
2115 * it it enlarged and when it is stored info.
2119 * Store the vtable in class->runtime_info.
2120 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2122 mono_memory_barrier ();
2124 old_info = class->runtime_info;
2125 if (old_info && old_info->max_domain >= domain->domain_id) {
2126 /* someone already created a large enough runtime info */
2127 old_info->domain_vtables [domain->domain_id] = vt;
2129 int new_size = domain->domain_id;
2131 new_size = MAX (new_size, old_info->max_domain);
2133 /* make the new size a power of two */
2135 while (new_size > i)
2138 /* this is a bounded memory retention issue: may want to
2139 * handle it differently when we'll have a rcu-like system.
2141 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2142 runtime_info->max_domain = new_size - 1;
2143 /* copy the stuff from the older info */
2145 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2147 runtime_info->domain_vtables [domain->domain_id] = vt;
2149 mono_memory_barrier ();
2150 class->runtime_info = runtime_info;
2153 if (class == mono_defaults.monotype_class) {
2154 /*FIXME check for OOM*/
2155 vt->type = mono_type_get_object (domain, &class->byval_arg);
2156 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2157 /* This is unregistered in
2158 unregister_vtable_reflection_type() in
2160 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2163 mono_domain_unlock (domain);
2164 mono_loader_unlock ();
2166 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2167 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2168 mono_raise_exception (mono_class_get_exception_for_failure (class));
2170 /* make sure the parent is initialized */
2171 /*FIXME shouldn't this fail the current type?*/
2173 mono_class_vtable_full (domain, class->parent, raise_on_error);
2179 * mono_class_proxy_vtable:
2180 * @domain: the application domain
2181 * @remove_class: the remote class
2183 * Creates a vtable for transparent proxies. It is basically
2184 * a copy of the real vtable of the class wrapped in @remote_class,
2185 * but all function pointers invoke the remoting functions, and
2186 * vtable->klass points to the transparent proxy class, and not to @class.
2189 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2192 MonoVTable *vt, *pvt;
2193 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2195 GSList *extra_interfaces = NULL;
2196 MonoClass *class = remote_class->proxy_class;
2197 gpointer *interface_offsets;
2201 #ifdef COMPRESSED_INTERFACE_BITMAP
2205 vt = mono_class_vtable (domain, class);
2206 g_assert (vt); /*FIXME property handle failure*/
2207 max_interface_id = vt->max_interface_id;
2209 /* Calculate vtable space for extra interfaces */
2210 for (j = 0; j < remote_class->interface_count; j++) {
2211 MonoClass* iclass = remote_class->interfaces[j];
2215 /*FIXME test for interfaces with variant generic arguments*/
2216 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2217 continue; /* interface implemented by the class */
2218 if (g_slist_find (extra_interfaces, iclass))
2221 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2223 method_count = mono_class_num_methods (iclass);
2225 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2226 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2228 for (i = 0; i < ifaces->len; ++i) {
2229 MonoClass *ic = g_ptr_array_index (ifaces, i);
2230 /*FIXME test for interfaces with variant generic arguments*/
2231 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2232 continue; /* interface implemented by the class */
2233 if (g_slist_find (extra_interfaces, ic))
2235 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2236 method_count += mono_class_num_methods (ic);
2238 g_ptr_array_free (ifaces, TRUE);
2241 extra_interface_vtsize += method_count * sizeof (gpointer);
2242 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2246 mono_stats.imt_number_of_tables++;
2247 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2248 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2249 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2251 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2252 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2255 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2257 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2259 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2261 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2262 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2264 pvt->klass = mono_defaults.transparent_proxy_class;
2265 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2266 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2268 /* initialize vtable */
2269 mono_class_setup_vtable (class);
2270 for (i = 0; i < class->vtable_size; ++i) {
2273 if ((cm = class->vtable [i]))
2274 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2276 pvt->vtable [i] = NULL;
2279 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2280 /* create trampolines for abstract methods */
2281 for (k = class; k; k = k->parent) {
2283 gpointer iter = NULL;
2284 while ((m = mono_class_get_methods (k, &iter)))
2285 if (!pvt->vtable [m->slot])
2286 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2290 pvt->max_interface_id = max_interface_id;
2291 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2292 #ifdef COMPRESSED_INTERFACE_BITMAP
2293 bitmap = g_malloc0 (bsize);
2295 bitmap = mono_domain_alloc0 (domain, bsize);
2298 if (! ARCH_USE_IMT) {
2299 /* initialize interface offsets */
2300 for (i = 0; i < class->interface_offsets_count; ++i) {
2301 int interface_id = class->interfaces_packed [i]->interface_id;
2302 int slot = class->interface_offsets_packed [i];
2303 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2306 for (i = 0; i < class->interface_offsets_count; ++i) {
2307 int interface_id = class->interfaces_packed [i]->interface_id;
2308 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2311 if (extra_interfaces) {
2312 int slot = class->vtable_size;
2318 /* Create trampolines for the methods of the interfaces */
2319 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2320 interf = list_item->data;
2322 if (! ARCH_USE_IMT) {
2323 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2325 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2329 while ((cm = mono_class_get_methods (interf, &iter)))
2330 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2332 slot += mono_class_num_methods (interf);
2334 if (! ARCH_USE_IMT) {
2335 g_slist_free (extra_interfaces);
2340 /* Now that the vtable is full, we can actually fill up the IMT */
2341 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2342 if (extra_interfaces) {
2343 g_slist_free (extra_interfaces);
2347 #ifdef COMPRESSED_INTERFACE_BITMAP
2348 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2349 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2350 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2353 pvt->interface_bitmap = bitmap;
2359 * mono_class_field_is_special_static:
2361 * Returns whether @field is a thread/context static field.
2364 mono_class_field_is_special_static (MonoClassField *field)
2366 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2368 if (mono_field_is_deleted (field))
2370 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2371 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2378 * mono_class_field_get_special_static_type:
2379 * @field: The MonoClassField describing the field.
2381 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2382 * SPECIAL_STATIC_NONE otherwise.
2385 mono_class_field_get_special_static_type (MonoClassField *field)
2387 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2388 return SPECIAL_STATIC_NONE;
2389 if (mono_field_is_deleted (field))
2390 return SPECIAL_STATIC_NONE;
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2392 return field_is_special_static (field->parent, field);
2393 return SPECIAL_STATIC_NONE;
2397 * mono_class_has_special_static_fields:
2399 * Returns whenever @klass has any thread/context static fields.
2402 mono_class_has_special_static_fields (MonoClass *klass)
2404 MonoClassField *field;
2408 while ((field = mono_class_get_fields (klass, &iter))) {
2409 g_assert (field->parent == klass);
2410 if (mono_class_field_is_special_static (field))
2418 * create_remote_class_key:
2419 * Creates an array of pointers that can be used as a hash key for a remote class.
2420 * The first element of the array is the number of pointers.
2423 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2428 if (remote_class == NULL) {
2429 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2430 key = g_malloc (sizeof(gpointer) * 3);
2431 key [0] = GINT_TO_POINTER (2);
2432 key [1] = mono_defaults.marshalbyrefobject_class;
2433 key [2] = extra_class;
2435 key = g_malloc (sizeof(gpointer) * 2);
2436 key [0] = GINT_TO_POINTER (1);
2437 key [1] = extra_class;
2440 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2441 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2442 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2443 key [1] = remote_class->proxy_class;
2445 // Keep the list of interfaces sorted
2446 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2447 if (extra_class && remote_class->interfaces [i] > extra_class) {
2448 key [j++] = extra_class;
2451 key [j] = remote_class->interfaces [i];
2454 key [j] = extra_class;
2456 // Replace the old class. The interface list is the same
2457 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2458 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2459 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2460 for (i = 0; i < remote_class->interface_count; i++)
2461 key [2 + i] = remote_class->interfaces [i];
2469 * copy_remote_class_key:
2471 * Make a copy of KEY in the domain and return the copy.
2474 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2476 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2477 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2479 memcpy (mp_key, key, key_size);
2485 * mono_remote_class:
2486 * @domain: the application domain
2487 * @class_name: name of the remote class
2489 * Creates and initializes a MonoRemoteClass object for a remote type.
2491 * Can raise an exception on failure.
2494 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2497 MonoRemoteClass *rc;
2498 gpointer* key, *mp_key;
2501 key = create_remote_class_key (NULL, proxy_class);
2503 mono_domain_lock (domain);
2504 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2508 mono_domain_unlock (domain);
2512 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2513 if (!mono_error_ok (&error)) {
2515 mono_domain_unlock (domain);
2516 mono_error_raise_exception (&error);
2519 mp_key = copy_remote_class_key (domain, key);
2523 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2524 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2525 rc->interface_count = 1;
2526 rc->interfaces [0] = proxy_class;
2527 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2529 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2530 rc->interface_count = 0;
2531 rc->proxy_class = proxy_class;
2534 rc->default_vtable = NULL;
2535 rc->xdomain_vtable = NULL;
2536 rc->proxy_class_name = name;
2537 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2539 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2541 mono_domain_unlock (domain);
2546 * clone_remote_class:
2547 * Creates a copy of the remote_class, adding the provided class or interface
2549 static MonoRemoteClass*
2550 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2552 MonoRemoteClass *rc;
2553 gpointer* key, *mp_key;
2555 key = create_remote_class_key (remote_class, extra_class);
2556 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2562 mp_key = copy_remote_class_key (domain, key);
2566 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2568 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2569 rc->proxy_class = remote_class->proxy_class;
2570 rc->interface_count = remote_class->interface_count + 1;
2572 // Keep the list of interfaces sorted, since the hash key of
2573 // the remote class depends on this
2574 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2575 if (remote_class->interfaces [i] > extra_class && i == j)
2576 rc->interfaces [j++] = extra_class;
2577 rc->interfaces [j] = remote_class->interfaces [i];
2580 rc->interfaces [j] = extra_class;
2582 // Replace the old class. The interface array is the same
2583 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2584 rc->proxy_class = extra_class;
2585 rc->interface_count = remote_class->interface_count;
2586 if (rc->interface_count > 0)
2587 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2590 rc->default_vtable = NULL;
2591 rc->xdomain_vtable = NULL;
2592 rc->proxy_class_name = remote_class->proxy_class_name;
2594 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2600 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2602 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2603 mono_domain_lock (domain);
2604 if (rp->target_domain_id != -1) {
2605 if (remote_class->xdomain_vtable == NULL)
2606 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2607 mono_domain_unlock (domain);
2608 mono_loader_unlock ();
2609 return remote_class->xdomain_vtable;
2611 if (remote_class->default_vtable == NULL) {
2614 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2615 klass = mono_class_from_mono_type (type);
2616 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2617 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2619 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2622 mono_domain_unlock (domain);
2623 mono_loader_unlock ();
2624 return remote_class->default_vtable;
2628 * mono_upgrade_remote_class:
2629 * @domain: the application domain
2630 * @tproxy: the proxy whose remote class has to be upgraded.
2631 * @klass: class to which the remote class can be casted.
2633 * Updates the vtable of the remote class by adding the necessary method slots
2634 * and interface offsets so it can be safely casted to klass. klass can be a
2635 * class or an interface.
2638 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2640 MonoTransparentProxy *tproxy;
2641 MonoRemoteClass *remote_class;
2642 gboolean redo_vtable;
2644 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2645 mono_domain_lock (domain);
2647 tproxy = (MonoTransparentProxy*) proxy_object;
2648 remote_class = tproxy->remote_class;
2650 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2653 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2654 if (remote_class->interfaces [i] == klass)
2655 redo_vtable = FALSE;
2658 redo_vtable = (remote_class->proxy_class != klass);
2662 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2663 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2666 mono_domain_unlock (domain);
2667 mono_loader_unlock ();
2672 * mono_object_get_virtual_method:
2673 * @obj: object to operate on.
2676 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2677 * the instance of a callvirt of method.
2680 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2683 MonoMethod **vtable;
2685 MonoMethod *res = NULL;
2687 klass = mono_object_class (obj);
2688 if (klass == mono_defaults.transparent_proxy_class) {
2689 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2695 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2698 mono_class_setup_vtable (klass);
2699 vtable = klass->vtable;
2701 if (method->slot == -1) {
2702 /* method->slot might not be set for instances of generic methods */
2703 if (method->is_inflated) {
2704 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2705 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2708 g_assert_not_reached ();
2712 /* check method->slot is a valid index: perform isinstance? */
2713 if (method->slot != -1) {
2714 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2716 gboolean variance_used = FALSE;
2717 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2718 g_assert (iface_offset > 0);
2719 res = vtable [iface_offset + method->slot];
2722 res = vtable [method->slot];
2727 /* It may be an interface, abstract class method or generic method */
2728 if (!res || mono_method_signature (res)->generic_param_count)
2731 /* generic methods demand invoke_with_check */
2732 if (mono_method_signature (res)->generic_param_count)
2733 res = mono_marshal_get_remoting_invoke_with_check (res);
2736 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2737 res = mono_cominterop_get_invoke (res);
2740 res = mono_marshal_get_remoting_invoke (res);
2743 if (method->is_inflated) {
2744 /* Have to inflate the result */
2745 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2755 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2757 g_error ("runtime invoke called on uninitialized runtime");
2761 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2764 * mono_runtime_invoke:
2765 * @method: method to invoke
2766 * @obJ: object instance
2767 * @params: arguments to the method
2768 * @exc: exception information.
2770 * Invokes the method represented by @method on the object @obj.
2772 * obj is the 'this' pointer, it should be NULL for static
2773 * methods, a MonoObject* for object instances and a pointer to
2774 * the value type for value types.
2776 * The params array contains the arguments to the method with the
2777 * same convention: MonoObject* pointers for object instances and
2778 * pointers to the value type otherwise.
2780 * From unmanaged code you'll usually use the
2781 * mono_runtime_invoke() variant.
2783 * Note that this function doesn't handle virtual methods for
2784 * you, it will exec the exact method you pass: we still need to
2785 * expose a function to lookup the derived class implementation
2786 * of a virtual method (there are examples of this in the code,
2789 * You can pass NULL as the exc argument if you don't want to
2790 * catch exceptions, otherwise, *exc will be set to the exception
2791 * thrown, if any. if an exception is thrown, you can't use the
2792 * MonoObject* result from the function.
2794 * If the method returns a value type, it is boxed in an object
2798 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2802 if (mono_runtime_get_no_exec ())
2803 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2805 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2806 mono_profiler_method_start_invoke (method);
2808 result = default_mono_runtime_invoke (method, obj, params, exc);
2810 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2811 mono_profiler_method_end_invoke (method);
2817 * mono_method_get_unmanaged_thunk:
2818 * @method: method to generate a thunk for.
2820 * Returns an unmanaged->managed thunk that can be used to call
2821 * a managed method directly from C.
2823 * The thunk's C signature closely matches the managed signature:
2825 * C#: public bool Equals (object obj);
2826 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2827 * MonoObject*, MonoException**);
2829 * The 1st ("this") parameter must not be used with static methods:
2831 * C#: public static bool ReferenceEquals (object a, object b);
2832 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2835 * The last argument must be a non-null pointer of a MonoException* pointer.
2836 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2837 * exception has been thrown in managed code. Otherwise it will point
2838 * to the MonoException* caught by the thunk. In this case, the result of
2839 * the thunk is undefined:
2841 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2842 * MonoException *ex = NULL;
2843 * Equals func = mono_method_get_unmanaged_thunk (method);
2844 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2846 * // handle exception
2849 * The calling convention of the thunk matches the platform's default
2850 * convention. This means that under Windows, C declarations must
2851 * contain the __stdcall attribute:
2853 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2854 * MonoObject*, MonoException**);
2858 * Value type arguments and return values are treated as they were objects:
2860 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2861 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2863 * Arguments must be properly boxed upon trunk's invocation, while return
2864 * values must be unboxed.
2867 mono_method_get_unmanaged_thunk (MonoMethod *method)
2869 method = mono_marshal_get_thunk_invoke_wrapper (method);
2870 return mono_compile_method (method);
2874 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2878 /* object fields cannot be byref, so we don't need a
2880 gpointer *p = (gpointer*)dest;
2887 case MONO_TYPE_BOOLEAN:
2889 case MONO_TYPE_U1: {
2890 guint8 *p = (guint8*)dest;
2891 *p = value ? *(guint8*)value : 0;
2896 case MONO_TYPE_CHAR: {
2897 guint16 *p = (guint16*)dest;
2898 *p = value ? *(guint16*)value : 0;
2901 #if SIZEOF_VOID_P == 4
2906 case MONO_TYPE_U4: {
2907 gint32 *p = (gint32*)dest;
2908 *p = value ? *(gint32*)value : 0;
2911 #if SIZEOF_VOID_P == 8
2916 case MONO_TYPE_U8: {
2917 gint64 *p = (gint64*)dest;
2918 *p = value ? *(gint64*)value : 0;
2921 case MONO_TYPE_R4: {
2922 float *p = (float*)dest;
2923 *p = value ? *(float*)value : 0;
2926 case MONO_TYPE_R8: {
2927 double *p = (double*)dest;
2928 *p = value ? *(double*)value : 0;
2931 case MONO_TYPE_STRING:
2932 case MONO_TYPE_SZARRAY:
2933 case MONO_TYPE_CLASS:
2934 case MONO_TYPE_OBJECT:
2935 case MONO_TYPE_ARRAY:
2936 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2938 case MONO_TYPE_FNPTR:
2939 case MONO_TYPE_PTR: {
2940 gpointer *p = (gpointer*)dest;
2941 *p = deref_pointer? *(gpointer*)value: value;
2944 case MONO_TYPE_VALUETYPE:
2945 /* note that 't' and 'type->type' can be different */
2946 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2947 t = mono_class_enum_basetype (type->data.klass)->type;
2950 MonoClass *class = mono_class_from_mono_type (type);
2951 int size = mono_class_value_size (class, NULL);
2953 mono_gc_bzero (dest, size);
2955 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2958 case MONO_TYPE_GENERICINST:
2959 t = type->data.generic_class->container_class->byval_arg.type;
2962 g_warning ("got type %x", type->type);
2963 g_assert_not_reached ();
2968 * mono_field_set_value:
2969 * @obj: Instance object
2970 * @field: MonoClassField describing the field to set
2971 * @value: The value to be set
2973 * Sets the value of the field described by @field in the object instance @obj
2974 * to the value passed in @value. This method should only be used for instance
2975 * fields. For static fields, use mono_field_static_set_value.
2977 * The value must be on the native format of the field type.
2980 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2984 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2986 dest = (char*)obj + field->offset;
2987 set_value (field->type, dest, value, FALSE);
2991 * mono_field_static_set_value:
2992 * @field: MonoClassField describing the field to set
2993 * @value: The value to be set
2995 * Sets the value of the static field described by @field
2996 * to the value passed in @value.
2998 * The value must be on the native format of the field type.
3001 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3005 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3006 /* you cant set a constant! */
3007 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3009 if (field->offset == -1) {
3010 /* Special static */
3013 mono_domain_lock (vt->domain);
3014 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3015 mono_domain_unlock (vt->domain);
3016 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3018 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3020 set_value (field->type, dest, value, FALSE);
3024 * mono_vtable_get_static_field_data:
3026 * Internal use function: return a pointer to the memory holding the static fields
3027 * for a class or NULL if there are no static fields.
3028 * This is exported only for use by the debugger.
3031 mono_vtable_get_static_field_data (MonoVTable *vt)
3033 if (!vt->has_static_fields)
3035 return vt->vtable [vt->klass->vtable_size];
3039 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3043 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3044 if (field->offset == -1) {
3045 /* Special static */
3048 mono_domain_lock (vt->domain);
3049 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3050 mono_domain_unlock (vt->domain);
3051 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3053 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3056 src = (guint8*)obj + field->offset;
3063 * mono_field_get_value:
3064 * @obj: Object instance
3065 * @field: MonoClassField describing the field to fetch information from
3066 * @value: pointer to the location where the value will be stored
3068 * Use this routine to get the value of the field @field in the object
3071 * The pointer provided by value must be of the field type, for reference
3072 * types this is a MonoObject*, for value types its the actual pointer to
3077 * mono_field_get_value (obj, int_field, &i);
3080 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3086 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3088 src = (char*)obj + field->offset;
3089 set_value (field->type, value, src, TRUE);
3093 * mono_field_get_value_object:
3094 * @domain: domain where the object will be created (if boxing)
3095 * @field: MonoClassField describing the field to fetch information from
3096 * @obj: The object instance for the field.
3098 * Returns: a new MonoObject with the value from the given field. If the
3099 * field represents a value type, the value is boxed.
3103 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3107 MonoVTable *vtable = NULL;
3109 gboolean is_static = FALSE;
3110 gboolean is_ref = FALSE;
3111 gboolean is_literal = FALSE;
3112 gboolean is_ptr = FALSE;
3114 MonoType *type = mono_field_get_type_checked (field, &error);
3116 if (!mono_error_ok (&error))
3117 mono_error_raise_exception (&error);
3119 switch (type->type) {
3120 case MONO_TYPE_STRING:
3121 case MONO_TYPE_OBJECT:
3122 case MONO_TYPE_CLASS:
3123 case MONO_TYPE_ARRAY:
3124 case MONO_TYPE_SZARRAY:
3129 case MONO_TYPE_BOOLEAN:
3132 case MONO_TYPE_CHAR:
3141 case MONO_TYPE_VALUETYPE:
3142 is_ref = type->byref;
3144 case MONO_TYPE_GENERICINST:
3145 is_ref = !mono_type_generic_inst_is_valuetype (type);
3151 g_error ("type 0x%x not handled in "
3152 "mono_field_get_value_object", type->type);
3156 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3159 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3163 vtable = mono_class_vtable (domain, field->parent);
3165 char *name = mono_type_get_full_name (field->parent);
3166 /*FIXME extend this to use the MonoError api*/
3167 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3171 if (!vtable->initialized)
3172 mono_runtime_class_init (vtable);
3180 get_default_field_value (domain, field, &o);
3181 } else if (is_static) {
3182 mono_field_static_get_value (vtable, field, &o);
3184 mono_field_get_value (obj, field, &o);
3190 static MonoMethod *m;
3196 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3197 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3203 get_default_field_value (domain, field, v);
3204 } else if (is_static) {
3205 mono_field_static_get_value (vtable, field, v);
3207 mono_field_get_value (obj, field, v);
3210 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3212 args [1] = mono_type_get_object (mono_domain_get (), type);
3214 return mono_runtime_invoke (m, NULL, args, NULL);
3217 /* boxed value type */
3218 klass = mono_class_from_mono_type (type);
3220 if (mono_class_is_nullable (klass))
3221 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3223 o = mono_object_new (domain, klass);
3224 v = ((gchar *) o) + sizeof (MonoObject);
3227 get_default_field_value (domain, field, v);
3228 } else if (is_static) {
3229 mono_field_static_get_value (vtable, field, v);
3231 mono_field_get_value (obj, field, v);
3238 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3241 const char *p = blob;
3242 mono_metadata_decode_blob_size (p, &p);
3245 case MONO_TYPE_BOOLEAN:
3248 *(guint8 *) value = *p;
3250 case MONO_TYPE_CHAR:
3253 *(guint16*) value = read16 (p);
3257 *(guint32*) value = read32 (p);
3261 *(guint64*) value = read64 (p);
3264 readr4 (p, (float*) value);
3267 readr8 (p, (double*) value);
3269 case MONO_TYPE_STRING:
3270 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3272 case MONO_TYPE_CLASS:
3273 *(gpointer*) value = NULL;
3277 g_warning ("type 0x%02x should not be in constant table", type);
3283 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3285 MonoTypeEnum def_type;
3288 data = mono_class_get_field_default_value (field, &def_type);
3289 mono_get_constant_value_from_blob (domain, def_type, data, value);
3293 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3297 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3299 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3300 get_default_field_value (vt->domain, field, value);
3304 if (field->offset == -1) {
3305 /* Special static */
3306 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3307 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3309 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3311 set_value (field->type, value, src, TRUE);
3315 * mono_field_static_get_value:
3316 * @vt: vtable to the object
3317 * @field: MonoClassField describing the field to fetch information from
3318 * @value: where the value is returned
3320 * Use this routine to get the value of the static field @field value.
3322 * The pointer provided by value must be of the field type, for reference
3323 * types this is a MonoObject*, for value types its the actual pointer to
3328 * mono_field_static_get_value (vt, int_field, &i);
3331 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3333 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3337 * mono_property_set_value:
3338 * @prop: MonoProperty to set
3339 * @obj: instance object on which to act
3340 * @params: parameters to pass to the propery
3341 * @exc: optional exception
3343 * Invokes the property's set method with the given arguments on the
3344 * object instance obj (or NULL for static properties).
3346 * You can pass NULL as the exc argument if you don't want to
3347 * catch exceptions, otherwise, *exc will be set to the exception
3348 * thrown, if any. if an exception is thrown, you can't use the
3349 * MonoObject* result from the function.
3352 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3354 default_mono_runtime_invoke (prop->set, obj, params, exc);
3358 * mono_property_get_value:
3359 * @prop: MonoProperty to fetch
3360 * @obj: instance object on which to act
3361 * @params: parameters to pass to the propery
3362 * @exc: optional exception
3364 * Invokes the property's get method with the given arguments on the
3365 * object instance obj (or NULL for static properties).
3367 * You can pass NULL as the exc argument if you don't want to
3368 * catch exceptions, otherwise, *exc will be set to the exception
3369 * thrown, if any. if an exception is thrown, you can't use the
3370 * MonoObject* result from the function.
3372 * Returns: the value from invoking the get method on the property.
3375 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3377 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3381 * mono_nullable_init:
3382 * @buf: The nullable structure to initialize.
3383 * @value: the value to initialize from
3384 * @klass: the type for the object
3386 * Initialize the nullable structure pointed to by @buf from @value which
3387 * should be a boxed value type. The size of @buf should be able to hold
3388 * as much data as the @klass->instance_size (which is the number of bytes
3389 * that will be copies).
3391 * Since Nullables have variable structure, we can not define a C
3392 * structure for them.
3395 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3397 MonoClass *param_class = klass->cast_class;
3399 mono_class_setup_fields_locking (klass);
3400 g_assert (klass->fields_inited);
3402 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3403 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3405 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3407 if (param_class->has_references)
3408 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3410 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3412 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3417 * mono_nullable_box:
3418 * @buf: The buffer representing the data to be boxed
3419 * @klass: the type to box it as.
3421 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3425 mono_nullable_box (guint8 *buf, MonoClass *klass)
3427 MonoClass *param_class = klass->cast_class;
3429 mono_class_setup_fields_locking (klass);
3430 g_assert (klass->fields_inited);
3432 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3433 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3435 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3436 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3437 if (param_class->has_references)
3438 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3440 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3448 * mono_get_delegate_invoke:
3449 * @klass: The delegate class
3451 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3454 mono_get_delegate_invoke (MonoClass *klass)
3458 /* This is called at runtime, so avoid the slower search in metadata */
3459 mono_class_setup_methods (klass);
3460 if (klass->exception_type)
3462 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3467 * mono_runtime_delegate_invoke:
3468 * @delegate: pointer to a delegate object.
3469 * @params: parameters for the delegate.
3470 * @exc: Pointer to the exception result.
3472 * Invokes the delegate method @delegate with the parameters provided.
3474 * You can pass NULL as the exc argument if you don't want to
3475 * catch exceptions, otherwise, *exc will be set to the exception
3476 * thrown, if any. if an exception is thrown, you can't use the
3477 * MonoObject* result from the function.
3480 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3484 im = mono_get_delegate_invoke (delegate->vtable->klass);
3487 return mono_runtime_invoke (im, delegate, params, exc);
3490 static char **main_args = NULL;
3491 static int num_main_args;
3494 * mono_runtime_get_main_args:
3496 * Returns: a MonoArray with the arguments passed to the main program
3499 mono_runtime_get_main_args (void)
3503 MonoDomain *domain = mono_domain_get ();
3508 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3510 for (i = 0; i < num_main_args; ++i)
3511 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3517 free_main_args (void)
3521 for (i = 0; i < num_main_args; ++i)
3522 g_free (main_args [i]);
3527 * mono_runtime_run_main:
3528 * @method: the method to start the application with (usually Main)
3529 * @argc: number of arguments from the command line
3530 * @argv: array of strings from the command line
3531 * @exc: excetption results
3533 * Execute a standard Main() method (argc/argv contains the
3534 * executable name). This method also sets the command line argument value
3535 * needed by System.Environment.
3540 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3544 MonoArray *args = NULL;
3545 MonoDomain *domain = mono_domain_get ();
3546 gchar *utf8_fullpath;
3547 MonoMethodSignature *sig;
3549 g_assert (method != NULL);
3551 mono_thread_set_main (mono_thread_current ());
3553 main_args = g_new0 (char*, argc);
3554 num_main_args = argc;
3556 if (!g_path_is_absolute (argv [0])) {
3557 gchar *basename = g_path_get_basename (argv [0]);
3558 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3562 utf8_fullpath = mono_utf8_from_external (fullpath);
3563 if(utf8_fullpath == NULL) {
3564 /* Printing the arg text will cause glib to
3565 * whinge about "Invalid UTF-8", but at least
3566 * its relevant, and shows the problem text
3569 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3570 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3577 utf8_fullpath = mono_utf8_from_external (argv[0]);
3578 if(utf8_fullpath == NULL) {
3579 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3580 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3585 main_args [0] = utf8_fullpath;
3587 for (i = 1; i < argc; ++i) {
3590 utf8_arg=mono_utf8_from_external (argv[i]);
3591 if(utf8_arg==NULL) {
3592 /* Ditto the comment about Invalid UTF-8 here */
3593 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3594 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3598 main_args [i] = utf8_arg;
3603 sig = mono_method_signature (method);
3605 g_print ("Unable to load Main method.\n");
3609 if (sig->param_count) {
3610 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3611 for (i = 0; i < argc; ++i) {
3612 /* The encodings should all work, given that
3613 * we've checked all these args for the
3616 gchar *str = mono_utf8_from_external (argv [i]);
3617 MonoString *arg = mono_string_new (domain, str);
3618 mono_array_setref (args, i, arg);
3622 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3625 mono_assembly_set_main (method->klass->image->assembly);
3627 return mono_runtime_exec_main (method, args, exc);
3631 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3633 static MonoMethod *serialize_method;
3638 if (!serialize_method) {
3639 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3640 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3643 if (!serialize_method) {
3648 g_assert (!mono_object_class (obj)->marshalbyref);
3652 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3660 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3662 static MonoMethod *deserialize_method;
3667 if (!deserialize_method) {
3668 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3669 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3671 if (!deserialize_method) {
3678 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3686 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3688 static MonoMethod *get_proxy_method;
3690 MonoDomain *domain = mono_domain_get ();
3691 MonoRealProxy *real_proxy;
3692 MonoReflectionType *reflection_type;
3693 MonoTransparentProxy *transparent_proxy;
3695 if (!get_proxy_method)
3696 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3698 g_assert (obj->vtable->klass->marshalbyref);
3700 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3701 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3703 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3704 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3707 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3711 return (MonoObject*) transparent_proxy;
3715 * mono_object_xdomain_representation
3717 * @target_domain: a domain
3718 * @exc: pointer to a MonoObject*
3720 * Creates a representation of obj in the domain target_domain. This
3721 * is either a copy of obj arrived through via serialization and
3722 * deserialization or a proxy, depending on whether the object is
3723 * serializable or marshal by ref. obj must not be in target_domain.
3725 * If the object cannot be represented in target_domain, NULL is
3726 * returned and *exc is set to an appropriate exception.
3729 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3731 MonoObject *deserialized = NULL;
3732 gboolean failure = FALSE;
3736 if (mono_object_class (obj)->marshalbyref) {
3737 deserialized = make_transparent_proxy (obj, &failure, exc);
3739 MonoDomain *domain = mono_domain_get ();
3740 MonoObject *serialized;
3742 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3743 serialized = serialize_object (obj, &failure, exc);
3744 mono_domain_set_internal_with_options (target_domain, FALSE);
3746 deserialized = deserialize_object (serialized, &failure, exc);
3747 if (domain != target_domain)
3748 mono_domain_set_internal_with_options (domain, FALSE);
3751 return deserialized;
3754 /* Used in call_unhandled_exception_delegate */
3756 create_unhandled_exception_eventargs (MonoObject *exc)
3760 MonoMethod *method = NULL;
3761 MonoBoolean is_terminating = TRUE;
3764 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3767 mono_class_init (klass);
3769 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3770 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3774 args [1] = &is_terminating;
3776 obj = mono_object_new (mono_domain_get (), klass);
3777 mono_runtime_invoke (method, obj, args, NULL);
3782 /* Used in mono_unhandled_exception */
3784 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3785 MonoObject *e = NULL;
3787 MonoDomain *current_domain = mono_domain_get ();
3789 if (domain != current_domain)
3790 mono_domain_set_internal_with_options (domain, FALSE);
3792 g_assert (domain == mono_object_domain (domain->domain));
3794 if (mono_object_domain (exc) != domain) {
3795 MonoObject *serialization_exc;
3797 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3799 if (serialization_exc) {
3801 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3804 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3805 "System.Runtime.Serialization", "SerializationException",
3806 "Could not serialize unhandled exception.");
3810 g_assert (mono_object_domain (exc) == domain);
3812 pa [0] = domain->domain;
3813 pa [1] = create_unhandled_exception_eventargs (exc);
3814 mono_runtime_delegate_invoke (delegate, pa, &e);
3816 if (domain != current_domain)
3817 mono_domain_set_internal_with_options (current_domain, FALSE);
3821 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3822 if (!mono_error_ok (&error)) {
3823 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3824 mono_error_cleanup (&error);
3826 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3832 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3835 * mono_runtime_unhandled_exception_policy_set:
3836 * @policy: the new policy
3838 * This is a VM internal routine.
3840 * Sets the runtime policy for handling unhandled exceptions.
3843 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3844 runtime_unhandled_exception_policy = policy;
3848 * mono_runtime_unhandled_exception_policy_get:
3850 * This is a VM internal routine.
3852 * Gets the runtime policy for handling unhandled exceptions.
3854 MonoRuntimeUnhandledExceptionPolicy
3855 mono_runtime_unhandled_exception_policy_get (void) {
3856 return runtime_unhandled_exception_policy;
3860 * mono_unhandled_exception:
3861 * @exc: exception thrown
3863 * This is a VM internal routine.
3865 * We call this function when we detect an unhandled exception
3866 * in the default domain.
3868 * It invokes the * UnhandledException event in AppDomain or prints
3869 * a warning to the console
3872 mono_unhandled_exception (MonoObject *exc)
3874 MonoDomain *current_domain = mono_domain_get ();
3875 MonoDomain *root_domain = mono_get_root_domain ();
3876 MonoClassField *field;
3877 MonoObject *current_appdomain_delegate;
3878 MonoObject *root_appdomain_delegate;
3880 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3881 "UnhandledException");
3884 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3885 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3886 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3887 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3888 if (current_domain != root_domain) {
3889 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3891 current_appdomain_delegate = NULL;
3894 /* set exitcode only if we will abort the process */
3895 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3897 mono_environment_exitcode_set (1);
3898 mono_print_unhandled_exception (exc);
3900 if (root_appdomain_delegate) {
3901 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3903 if (current_appdomain_delegate) {
3904 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3911 * mono_runtime_exec_managed_code:
3912 * @domain: Application domain
3913 * @main_func: function to invoke from the execution thread
3914 * @main_args: parameter to the main_func
3916 * Launch a new thread to execute a function
3918 * main_func is called back from the thread with main_args as the
3919 * parameter. The callback function is expected to start Main()
3920 * eventually. This function then waits for all managed threads to
3922 * It is not necesseray anymore to execute managed code in a subthread,
3923 * so this function should not be used anymore by default: just
3924 * execute the code and then call mono_thread_manage ().
3927 mono_runtime_exec_managed_code (MonoDomain *domain,
3928 MonoMainThreadFunc main_func,
3931 mono_thread_create (domain, main_func, main_args);
3933 mono_thread_manage ();
3937 * Execute a standard Main() method (args doesn't contain the
3941 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3946 MonoCustomAttrInfo* cinfo;
3947 gboolean has_stathread_attribute;
3948 MonoInternalThread* thread = mono_thread_internal_current ();
3954 domain = mono_object_domain (args);
3955 if (!domain->entry_assembly) {
3957 MonoAssembly *assembly;
3959 assembly = method->klass->image->assembly;
3960 domain->entry_assembly = assembly;
3961 /* Domains created from another domain already have application_base and configuration_file set */
3962 if (domain->setup->application_base == NULL) {
3963 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3966 if (domain->setup->configuration_file == NULL) {
3967 str = g_strconcat (assembly->image->name, ".config", NULL);
3968 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3970 mono_set_private_bin_path_from_config (domain);
3974 cinfo = mono_custom_attrs_from_method (method);
3976 static MonoClass *stathread_attribute = NULL;
3977 if (!stathread_attribute)
3978 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3979 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3981 mono_custom_attrs_free (cinfo);
3983 has_stathread_attribute = FALSE;
3985 if (has_stathread_attribute) {
3986 thread->apartment_state = ThreadApartmentState_STA;
3988 thread->apartment_state = ThreadApartmentState_MTA;
3990 mono_thread_init_apartment_state ();
3992 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3994 /* FIXME: check signature of method */
3995 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3997 res = mono_runtime_invoke (method, NULL, pa, exc);
3999 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4003 mono_environment_exitcode_set (rval);
4005 mono_runtime_invoke (method, NULL, pa, exc);
4009 /* If the return type of Main is void, only
4010 * set the exitcode if an exception was thrown
4011 * (we don't want to blow away an
4012 * explicitly-set exit code)
4015 mono_environment_exitcode_set (rval);
4019 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4025 * mono_install_runtime_invoke:
4026 * @func: Function to install
4028 * This is a VM internal routine
4031 mono_install_runtime_invoke (MonoInvokeFunc func)
4033 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4038 * mono_runtime_invoke_array:
4039 * @method: method to invoke
4040 * @obJ: object instance
4041 * @params: arguments to the method
4042 * @exc: exception information.
4044 * Invokes the method represented by @method on the object @obj.
4046 * obj is the 'this' pointer, it should be NULL for static
4047 * methods, a MonoObject* for object instances and a pointer to
4048 * the value type for value types.
4050 * The params array contains the arguments to the method with the
4051 * same convention: MonoObject* pointers for object instances and
4052 * pointers to the value type otherwise. The _invoke_array
4053 * variant takes a C# object[] as the params argument (MonoArray
4054 * *params): in this case the value types are boxed inside the
4055 * respective reference representation.
4057 * From unmanaged code you'll usually use the
4058 * mono_runtime_invoke() variant.
4060 * Note that this function doesn't handle virtual methods for
4061 * you, it will exec the exact method you pass: we still need to
4062 * expose a function to lookup the derived class implementation
4063 * of a virtual method (there are examples of this in the code,
4066 * You can pass NULL as the exc argument if you don't want to
4067 * catch exceptions, otherwise, *exc will be set to the exception
4068 * thrown, if any. if an exception is thrown, you can't use the
4069 * MonoObject* result from the function.
4071 * If the method returns a value type, it is boxed in an object
4075 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4078 MonoMethodSignature *sig = mono_method_signature (method);
4079 gpointer *pa = NULL;
4082 gboolean has_byref_nullables = FALSE;
4084 if (NULL != params) {
4085 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4086 for (i = 0; i < mono_array_length (params); i++) {
4087 MonoType *t = sig->params [i];
4093 case MONO_TYPE_BOOLEAN:
4096 case MONO_TYPE_CHAR:
4105 case MONO_TYPE_VALUETYPE:
4106 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4107 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4108 pa [i] = mono_array_get (params, MonoObject*, i);
4110 has_byref_nullables = TRUE;
4112 /* MS seems to create the objects if a null is passed in */
4113 if (!mono_array_get (params, MonoObject*, i))
4114 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4118 * We can't pass the unboxed vtype byref to the callee, since
4119 * that would mean the callee would be able to modify boxed
4120 * primitive types. So we (and MS) make a copy of the boxed
4121 * object, pass that to the callee, and replace the original
4122 * boxed object in the arg array with the copy.
4124 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4125 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4126 mono_array_setref (params, i, copy);
4129 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4132 case MONO_TYPE_STRING:
4133 case MONO_TYPE_OBJECT:
4134 case MONO_TYPE_CLASS:
4135 case MONO_TYPE_ARRAY:
4136 case MONO_TYPE_SZARRAY:
4138 pa [i] = mono_array_addr (params, MonoObject*, i);
4139 // FIXME: I need to check this code path
4141 pa [i] = mono_array_get (params, MonoObject*, i);
4143 case MONO_TYPE_GENERICINST:
4145 t = &t->data.generic_class->container_class->this_arg;
4147 t = &t->data.generic_class->container_class->byval_arg;
4149 case MONO_TYPE_PTR: {
4152 /* The argument should be an IntPtr */
4153 arg = mono_array_get (params, MonoObject*, i);
4157 g_assert (arg->vtable->klass == mono_defaults.int_class);
4158 pa [i] = ((MonoIntPtr*)arg)->m_value;
4163 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4168 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4171 if (mono_class_is_nullable (method->klass)) {
4172 /* Need to create a boxed vtype instead */
4178 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4182 obj = mono_object_new (mono_domain_get (), method->klass);
4183 g_assert (obj); /*maybe we should raise a TLE instead?*/
4184 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4185 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4187 if (method->klass->valuetype)
4188 o = mono_object_unbox (obj);
4191 } else if (method->klass->valuetype) {
4192 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4195 mono_runtime_invoke (method, o, pa, exc);
4198 if (mono_class_is_nullable (method->klass)) {
4199 MonoObject *nullable;
4201 /* Convert the unboxed vtype into a Nullable structure */
4202 nullable = mono_object_new (mono_domain_get (), method->klass);
4204 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4205 obj = mono_object_unbox (nullable);
4208 /* obj must be already unboxed if needed */
4209 res = mono_runtime_invoke (method, obj, pa, exc);
4211 if (sig->ret->type == MONO_TYPE_PTR) {
4212 MonoClass *pointer_class;
4213 static MonoMethod *box_method;
4215 MonoObject *box_exc;
4218 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4219 * convert it to a Pointer object.
4221 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4223 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4225 g_assert (res->vtable->klass == mono_defaults.int_class);
4226 box_args [0] = ((MonoIntPtr*)res)->m_value;
4227 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4228 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4229 g_assert (!box_exc);
4232 if (has_byref_nullables) {
4234 * The runtime invoke wrapper already converted byref nullables back,
4235 * and stored them in pa, we just need to copy them back to the
4238 for (i = 0; i < mono_array_length (params); i++) {
4239 MonoType *t = sig->params [i];
4241 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4242 mono_array_setref (params, i, pa [i]);
4251 arith_overflow (void)
4253 mono_raise_exception (mono_get_exception_overflow ());
4257 * mono_object_allocate:
4258 * @size: number of bytes to allocate
4260 * This is a very simplistic routine until we have our GC-aware
4263 * Returns: an allocated object of size @size, or NULL on failure.
4265 static inline void *
4266 mono_object_allocate (size_t size, MonoVTable *vtable)
4269 mono_stats.new_object_count++;
4270 ALLOC_OBJECT (o, vtable, size);
4276 * mono_object_allocate_ptrfree:
4277 * @size: number of bytes to allocate
4279 * Note that the memory allocated is not zeroed.
4280 * Returns: an allocated object of size @size, or NULL on failure.
4282 static inline void *
4283 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4286 mono_stats.new_object_count++;
4287 ALLOC_PTRFREE (o, vtable, size);
4291 static inline void *
4292 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4295 ALLOC_TYPED (o, size, vtable);
4296 mono_stats.new_object_count++;
4303 * @klass: the class of the object that we want to create
4305 * Returns: a newly created object whose definition is
4306 * looked up using @klass. This will not invoke any constructors,
4307 * so the consumer of this routine has to invoke any constructors on
4308 * its own to initialize the object.
4310 * It returns NULL on failure.
4313 mono_object_new (MonoDomain *domain, MonoClass *klass)
4317 MONO_ARCH_SAVE_REGS;
4318 vtable = mono_class_vtable (domain, klass);
4321 return mono_object_new_specific (vtable);
4325 * mono_object_new_pinned:
4327 * Same as mono_object_new, but the returned object will be pinned.
4328 * For SGEN, these objects will only be freed at appdomain unload.
4331 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4335 MONO_ARCH_SAVE_REGS;
4336 vtable = mono_class_vtable (domain, klass);
4341 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4343 return mono_object_new_specific (vtable);
4348 * mono_object_new_specific:
4349 * @vtable: the vtable of the object that we want to create
4351 * Returns: A newly created object with class and domain specified
4355 mono_object_new_specific (MonoVTable *vtable)
4359 MONO_ARCH_SAVE_REGS;
4361 /* check for is_com_object for COM Interop */
4362 if (vtable->remote || vtable->klass->is_com_object)
4365 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4368 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4371 mono_class_init (klass);
4373 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4375 vtable->domain->create_proxy_for_type_method = im;
4378 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4380 o = mono_runtime_invoke (im, NULL, pa, NULL);
4381 if (o != NULL) return o;
4384 return mono_object_new_alloc_specific (vtable);
4388 mono_object_new_alloc_specific (MonoVTable *vtable)
4392 if (!vtable->klass->has_references) {
4393 o = mono_object_new_ptrfree (vtable);
4394 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4395 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4397 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4398 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4400 if (G_UNLIKELY (vtable->klass->has_finalize))
4401 mono_object_register_finalizer (o);
4403 if (G_UNLIKELY (profile_allocs))
4404 mono_profiler_allocation (o, vtable->klass);
4409 mono_object_new_fast (MonoVTable *vtable)
4412 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4417 mono_object_new_ptrfree (MonoVTable *vtable)
4420 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4421 #if NEED_TO_ZERO_PTRFREE
4422 /* an inline memset is much faster for the common vcase of small objects
4423 * note we assume the allocated size is a multiple of sizeof (void*).
4425 if (vtable->klass->instance_size < 128) {
4427 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4428 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4434 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4441 mono_object_new_ptrfree_box (MonoVTable *vtable)
4444 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4445 /* the object will be boxed right away, no need to memzero it */
4450 * mono_class_get_allocation_ftn:
4452 * @for_box: the object will be used for boxing
4453 * @pass_size_in_words:
4455 * Return the allocation function appropriate for the given class.
4459 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4461 *pass_size_in_words = FALSE;
4463 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4464 profile_allocs = FALSE;
4466 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4467 return mono_object_new_specific;
4469 if (!vtable->klass->has_references) {
4470 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4472 return mono_object_new_ptrfree_box;
4473 return mono_object_new_ptrfree;
4476 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4478 return mono_object_new_fast;
4481 * FIXME: This is actually slower than mono_object_new_fast, because
4482 * of the overhead of parameter passing.
4485 *pass_size_in_words = TRUE;
4486 #ifdef GC_REDIRECT_TO_LOCAL
4487 return GC_local_gcj_fast_malloc;
4489 return GC_gcj_fast_malloc;
4494 return mono_object_new_specific;
4498 * mono_object_new_from_token:
4499 * @image: Context where the type_token is hosted
4500 * @token: a token of the type that we want to create
4502 * Returns: A newly created object whose definition is
4503 * looked up using @token in the @image image
4506 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4510 class = mono_class_get (image, token);
4512 return mono_object_new (domain, class);
4517 * mono_object_clone:
4518 * @obj: the object to clone
4520 * Returns: A newly created object who is a shallow copy of @obj
4523 mono_object_clone (MonoObject *obj)
4526 int size = obj->vtable->klass->instance_size;
4528 if (obj->vtable->klass->rank)
4529 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4531 o = mono_object_allocate (size, obj->vtable);
4533 if (obj->vtable->klass->has_references) {
4534 mono_gc_wbarrier_object_copy (o, obj);
4536 int size = obj->vtable->klass->instance_size;
4537 /* do not copy the sync state */
4538 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4540 if (G_UNLIKELY (profile_allocs))
4541 mono_profiler_allocation (o, obj->vtable->klass);
4543 if (obj->vtable->klass->has_finalize)
4544 mono_object_register_finalizer (o);
4549 * mono_array_full_copy:
4550 * @src: source array to copy
4551 * @dest: destination array
4553 * Copies the content of one array to another with exactly the same type and size.
4556 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4559 MonoClass *klass = src->obj.vtable->klass;
4561 MONO_ARCH_SAVE_REGS;
4563 g_assert (klass == dest->obj.vtable->klass);
4565 size = mono_array_length (src);
4566 g_assert (size == mono_array_length (dest));
4567 size *= mono_array_element_size (klass);
4569 if (klass->element_class->valuetype) {
4570 if (klass->element_class->has_references)
4571 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4573 mono_gc_memmove (&dest->vector, &src->vector, size);
4575 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4578 mono_gc_memmove (&dest->vector, &src->vector, size);
4583 * mono_array_clone_in_domain:
4584 * @domain: the domain in which the array will be cloned into
4585 * @array: the array to clone
4587 * This routine returns a copy of the array that is hosted on the
4588 * specified MonoDomain.
4591 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4596 MonoClass *klass = array->obj.vtable->klass;
4598 MONO_ARCH_SAVE_REGS;
4600 if (array->bounds == NULL) {
4601 size = mono_array_length (array);
4602 o = mono_array_new_full (domain, klass, &size, NULL);
4604 size *= mono_array_element_size (klass);
4606 if (klass->element_class->valuetype) {
4607 if (klass->element_class->has_references)
4608 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4610 mono_gc_memmove (&o->vector, &array->vector, size);
4612 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4615 mono_gc_memmove (&o->vector, &array->vector, size);
4620 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4621 size = mono_array_element_size (klass);
4622 for (i = 0; i < klass->rank; ++i) {
4623 sizes [i] = array->bounds [i].length;
4624 size *= array->bounds [i].length;
4625 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4627 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4629 if (klass->element_class->valuetype) {
4630 if (klass->element_class->has_references)
4631 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4633 mono_gc_memmove (&o->vector, &array->vector, size);
4635 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4638 mono_gc_memmove (&o->vector, &array->vector, size);
4646 * @array: the array to clone
4648 * Returns: A newly created array who is a shallow copy of @array
4651 mono_array_clone (MonoArray *array)
4653 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4656 /* helper macros to check for overflow when calculating the size of arrays */
4657 #ifdef MONO_BIG_ARRAYS
4658 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4659 #define MYGUINT_MAX MYGUINT64_MAX
4660 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4661 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4662 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4663 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4664 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4666 #define MYGUINT32_MAX 4294967295U
4667 #define MYGUINT_MAX MYGUINT32_MAX
4668 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4669 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4670 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4671 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4672 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4676 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4680 byte_len = mono_array_element_size (class);
4681 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4684 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4686 byte_len += sizeof (MonoArray);
4694 * mono_array_new_full:
4695 * @domain: domain where the object is created
4696 * @array_class: array class
4697 * @lengths: lengths for each dimension in the array
4698 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4700 * This routine creates a new array objects with the given dimensions,
4701 * lower bounds and type.
4704 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4706 uintptr_t byte_len, len, bounds_size;
4709 MonoArrayBounds *bounds;
4713 if (!array_class->inited)
4714 mono_class_init (array_class);
4718 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4719 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4721 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4725 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4727 for (i = 0; i < array_class->rank; ++i) {
4728 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4730 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4731 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4736 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4737 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4741 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4742 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4743 byte_len = (byte_len + 3) & ~3;
4744 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4745 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4746 byte_len += bounds_size;
4749 * Following three lines almost taken from mono_object_new ():
4750 * they need to be kept in sync.
4752 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4753 #ifndef HAVE_SGEN_GC
4754 if (!array_class->has_references) {
4755 o = mono_object_allocate_ptrfree (byte_len, vtable);
4756 #if NEED_TO_ZERO_PTRFREE
4757 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4759 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4760 o = mono_object_allocate_spec (byte_len, vtable);
4762 o = mono_object_allocate (byte_len, vtable);
4765 array = (MonoArray*)o;
4766 array->max_length = len;
4769 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4770 array->bounds = bounds;
4774 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4776 o = mono_gc_alloc_vector (vtable, byte_len, len);
4777 array = (MonoArray*)o;
4778 mono_stats.new_object_count++;
4780 bounds = array->bounds;
4784 for (i = 0; i < array_class->rank; ++i) {
4785 bounds [i].length = lengths [i];
4787 bounds [i].lower_bound = lower_bounds [i];
4791 if (G_UNLIKELY (profile_allocs))
4792 mono_profiler_allocation (o, array_class);
4799 * @domain: domain where the object is created
4800 * @eclass: element class
4801 * @n: number of array elements
4803 * This routine creates a new szarray with @n elements of type @eclass.
4806 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4810 MONO_ARCH_SAVE_REGS;
4812 ac = mono_array_class_get (eclass, 1);
4815 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4819 * mono_array_new_specific:
4820 * @vtable: a vtable in the appropriate domain for an initialized class
4821 * @n: number of array elements
4823 * This routine is a fast alternative to mono_array_new() for code which
4824 * can be sure about the domain it operates in.
4827 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4833 MONO_ARCH_SAVE_REGS;
4835 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4840 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4841 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4844 #ifndef HAVE_SGEN_GC
4845 if (!vtable->klass->has_references) {
4846 o = mono_object_allocate_ptrfree (byte_len, vtable);
4847 #if NEED_TO_ZERO_PTRFREE
4848 ((MonoArray*)o)->bounds = NULL;
4849 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4851 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4852 o = mono_object_allocate_spec (byte_len, vtable);
4854 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4855 o = mono_object_allocate (byte_len, vtable);
4858 ao = (MonoArray *)o;
4861 o = mono_gc_alloc_vector (vtable, byte_len, n);
4863 mono_stats.new_object_count++;
4866 if (G_UNLIKELY (profile_allocs))
4867 mono_profiler_allocation (o, vtable->klass);
4873 * mono_string_new_utf16:
4874 * @text: a pointer to an utf16 string
4875 * @len: the length of the string
4877 * Returns: A newly created string object which contains @text.
4880 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4884 s = mono_string_new_size (domain, len);
4885 g_assert (s != NULL);
4887 memcpy (mono_string_chars (s), text, len * 2);
4893 * mono_string_new_size:
4894 * @text: a pointer to an utf16 string
4895 * @len: the length of the string
4897 * Returns: A newly created string object of @len
4900 mono_string_new_size (MonoDomain *domain, gint32 len)
4904 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4906 /* overflow ? can't fit it, can't allocate it! */
4908 mono_gc_out_of_memory (-1);
4910 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4913 #ifndef HAVE_SGEN_GC
4914 s = mono_object_allocate_ptrfree (size, vtable);
4918 s = mono_gc_alloc_string (vtable, size, len);
4920 #if NEED_TO_ZERO_PTRFREE
4923 if (G_UNLIKELY (profile_allocs))
4924 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4930 * mono_string_new_len:
4931 * @text: a pointer to an utf8 string
4932 * @length: number of bytes in @text to consider
4934 * Returns: A newly created string object which contains @text.
4937 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4939 GError *error = NULL;
4940 MonoString *o = NULL;
4942 glong items_written;
4944 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4947 o = mono_string_new_utf16 (domain, ut, items_written);
4949 g_error_free (error);
4958 * @text: a pointer to an utf8 string
4960 * Returns: A newly created string object which contains @text.
4963 mono_string_new (MonoDomain *domain, const char *text)
4965 GError *error = NULL;
4966 MonoString *o = NULL;
4968 glong items_written;
4973 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4976 o = mono_string_new_utf16 (domain, ut, items_written);
4978 g_error_free (error);
4981 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4986 MonoString *o = NULL;
4988 if (!g_utf8_validate (text, -1, &end))
4991 len = g_utf8_strlen (text, -1);
4992 o = mono_string_new_size (domain, len);
4993 str = mono_string_chars (o);
4995 while (text < end) {
4996 *str++ = g_utf8_get_char (text);
4997 text = g_utf8_next_char (text);
5004 * mono_string_new_wrapper:
5005 * @text: pointer to utf8 characters.
5007 * Helper function to create a string object from @text in the current domain.
5010 mono_string_new_wrapper (const char *text)
5012 MonoDomain *domain = mono_domain_get ();
5014 MONO_ARCH_SAVE_REGS;
5017 return mono_string_new (domain, text);
5024 * @class: the class of the value
5025 * @value: a pointer to the unboxed data
5027 * Returns: A newly created object which contains @value.
5030 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5036 g_assert (class->valuetype);
5037 if (mono_class_is_nullable (class))
5038 return mono_nullable_box (value, class);
5040 vtable = mono_class_vtable (domain, class);
5043 size = mono_class_instance_size (class);
5044 res = mono_object_new_alloc_specific (vtable);
5045 if (G_UNLIKELY (profile_allocs))
5046 mono_profiler_allocation (res, class);
5048 size = size - sizeof (MonoObject);
5051 g_assert (size == mono_class_value_size (class, NULL));
5052 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5054 #if NO_UNALIGNED_ACCESS
5055 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5059 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5062 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5065 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5068 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5071 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5075 if (class->has_finalize)
5076 mono_object_register_finalizer (res);
5082 * @dest: destination pointer
5083 * @src: source pointer
5084 * @klass: a valuetype class
5086 * Copy a valuetype from @src to @dest. This function must be used
5087 * when @klass contains references fields.
5090 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5092 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5096 * mono_value_copy_array:
5097 * @dest: destination array
5098 * @dest_idx: index in the @dest array
5099 * @src: source pointer
5100 * @count: number of items
5102 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5103 * This function must be used when @klass contains references fields.
5104 * Overlap is handled.
5107 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5109 int size = mono_array_element_size (dest->obj.vtable->klass);
5110 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5111 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5112 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5116 * mono_object_get_domain:
5117 * @obj: object to query
5119 * Returns: the MonoDomain where the object is hosted
5122 mono_object_get_domain (MonoObject *obj)
5124 return mono_object_domain (obj);
5128 * mono_object_get_class:
5129 * @obj: object to query
5131 * Returns: the MonOClass of the object.
5134 mono_object_get_class (MonoObject *obj)
5136 return mono_object_class (obj);
5139 * mono_object_get_size:
5140 * @o: object to query
5142 * Returns: the size, in bytes, of @o
5145 mono_object_get_size (MonoObject* o)
5147 MonoClass* klass = mono_object_class (o);
5148 if (klass == mono_defaults.string_class) {
5149 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5150 } else if (o->vtable->rank) {
5151 MonoArray *array = (MonoArray*)o;
5152 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5153 if (array->bounds) {
5156 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5160 return mono_class_instance_size (klass);
5165 * mono_object_unbox:
5166 * @obj: object to unbox
5168 * Returns: a pointer to the start of the valuetype boxed in this
5171 * This method will assert if the object passed is not a valuetype.
5174 mono_object_unbox (MonoObject *obj)
5176 /* add assert for valuetypes? */
5177 g_assert (obj->vtable->klass->valuetype);
5178 return ((char*)obj) + sizeof (MonoObject);
5182 * mono_object_isinst:
5184 * @klass: a pointer to a class
5186 * Returns: @obj if @obj is derived from @klass
5189 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5192 mono_class_init (klass);
5194 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5195 return mono_object_isinst_mbyref (obj, klass);
5200 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5204 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5213 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5214 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5218 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5219 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5222 MonoClass *oklass = vt->klass;
5223 if (oklass == mono_defaults.transparent_proxy_class)
5224 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5226 mono_class_setup_supertypes (klass);
5227 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5231 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5233 MonoDomain *domain = mono_domain_get ();
5235 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5236 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5237 MonoMethod *im = NULL;
5240 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5241 im = mono_object_get_virtual_method (rp, im);
5244 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5247 res = mono_runtime_invoke (im, rp, pa, NULL);
5249 if (*(MonoBoolean *) mono_object_unbox(res)) {
5250 /* Update the vtable of the remote type, so it can safely cast to this new type */
5251 mono_upgrade_remote_class (domain, obj, klass);
5260 * mono_object_castclass_mbyref:
5262 * @klass: a pointer to a class
5264 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5267 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5269 if (!obj) return NULL;
5270 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5272 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5274 "InvalidCastException"));
5279 MonoDomain *orig_domain;
5285 str_lookup (MonoDomain *domain, gpointer user_data)
5287 LDStrInfo *info = user_data;
5288 if (info->res || domain == info->orig_domain)
5290 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5296 mono_string_get_pinned (MonoString *str)
5300 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5301 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5303 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5304 news->length = mono_string_length (str);
5310 #define mono_string_get_pinned(str) (str)
5314 mono_string_is_interned_lookup (MonoString *str, int insert)
5316 MonoGHashTable *ldstr_table;
5320 domain = ((MonoObject *)str)->vtable->domain;
5321 ldstr_table = domain->ldstr_table;
5323 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5328 str = mono_string_get_pinned (str);
5330 mono_g_hash_table_insert (ldstr_table, str, str);
5334 LDStrInfo ldstr_info;
5335 ldstr_info.orig_domain = domain;
5336 ldstr_info.ins = str;
5337 ldstr_info.res = NULL;
5339 mono_domain_foreach (str_lookup, &ldstr_info);
5340 if (ldstr_info.res) {
5342 * the string was already interned in some other domain:
5343 * intern it in the current one as well.
5345 mono_g_hash_table_insert (ldstr_table, str, str);
5355 * mono_string_is_interned:
5356 * @o: String to probe
5358 * Returns whether the string has been interned.
5361 mono_string_is_interned (MonoString *o)
5363 return mono_string_is_interned_lookup (o, FALSE);
5367 * mono_string_intern:
5368 * @o: String to intern
5370 * Interns the string passed.
5371 * Returns: The interned string.
5374 mono_string_intern (MonoString *str)
5376 return mono_string_is_interned_lookup (str, TRUE);
5381 * @domain: the domain where the string will be used.
5382 * @image: a metadata context
5383 * @idx: index into the user string table.
5385 * Implementation for the ldstr opcode.
5386 * Returns: a loaded string from the @image/@idx combination.
5389 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5391 MONO_ARCH_SAVE_REGS;
5393 if (image->dynamic) {
5394 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5397 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5398 return NULL; /*FIXME we should probably be raising an exception here*/
5399 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5404 * mono_ldstr_metadata_sig
5405 * @domain: the domain for the string
5406 * @sig: the signature of a metadata string
5408 * Returns: a MonoString for a string stored in the metadata
5411 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5413 const char *str = sig;
5414 MonoString *o, *interned;
5417 len2 = mono_metadata_decode_blob_size (str, &str);
5420 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5421 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5424 guint16 *p2 = (guint16*)mono_string_chars (o);
5425 for (i = 0; i < len2; ++i) {
5426 *p2 = GUINT16_FROM_LE (*p2);
5432 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5434 /* o will get garbage collected */
5438 o = mono_string_get_pinned (o);
5440 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5447 * mono_string_to_utf8:
5448 * @s: a System.String
5450 * Returns the UTF8 representation for @s.
5451 * The resulting buffer needs to be freed with mono_free().
5453 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5456 mono_string_to_utf8 (MonoString *s)
5459 char *result = mono_string_to_utf8_checked (s, &error);
5461 if (!mono_error_ok (&error))
5462 mono_error_raise_exception (&error);
5467 * mono_string_to_utf8_checked:
5468 * @s: a System.String
5469 * @error: a MonoError.
5471 * Converts a MonoString to its UTF8 representation. May fail; check
5472 * @error to determine whether the conversion was successful.
5473 * The resulting buffer should be freed with mono_free().
5476 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5480 GError *gerror = NULL;
5482 mono_error_init (error);
5488 return g_strdup ("");
5490 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5492 mono_error_set_argument (error, "string", "%s", gerror->message);
5493 g_error_free (gerror);
5496 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5497 if (s->length > written) {
5498 /* allocate the total length and copy the part of the string that has been converted */
5499 char *as2 = g_malloc0 (s->length);
5500 memcpy (as2, as, written);
5509 * mono_string_to_utf8_ignore:
5512 * Converts a MonoString to its UTF8 representation. Will ignore
5513 * invalid surrogate pairs.
5514 * The resulting buffer should be freed with mono_free().
5518 mono_string_to_utf8_ignore (MonoString *s)
5527 return g_strdup ("");
5529 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5531 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5532 if (s->length > written) {
5533 /* allocate the total length and copy the part of the string that has been converted */
5534 char *as2 = g_malloc0 (s->length);
5535 memcpy (as2, as, written);
5544 * mono_string_to_utf8_image_ignore:
5545 * @s: a System.String
5547 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5550 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5552 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5556 * mono_string_to_utf8_mp_ignore:
5557 * @s: a System.String
5559 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5562 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5564 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5569 * mono_string_to_utf16:
5572 * Return an null-terminated array of the utf-16 chars
5573 * contained in @s. The result must be freed with g_free().
5574 * This is a temporary helper until our string implementation
5575 * is reworked to always include the null terminating char.
5578 mono_string_to_utf16 (MonoString *s)
5585 as = g_malloc ((s->length * 2) + 2);
5586 as [(s->length * 2)] = '\0';
5587 as [(s->length * 2) + 1] = '\0';
5590 return (gunichar2 *)(as);
5593 memcpy (as, mono_string_chars(s), s->length * 2);
5594 return (gunichar2 *)(as);
5598 * mono_string_from_utf16:
5599 * @data: the UTF16 string (LPWSTR) to convert
5601 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5603 * Returns: a MonoString.
5606 mono_string_from_utf16 (gunichar2 *data)
5608 MonoDomain *domain = mono_domain_get ();
5614 while (data [len]) len++;
5616 return mono_string_new_utf16 (domain, data, len);
5621 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5628 r = mono_string_to_utf8_ignore (s);
5630 r = mono_string_to_utf8_checked (s, error);
5631 if (!mono_error_ok (error))
5638 len = strlen (r) + 1;
5640 mp_s = mono_mempool_alloc (mp, len);
5642 mp_s = mono_image_alloc (image, len);
5644 memcpy (mp_s, r, len);
5652 * mono_string_to_utf8_image:
5653 * @s: a System.String
5655 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5658 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5660 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5664 * mono_string_to_utf8_mp:
5665 * @s: a System.String
5667 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5670 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5672 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5676 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5679 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5681 eh_callbacks = *cbs;
5684 MonoRuntimeExceptionHandlingCallbacks *
5685 mono_get_eh_callbacks (void)
5687 return &eh_callbacks;
5691 * mono_raise_exception:
5692 * @ex: exception object
5694 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5697 mono_raise_exception (MonoException *ex)
5700 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5701 * that will cause gcc to omit the function epilog, causing problems when
5702 * the JIT tries to walk the stack, since the return address on the stack
5703 * will point into the next function in the executable, not this one.
5705 eh_callbacks.mono_raise_exception (ex);
5709 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5711 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5715 * mono_wait_handle_new:
5716 * @domain: Domain where the object will be created
5717 * @handle: Handle for the wait handle
5719 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5722 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5724 MonoWaitHandle *res;
5725 gpointer params [1];
5726 static MonoMethod *handle_set;
5728 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5730 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5732 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5734 params [0] = &handle;
5735 mono_runtime_invoke (handle_set, res, params, NULL);
5741 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5743 static MonoClassField *f_os_handle;
5744 static MonoClassField *f_safe_handle;
5746 if (!f_os_handle && !f_safe_handle) {
5747 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5748 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5753 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5757 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5764 mono_runtime_capture_context (MonoDomain *domain)
5766 RuntimeInvokeFunction runtime_invoke;
5768 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5769 MonoMethod *method = mono_get_context_capture_method ();
5770 MonoMethod *wrapper;
5773 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5774 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5775 domain->capture_context_method = mono_compile_method (method);
5778 runtime_invoke = domain->capture_context_runtime_invoke;
5780 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5783 * mono_async_result_new:
5784 * @domain:domain where the object will be created.
5785 * @handle: wait handle.
5786 * @state: state to pass to AsyncResult
5787 * @data: C closure data.
5789 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5790 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5794 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5796 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5797 MonoObject *context = mono_runtime_capture_context (domain);
5798 /* we must capture the execution context from the original thread */
5800 MONO_OBJECT_SETREF (res, execution_context, context);
5801 /* note: result may be null if the flow is suppressed */
5805 MONO_OBJECT_SETREF (res, object_data, object_data);
5806 MONO_OBJECT_SETREF (res, async_state, state);
5808 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5810 res->sync_completed = FALSE;
5811 res->completed = FALSE;
5817 mono_message_init (MonoDomain *domain,
5818 MonoMethodMessage *this,
5819 MonoReflectionMethod *method,
5820 MonoArray *out_args)
5822 static MonoClass *object_array_klass;
5823 static MonoClass *byte_array_klass;
5824 static MonoClass *string_array_klass;
5825 MonoMethodSignature *sig = mono_method_signature (method->method);
5831 if (!object_array_klass) {
5834 klass = mono_array_class_get (mono_defaults.object_class, 1);
5837 mono_memory_barrier ();
5838 object_array_klass = klass;
5840 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5843 mono_memory_barrier ();
5844 byte_array_klass = klass;
5846 klass = mono_array_class_get (mono_defaults.string_class, 1);
5849 mono_memory_barrier ();
5850 string_array_klass = klass;
5853 MONO_OBJECT_SETREF (this, method, method);
5855 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5856 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5857 this->async_result = NULL;
5858 this->call_type = CallType_Sync;
5860 names = g_new (char *, sig->param_count);
5861 mono_method_get_param_names (method->method, (const char **) names);
5862 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5864 for (i = 0; i < sig->param_count; i++) {
5865 name = mono_string_new (domain, names [i]);
5866 mono_array_setref (this->names, i, name);
5870 for (i = 0, j = 0; i < sig->param_count; i++) {
5871 if (sig->params [i]->byref) {
5873 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5874 mono_array_setref (this->args, i, arg);
5878 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5882 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5885 mono_array_set (this->arg_types, guint8, i, arg_type);
5890 * mono_remoting_invoke:
5891 * @real_proxy: pointer to a RealProxy object
5892 * @msg: The MonoMethodMessage to execute
5893 * @exc: used to store exceptions
5894 * @out_args: used to store output arguments
5896 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5897 * IMessage interface and it is not trivial to extract results from there. So
5898 * we call an helper method PrivateInvoke instead of calling
5899 * RealProxy::Invoke() directly.
5901 * Returns: the result object.
5904 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5905 MonoObject **exc, MonoArray **out_args)
5907 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5910 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5913 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5915 real_proxy->vtable->domain->private_invoke_method = im;
5918 pa [0] = real_proxy;
5923 return mono_runtime_invoke (im, NULL, pa, exc);
5927 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5928 MonoObject **exc, MonoArray **out_args)
5930 static MonoClass *object_array_klass;
5933 MonoMethodSignature *sig;
5935 int i, j, outarg_count = 0;
5937 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5939 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5940 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5941 target = tp->rp->unwrapped_server;
5943 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5947 domain = mono_domain_get ();
5948 method = msg->method->method;
5949 sig = mono_method_signature (method);
5951 for (i = 0; i < sig->param_count; i++) {
5952 if (sig->params [i]->byref)
5956 if (!object_array_klass) {
5959 klass = mono_array_class_get (mono_defaults.object_class, 1);
5962 mono_memory_barrier ();
5963 object_array_klass = klass;
5966 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5967 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5970 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5972 for (i = 0, j = 0; i < sig->param_count; i++) {
5973 if (sig->params [i]->byref) {
5975 arg = mono_array_get (msg->args, gpointer, i);
5976 mono_array_setref (*out_args, j, arg);
5985 * mono_object_to_string:
5987 * @exc: Any exception thrown by ToString (). May be NULL.
5989 * Returns: the result of calling ToString () on an object.
5992 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5994 static MonoMethod *to_string = NULL;
6000 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6002 method = mono_object_get_virtual_method (obj, to_string);
6004 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6008 * mono_print_unhandled_exception:
6009 * @exc: The exception
6011 * Prints the unhandled exception.
6014 mono_print_unhandled_exception (MonoObject *exc)
6017 char *message = (char*)"";
6018 gboolean free_message = FALSE;
6021 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6022 message = g_strdup ("OutOfMemoryException");
6024 str = mono_object_to_string (exc, NULL);
6026 message = mono_string_to_utf8_checked (str, &error);
6027 if (!mono_error_ok (&error)) {
6028 mono_error_cleanup (&error);
6029 message = (char *) "";
6031 free_message = TRUE;
6037 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6038 * exc->vtable->klass->name, message);
6040 g_printerr ("\nUnhandled Exception: %s\n", message);
6047 * mono_delegate_ctor:
6048 * @this: pointer to an uninitialized delegate object
6049 * @target: target object
6050 * @addr: pointer to native code
6053 * Initialize a delegate and sets a specific method, not the one
6054 * associated with addr. This is useful when sharing generic code.
6055 * In that case addr will most probably not be associated with the
6056 * correct instantiation of the method.
6059 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6061 MonoDelegate *delegate = (MonoDelegate *)this;
6068 delegate->method = method;
6070 class = this->vtable->klass;
6071 mono_stats.delegate_creations++;
6073 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6075 method = mono_marshal_get_remoting_invoke (method);
6076 delegate->method_ptr = mono_compile_method (method);
6077 MONO_OBJECT_SETREF (delegate, target, target);
6078 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6079 method = mono_marshal_get_unbox_wrapper (method);
6080 delegate->method_ptr = mono_compile_method (method);
6081 MONO_OBJECT_SETREF (delegate, target, target);
6083 delegate->method_ptr = addr;
6084 MONO_OBJECT_SETREF (delegate, target, target);
6087 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6091 * mono_delegate_ctor:
6092 * @this: pointer to an uninitialized delegate object
6093 * @target: target object
6094 * @addr: pointer to native code
6096 * This is used to initialize a delegate.
6099 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6101 MonoDomain *domain = mono_domain_get ();
6103 MonoMethod *method = NULL;
6107 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6109 if (!ji && domain != mono_get_root_domain ())
6110 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6112 method = ji->method;
6113 g_assert (!method->klass->generic_container);
6116 mono_delegate_ctor_with_method (this, target, addr, method);
6120 * mono_method_call_message_new:
6121 * @method: method to encapsulate
6122 * @params: parameters to the method
6123 * @invoke: optional, delegate invoke.
6124 * @cb: async callback delegate.
6125 * @state: state passed to the async callback.
6127 * Translates arguments pointers into a MonoMethodMessage.
6130 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6131 MonoDelegate **cb, MonoObject **state)
6133 MonoDomain *domain = mono_domain_get ();
6134 MonoMethodSignature *sig = mono_method_signature (method);
6135 MonoMethodMessage *msg;
6138 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6141 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6142 count = sig->param_count - 2;
6144 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6145 count = sig->param_count;
6148 for (i = 0; i < count; i++) {
6153 if (sig->params [i]->byref)
6154 vpos = *((gpointer *)params [i]);
6158 type = sig->params [i]->type;
6159 class = mono_class_from_mono_type (sig->params [i]);
6161 if (class->valuetype)
6162 arg = mono_value_box (domain, class, vpos);
6164 arg = *((MonoObject **)vpos);
6166 mono_array_setref (msg->args, i, arg);
6169 if (cb != NULL && state != NULL) {
6170 *cb = *((MonoDelegate **)params [i]);
6172 *state = *((MonoObject **)params [i]);
6179 * mono_method_return_message_restore:
6181 * Restore results from message based processing back to arguments pointers
6184 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6186 MonoMethodSignature *sig = mono_method_signature (method);
6187 int i, j, type, size, out_len;
6189 if (out_args == NULL)
6191 out_len = mono_array_length (out_args);
6195 for (i = 0, j = 0; i < sig->param_count; i++) {
6196 MonoType *pt = sig->params [i];
6201 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6203 arg = mono_array_get (out_args, gpointer, j);
6206 g_assert (type != MONO_TYPE_VOID);
6208 if (MONO_TYPE_IS_REFERENCE (pt)) {
6209 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6212 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6213 size = mono_class_value_size (class, NULL);
6214 if (class->has_references)
6215 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6217 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6219 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6220 mono_gc_bzero (*((gpointer *)params [i]), size);
6230 * mono_load_remote_field:
6231 * @this: pointer to an object
6232 * @klass: klass of the object containing @field
6233 * @field: the field to load
6234 * @res: a storage to store the result
6236 * This method is called by the runtime on attempts to load fields of
6237 * transparent proxy objects. @this points to such TP, @klass is the class of
6238 * the object containing @field. @res is a storage location which can be
6239 * used to store the result.
6241 * Returns: an address pointing to the value of field.
6244 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6246 static MonoMethod *getter = NULL;
6247 MonoDomain *domain = mono_domain_get ();
6248 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6249 MonoClass *field_class;
6250 MonoMethodMessage *msg;
6251 MonoArray *out_args;
6255 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6256 g_assert (res != NULL);
6258 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6259 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6264 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6268 field_class = mono_class_from_mono_type (field->type);
6270 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6271 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6272 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6274 full_name = mono_type_get_full_name (klass);
6275 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6276 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6279 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6281 if (exc) mono_raise_exception ((MonoException *)exc);
6283 if (mono_array_length (out_args) == 0)
6286 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6288 if (field_class->valuetype) {
6289 return ((char *)*res) + sizeof (MonoObject);
6295 * mono_load_remote_field_new:
6300 * Missing documentation.
6303 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6305 static MonoMethod *getter = NULL;
6306 MonoDomain *domain = mono_domain_get ();
6307 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6308 MonoClass *field_class;
6309 MonoMethodMessage *msg;
6310 MonoArray *out_args;
6311 MonoObject *exc, *res;
6314 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6316 field_class = mono_class_from_mono_type (field->type);
6318 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6320 if (field_class->valuetype) {
6321 res = mono_object_new (domain, field_class);
6322 val = ((gchar *) res) + sizeof (MonoObject);
6326 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6331 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6335 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6336 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6338 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6340 full_name = mono_type_get_full_name (klass);
6341 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6342 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6345 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6347 if (exc) mono_raise_exception ((MonoException *)exc);
6349 if (mono_array_length (out_args) == 0)
6352 res = mono_array_get (out_args, MonoObject *, 0);
6358 * mono_store_remote_field:
6359 * @this: pointer to an object
6360 * @klass: klass of the object containing @field
6361 * @field: the field to load
6362 * @val: the value/object to store
6364 * This method is called by the runtime on attempts to store fields of
6365 * transparent proxy objects. @this points to such TP, @klass is the class of
6366 * the object containing @field. @val is the new value to store in @field.
6369 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6371 static MonoMethod *setter = NULL;
6372 MonoDomain *domain = mono_domain_get ();
6373 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6374 MonoClass *field_class;
6375 MonoMethodMessage *msg;
6376 MonoArray *out_args;
6381 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6383 field_class = mono_class_from_mono_type (field->type);
6385 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6386 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6387 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6392 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6396 if (field_class->valuetype)
6397 arg = mono_value_box (domain, field_class, val);
6399 arg = *((MonoObject **)val);
6402 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6403 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6405 full_name = mono_type_get_full_name (klass);
6406 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6407 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6408 mono_array_setref (msg->args, 2, arg);
6411 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6413 if (exc) mono_raise_exception ((MonoException *)exc);
6417 * mono_store_remote_field_new:
6423 * Missing documentation
6426 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6428 static MonoMethod *setter = NULL;
6429 MonoDomain *domain = mono_domain_get ();
6430 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6431 MonoClass *field_class;
6432 MonoMethodMessage *msg;
6433 MonoArray *out_args;
6437 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6439 field_class = mono_class_from_mono_type (field->type);
6441 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6442 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6443 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6448 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6452 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6453 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6455 full_name = mono_type_get_full_name (klass);
6456 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6457 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6458 mono_array_setref (msg->args, 2, arg);
6461 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6463 if (exc) mono_raise_exception ((MonoException *)exc);
6467 * mono_create_ftnptr:
6469 * Given a function address, create a function descriptor for it.
6470 * This is only needed on some platforms.
6473 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6475 return callbacks.create_ftnptr (domain, addr);
6479 * mono_get_addr_from_ftnptr:
6481 * Given a pointer to a function descriptor, return the function address.
6482 * This is only needed on some platforms.
6485 mono_get_addr_from_ftnptr (gpointer descr)
6487 return callbacks.get_addr_from_ftnptr (descr);
6491 * mono_string_chars:
6494 * Returns a pointer to the UCS16 characters stored in the MonoString
6497 mono_string_chars (MonoString *s)
6503 * mono_string_length:
6506 * Returns the lenght in characters of the string
6509 mono_string_length (MonoString *s)
6515 * mono_array_length:
6516 * @array: a MonoArray*
6518 * Returns the total number of elements in the array. This works for
6519 * both vectors and multidimensional arrays.
6522 mono_array_length (MonoArray *array)
6524 return array->max_length;
6528 * mono_array_addr_with_size:
6529 * @array: a MonoArray*
6530 * @size: size of the array elements
6531 * @idx: index into the array
6533 * Returns the address of the @idx element in the array.
6536 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6538 return ((char*)(array)->vector) + size * idx;